From 5439fb8b13029a29b7e1e3a4ba1150595b85db97 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Mon, 29 Jun 2020 00:35:51 +0200 Subject: [PATCH] added basic valorant icon support + json type chooser --- FModel/App.xaml.cs | 2 - FModel/Creator/BaseIcon.cs | 2 +- FModel/Creator/BaseUIData.cs | 90 ++++++++++++++++++ FModel/Creator/BaseUserOption.cs | 7 +- FModel/Creator/Bundles/Header.cs | 4 +- .../{Creator.cs => FortniteCreator.cs} | 4 +- FModel/Creator/Icons/LargeSmallImage.cs | 2 +- FModel/Creator/Texts/Text.cs | 4 +- FModel/Creator/Texts/Typefaces.cs | 28 ++++-- FModel/Creator/ValorantCreator.cs | 36 +++++++ FModel/Discord/DiscordIntegration.cs | 2 +- FModel/Enums.cs | 6 ++ FModel/MainWindow.xaml.cs | 1 + FModel/PakReader/Pak/PakFileReader.cs | 2 +- FModel/PakReader/Pak/PakPackage.cs | 93 +++++++++++++++++-- FModel/PakReader/Parsers/Class/IUExport.cs | 6 +- FModel/PakReader/Parsers/Class/UObject.cs | 61 +++++++++--- .../Objects/ERichCurveExtrapolation.cs | 18 ++++ .../Objects/FMovieSceneFloatChannel.cs | 16 ++++ .../Parsers/Objects/FPackageIndex.cs | 15 +++ FModel/PakReader/Parsers/Objects/FPakEntry.cs | 14 +-- .../Parsers/Objects/UScriptStruct.cs | 1 + FModel/PakReader/Parsers/PackageReader.cs | 66 +++++++------ .../Parsers/PropertyTagData/ArrayProperty.cs | 44 ++++++++- .../Parsers/PropertyTagData/BaseProperty.cs | 36 ++++++- .../Parsers/PropertyTagData/BoolProperty.cs | 2 + .../Parsers/PropertyTagData/ByteProperty.cs | 2 + .../Parsers/PropertyTagData/DoubleProperty.cs | 2 + .../Parsers/PropertyTagData/EnumProperty.cs | 2 + .../Parsers/PropertyTagData/FloatProperty.cs | 2 + .../Parsers/PropertyTagData/Int16Property.cs | 2 + .../Parsers/PropertyTagData/Int64Property.cs | 2 + .../Parsers/PropertyTagData/Int8Property.cs | 2 + .../Parsers/PropertyTagData/IntProperty.cs | 2 + .../PropertyTagData/InterfaceProperty.cs | 2 + .../Parsers/PropertyTagData/MapProperty.cs | 44 ++++++++- .../Parsers/PropertyTagData/NameProperty.cs | 2 + .../Parsers/PropertyTagData/ObjectProperty.cs | 3 + .../Parsers/PropertyTagData/SetProperty.cs | 44 ++++++++- .../PropertyTagData/SoftObjectProperty.cs | 2 + .../Parsers/PropertyTagData/StrProperty.cs | 2 + .../Parsers/PropertyTagData/StructProperty.cs | 59 +++++++++++- .../Parsers/PropertyTagData/TextProperty.cs | 2 + .../Parsers/PropertyTagData/UInt16Property.cs | 2 + .../Parsers/PropertyTagData/UInt32Property.cs | 2 + .../Parsers/PropertyTagData/UInt64Property.cs | 2 + FModel/Properties/Resources.Designer.cs | 20 +++- FModel/Properties/Resources.ar.resx | 2 +- FModel/Properties/Resources.de-DE.resx | 2 +- FModel/Properties/Resources.es.resx | 2 +- FModel/Properties/Resources.fr-FR.resx | 8 +- FModel/Properties/Resources.it-IT.resx | 2 +- FModel/Properties/Resources.ja-JP.resx | 2 +- FModel/Properties/Resources.resx | 8 +- FModel/Properties/Settings.Designer.cs | 12 +++ FModel/Properties/Settings.settings | 3 + FModel/Utils/Assets.cs | 13 ++- FModel/Utils/EGL2.cs | 8 +- FModel/Utils/Paks.cs | 5 +- .../ViewModels/ComboBox/ComboBoxViewModel.cs | 6 ++ .../MenuItem/PakMenuItemViewModel.cs | 2 +- FModel/Windows/Search/Search.xaml.cs | 1 + FModel/Windows/Settings/General.xaml | 22 ++--- FModel/Windows/Settings/General.xaml.cs | 8 +- 64 files changed, 735 insertions(+), 135 deletions(-) create mode 100644 FModel/Creator/BaseUIData.cs rename FModel/Creator/{Creator.cs => FortniteCreator.cs} (98%) create mode 100644 FModel/Creator/ValorantCreator.cs create mode 100644 FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index 7ae72599..fee74aca 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -39,8 +39,6 @@ namespace FModel DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Culture]", Thread.CurrentThread.CurrentUICulture); StatusBarVm.statusBarViewModel.Set(FModel.Properties.Resources.Initializing, FModel.Properties.Resources.Loading); - if (FModel.Properties.Settings.Default.UseDiscordRpc) - DiscordIntegration.StartClient(); base.OnStartup(e); } diff --git a/FModel/Creator/BaseIcon.cs b/FModel/Creator/BaseIcon.cs index ba958a98..bb36ac9b 100644 --- a/FModel/Creator/BaseIcon.cs +++ b/FModel/Creator/BaseIcon.cs @@ -1,4 +1,4 @@ -using FModel.Creator.Icons; +using FModel.Creator.Icons; using FModel.Creator.Rarities; using FModel.Creator.Stats; using FModel.Creator.Texts; diff --git a/FModel/Creator/BaseUIData.cs b/FModel/Creator/BaseUIData.cs new file mode 100644 index 00000000..8c8459d1 --- /dev/null +++ b/FModel/Creator/BaseUIData.cs @@ -0,0 +1,90 @@ +using FModel.Creator.Texts; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; + +namespace FModel.Creator +{ + public class BaseUIData + { + private readonly SKPaint descriptionPaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.DescriptionTypeface, + TextSize = 13, + Color = SKColors.White, + }; + + public SKBitmap IconImage; + public string DisplayName; + public string Description; + public int Width = 512; // keep it 512 (or a multiple of 512) if you don't want blurry icons + public int Height = 64; + public int Margin = 2; + + public BaseUIData() + { + IconImage = null; + DisplayName = ""; + Description = ""; + } + + public BaseUIData(IUExport export) : this() + { + if (export.GetExport("DisplayName") is TextProperty displayName) + DisplayName = Text.GetTextPropertyBase(displayName); + if (export.GetExport("Description") is TextProperty description) + { + Description = Text.GetTextPropertyBase(description); + if (!string.IsNullOrEmpty(Description)) + { + Height += (int)descriptionPaint.TextSize * Helper.SplitLines(Description, descriptionPaint, Width - Margin).Length; + Height += (int)descriptionPaint.TextSize; + } + } + + if (export.GetExport("FullRender", "VerticalPromoImage", "LargeIcon", "DisplayIcon") is ObjectProperty icon) + { + SKBitmap raw = Utils.GetObjectTexture(icon); + if (raw != null) + { + int coef = Width / raw.Width; + int sizeX = raw.Width * coef; + int sizeY = raw.Height * coef; + Height += sizeY; + IconImage = raw.Resize(sizeX, sizeY); + } + } + } + + public void Draw(SKCanvas c) + { + int textSize = 45; + SKPaint namePaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.DisplayNameTypeface, + TextSize = textSize, + Color = SKColors.White, + TextAlign = SKTextAlign.Left, + }; + + // resize if too long + while (namePaint.MeasureText(DisplayName) > Width) + { + namePaint.TextSize = textSize -= 2; + } + + c.DrawText(DisplayName, Margin, Margin + textSize, namePaint); + + // wrap if too long + Helper.DrawMultilineText(c, Description, Width, Margin, ETextSide.Left, + new SKRect(Margin, textSize + 25, Width - Margin, Height - 25), descriptionPaint, out var yPos); + + c.DrawBitmap(IconImage, new SKRect(0, yPos, Width, Height), + new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true }); + } + } +} diff --git a/FModel/Creator/BaseUserOption.cs b/FModel/Creator/BaseUserOption.cs index 80eab7bc..d5794c9b 100644 --- a/FModel/Creator/BaseUserOption.cs +++ b/FModel/Creator/BaseUserOption.cs @@ -38,8 +38,11 @@ namespace FModel.Creator if (export.GetExport("OptionDescription") is TextProperty optionDescription) { OptionDescription = Text.GetTextPropertyBase(optionDescription); - Height += (int)descriptionPaint.TextSize * Helper.SplitLines(OptionDescription, descriptionPaint, Width - Margin).Length; - Height += (int)descriptionPaint.TextSize; + if (!string.IsNullOrEmpty(OptionDescription)) + { + Height += (int)descriptionPaint.TextSize * Helper.SplitLines(OptionDescription, descriptionPaint, Width - Margin).Length; + Height += (int)descriptionPaint.TextSize; + } } if (export.GetExport("OptionValues") is ArrayProperty optionValues) diff --git a/FModel/Creator/Bundles/Header.cs b/FModel/Creator/Bundles/Header.cs index 66efc995..658e1804 100644 --- a/FModel/Creator/Bundles/Header.cs +++ b/FModel/Creator/Bundles/Header.cs @@ -85,9 +85,9 @@ namespace FModel.Creator.Bundles { if (displayStyle.Value is UObject o) { - if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue(out var c1, "PrimaryColor", "Context_LimitedTimeColor") && c1 is StructProperty s1 && s1.Value is FLinearColor primaryColor) + if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue(out var c1, "PrimaryColor") && c1 is StructProperty s1 && s1.Value is FLinearColor primaryColor) PrimaryColor = SKColor.Parse(primaryColor.Hex); - if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue(out var c2, "SecondaryColor", "Context_BaseColor") && c2 is StructProperty s2 && s2.Value is FLinearColor secondaryColor) + if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue(out var c2, "SecondaryColor") && c2 is StructProperty s2 && s2.Value is FLinearColor secondaryColor) SecondaryColor = SKColor.Parse(secondaryColor.Hex); if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue("AccentColor", out var c3) && c3 is StructProperty s3 && s3.Value is FLinearColor accentColor) { diff --git a/FModel/Creator/Creator.cs b/FModel/Creator/FortniteCreator.cs similarity index 98% rename from FModel/Creator/Creator.cs rename to FModel/Creator/FortniteCreator.cs index bc80e516..fb222904 100644 --- a/FModel/Creator/Creator.cs +++ b/FModel/Creator/FortniteCreator.cs @@ -10,14 +10,14 @@ using System.IO; namespace FModel.Creator { - static class Creator + static class FortniteCreator { /// /// we draw based on the fist export type of the asset, no need to check others it's a waste of time /// i don't cache images because i don't wanna store a lot of SKCanvas in the memory /// /// true if an icon has been drawn - public static bool TryDrawIcon(string assetPath, string exportType, IUExport export) + public static bool TryDrawFortniteIcon(string assetPath, string exportType, IUExport export) { var d = new DirectoryInfo(assetPath); string assetName = d.Name; diff --git a/FModel/Creator/Icons/LargeSmallImage.cs b/FModel/Creator/Icons/LargeSmallImage.cs index 4ed5a399..dcac5c7a 100644 --- a/FModel/Creator/Icons/LargeSmallImage.cs +++ b/FModel/Creator/Icons/LargeSmallImage.cs @@ -1,4 +1,4 @@ -using PakReader.Pak; +using PakReader.Pak; using PakReader.Parsers.Class; using PakReader.Parsers.PropertyTagData; using SkiaSharp; diff --git a/FModel/Creator/Texts/Text.cs b/FModel/Creator/Texts/Text.cs index b2cb71b4..64a92840 100644 --- a/FModel/Creator/Texts/Text.cs +++ b/FModel/Creator/Texts/Text.cs @@ -17,7 +17,9 @@ namespace FModel.Creator.Texts public static string GetTextPropertyBase(TextProperty t) { if (t.Value is FText text) - if (text.Text is FTextHistory.Base b) + if (text.Text is FTextHistory.None n) + return n.CultureInvariantString; + else if (text.Text is FTextHistory.Base b) return b.SourceString.Replace("", string.Empty).Replace("", string.Empty); else if (text.Text is FTextHistory.StringTableEntry s) { diff --git a/FModel/Creator/Texts/Typefaces.cs b/FModel/Creator/Texts/Typefaces.cs index 6c5376ed..fcd04a65 100644 --- a/FModel/Creator/Texts/Typefaces.cs +++ b/FModel/Creator/Texts/Typefaces.cs @@ -9,7 +9,7 @@ namespace FModel.Creator.Texts public class Typefaces { #pragma warning disable IDE0051 - private const string _BASE_PATH = "/Game/UI/Foundation/Fonts/"; + private const string _FORTNITE_BASE_PATH = "/Game/UI/Foundation/Fonts/"; private const string _ASIA_ERINM = "AsiaERINM"; // korean fortnite private const string _BURBANK_BIG_CONDENSED_BLACK = "BurbankBigCondensed-Black"; // russian private readonly Uri _BURBANK_BIG_CONDENSED_BOLD = new Uri("pack://application:,,,/Resources/BurbankBigCondensed-Bold.ttf"); // other languages fortnite unofficial @@ -36,6 +36,10 @@ namespace FModel.Creator.Texts private const string _NOTO_SANS_TC_REGULAR = "NotoSansTC-Regular"; private const string _BURBANK_SMALL_BLACK = "burbanksmall-black"; private const string _BURBANK_SMALL_BOLD = "burbanksmall-bold"; + + private const string _VALORANT_BASE_PATH = "/Game/UI/Fonts/FinalFonts/"; + private const string _DINNEXT_W1G_BOLD = "DINNextW1G-Bold"; + private const string _DINNEXT_W1G_REGULAR = "DINNextW1G-Regular"; #pragma warning restore IDE0051 public SKTypeface DefaultTypeface; // used as default font for all untranslated strings (item source, ...) @@ -50,12 +54,12 @@ namespace FModel.Creator.Texts { DefaultTypeface = SKTypeface.FromStream(Application.GetResourceStream(_BURBANK_BIG_CONDENSED_BOLD).Stream); - ArraySegment[] t = Utils.GetPropertyArraySegmentByte(_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK); + ArraySegment[] t = Utils.GetPropertyArraySegmentByte(_FORTNITE_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK); if (t != null && t.Length == 3) BundleDefaultTypeface = SKTypeface.FromStream(t[2].AsStream()); else BundleDefaultTypeface = DefaultTypeface; - string namePath = _BASE_PATH + ( + string namePath = _FORTNITE_BASE_PATH + ( Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _ASIA_ERINM : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Russian ? _BURBANK_BIG_CONDENSED_BLACK : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? _NIS_JYAU : @@ -63,7 +67,7 @@ namespace FModel.Creator.Texts Properties.Settings.Default.AssetsLanguage == (long)ELanguage.TraditionalChinese ? _NOTO_SANS_TC_BLACK : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? _NOTO_SANS_SC_BLACK : string.Empty); - if (!namePath.Equals(_BASE_PATH)) + if (!namePath.Equals(_FORTNITE_BASE_PATH)) { t = Utils.GetPropertyArraySegmentByte(namePath); if (t != null && t.Length == 3) @@ -71,7 +75,7 @@ namespace FModel.Creator.Texts } else DisplayNameTypeface = DefaultTypeface; - string descriptionPath = _BASE_PATH + ( + string descriptionPath = _FORTNITE_BASE_PATH + ( Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _NOTO_SANS_KR_REGULAR : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? _NOTO_SANS_JP_BOLD : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Arabic ? _NOTO_SANS_ARABIC_REGULAR : @@ -83,7 +87,7 @@ namespace FModel.Creator.Texts DescriptionTypeface = SKTypeface.FromStream(t[2].AsStream()); else DescriptionTypeface = DefaultTypeface; - string bundleNamePath = _BASE_PATH + ( + string bundleNamePath = _FORTNITE_BASE_PATH + ( Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _ASIA_ERINM : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Russian ? _BURBANK_BIG_CONDENSED_BLACK : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? _NIS_JYAU : @@ -91,7 +95,7 @@ namespace FModel.Creator.Texts Properties.Settings.Default.AssetsLanguage == (long)ELanguage.TraditionalChinese ? _NOTO_SANS_TC_BLACK : Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? _NOTO_SANS_SC_BLACK : string.Empty); - if (!bundleNamePath.Equals(_BASE_PATH)) + if (!bundleNamePath.Equals(_FORTNITE_BASE_PATH)) { t = Utils.GetPropertyArraySegmentByte(bundleNamePath); if (t != null && t.Length == 3) @@ -99,6 +103,16 @@ namespace FModel.Creator.Texts } else BundleDisplayNameTypeface = BundleDefaultTypeface; } + else if (Globals.Game.ActualGame == EGame.Valorant) + { + ArraySegment[] t = Utils.GetPropertyArraySegmentByte(_VALORANT_BASE_PATH + _DINNEXT_W1G_BOLD); + if (t != null && t.Length == 3) + DisplayNameTypeface = SKTypeface.FromStream(t[2].AsStream()); + + t = Utils.GetPropertyArraySegmentByte(_VALORANT_BASE_PATH + _DINNEXT_W1G_REGULAR); + if (t != null && t.Length == 3) + DescriptionTypeface = SKTypeface.FromStream(t[2].AsStream()); + } } public bool NeedReload(bool forceReload) => forceReload ? diff --git a/FModel/Creator/ValorantCreator.cs b/FModel/Creator/ValorantCreator.cs new file mode 100644 index 00000000..d6bbf4c4 --- /dev/null +++ b/FModel/Creator/ValorantCreator.cs @@ -0,0 +1,36 @@ +using FModel.Creator.Icons; +using FModel.Creator.Texts; +using FModel.ViewModels.ImageBox; +using PakReader.Parsers.Class; +using SkiaSharp; +using System.IO; + +namespace FModel.Creator +{ + static class ValorantCreator + { + public static bool TryDrawValorantIcon(string assetPath, IUExport export) + { + var d = new DirectoryInfo(assetPath); + string assetName = d.Name; + if (Text.TypeFaces.NeedReload(false)) + Text.TypeFaces = new Typefaces(); // when opening bundle creator settings without loading paks first + + BaseUIData icon = new BaseUIData(export); + if (icon.IconImage != null) + { + using (var ret = new SKBitmap(icon.Width, icon.Height, SKColorType.Rgba8888, SKAlphaType.Premul)) + using (var c = new SKCanvas(ret)) + { + icon.Draw(c); + + Watermark.DrawWatermark(c); // watermark should only be applied on icons with width = 512 + ImageBoxVm.imageBoxViewModel.Set(ret, assetName); + } + return true; + } + + return false; + } + } +} diff --git a/FModel/Discord/DiscordIntegration.cs b/FModel/Discord/DiscordIntegration.cs index 14493233..55d0ef90 100644 --- a/FModel/Discord/DiscordIntegration.cs +++ b/FModel/Discord/DiscordIntegration.cs @@ -38,7 +38,7 @@ namespace FModel.Discord { Assets = _assets, Timestamps = _baseTimestamp, - State = Properties.Resources.Idling + State = string.Format(Properties.Resources.Idling, Globals.Game.GetName()) }); Initialize(); SaveCurrentPresence(); diff --git a/FModel/Enums.cs b/FModel/Enums.cs index afadfe54..1de81d57 100644 --- a/FModel/Enums.cs +++ b/FModel/Enums.cs @@ -55,6 +55,12 @@ TraditionalChinese } + public enum EJsonType: long + { + Default, + Positioned + } + public enum EIconDesign : long { Default, diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index fa648c23..246742b5 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -90,6 +90,7 @@ namespace FModel private async Task Init() { await PaksGrabber.PopulateMenu().ConfigureAwait(false); + if (Properties.Settings.Default.UseDiscordRpc) DiscordIntegration.StartClient(); await AesGrabber.Load(Properties.Settings.Default.ReloadAesKeys).ConfigureAwait(false); await CdnDataGrabber.DoCDNStuff().ConfigureAwait(false); } diff --git a/FModel/PakReader/Pak/PakFileReader.cs b/FModel/PakReader/Pak/PakFileReader.cs index 35eed42d..9606fada 100644 --- a/FModel/PakReader/Pak/PakFileReader.cs +++ b/FModel/PakReader/Pak/PakFileReader.cs @@ -430,7 +430,7 @@ namespace PakReader.Pak pakLocation += 4; } } - return new FPakEntry(this.FileName, name, Offset, Size, UncompressedSize, new byte[20], CompressionBlocks, CompressionBlockSize, CompressionMethodIndex, (byte)((Encrypted ? 0x01 : 0x00) | (Deleted ? 0x02 : 0x00))); + return new FPakEntry(this.FileName, name, Offset, Size, UncompressedSize, CompressionBlocks, CompressionBlockSize, CompressionMethodIndex, (byte)((Encrypted ? 0x01 : 0x00) | (Deleted ? 0x02 : 0x00))); } else { diff --git a/FModel/PakReader/Pak/PakPackage.cs b/FModel/PakReader/Pak/PakPackage.cs index 97281e48..10c41953 100644 --- a/FModel/PakReader/Pak/PakPackage.cs +++ b/FModel/PakReader/Pak/PakPackage.cs @@ -1,7 +1,11 @@ using System; +using System.Collections.Generic; using System.IO; +using Newtonsoft.Json; using PakReader.Parsers; using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using PakReader.Parsers.PropertyTagData; namespace PakReader.Pak { @@ -11,7 +15,31 @@ namespace PakReader.Pak readonly ArraySegment UExp; readonly ArraySegment UBulk; - public string[] ExportTypes + public string JsonData + { + get + { + if (string.IsNullOrEmpty(exports.JsonData)) + { + var ret = new JsonExport[Exports.Length]; + for (int i = 0; i < ret.Length; i++) + { + ret[i] = new JsonExport + { + ExportType = ExportTypes[i].String, + ExportValue = (FModel.EJsonType)FModel.Properties.Settings.Default.AssetsJsonType switch + { + FModel.EJsonType.Default => GetJsonDict(Exports[i]), + _ => Exports[i] + } + }; + } + return exports.JsonData = JsonConvert.SerializeObject(ret, Formatting.Indented); + } + return exports.JsonData; + } + } + public FName[] ExportTypes { get { @@ -26,8 +54,8 @@ namespace PakReader.Pak bulk.Position = 0; var p = new PackageReader(asset, exp, bulk); - exports.Exports = p.Exports; - return exports.ExportTypes = p.ExportTypes; + exports.Exports = p.DataExports; + return exports.ExportTypes = p.DataExportTypes; } return exports.ExportTypes; } @@ -47,8 +75,8 @@ namespace PakReader.Pak bulk.Position = 0; var p = new PackageReader(asset, exp, bulk); - exports.ExportTypes = p.ExportTypes; - return exports.Exports = p.Exports; + exports.ExportTypes = p.DataExportTypes; + return exports.Exports = p.DataExports; } return exports.Exports; } @@ -63,10 +91,48 @@ namespace PakReader.Pak exports = new ExportList(); } - public string GetFirstExportType() => ExportTypes[0]; - - public IUExport[] GetAllExports() => Exports; - public IUExport GetFirstExport() => Exports[0]; + private Dictionary GetJsonDict(IUExport export) + { + if (export != null) + { + var ret = new Dictionary(export.Count); + foreach (KeyValuePair KvP in export) + { + if (KvP.Value == null) + ret[KvP.Key] = null; + else + ret[KvP.Key] = KvP.Value.GetType().Name switch + { + "ByteProperty" => ((ByteProperty)KvP.Value).GetValue(), + "BoolProperty" => ((BoolProperty)KvP.Value).GetValue(), + "IntProperty" => ((IntProperty)KvP.Value).GetValue(), + "FloatProperty" => ((FloatProperty)KvP.Value).GetValue(), + "ObjectProperty" => ((ObjectProperty)KvP.Value).GetValue(), + "NameProperty" => ((NameProperty)KvP.Value).GetValue(), + "DoubleProperty" => ((DoubleProperty)KvP.Value).GetValue(), + "ArrayProperty" => ((ArrayProperty)KvP.Value).GetValue(), + "StructProperty" => ((StructProperty)KvP.Value).GetValue(), + "StrProperty" => ((StrProperty)KvP.Value).GetValue(), + "TextProperty" => ((TextProperty)KvP.Value).GetValue(), + "InterfaceProperty" => ((InterfaceProperty)KvP.Value).GetValue(), + "SoftObjectProperty" => ((SoftObjectProperty)KvP.Value).GetValue(), + "UInt64Property" => ((UInt64Property)KvP.Value).GetValue(), + "UInt32Property" => ((UInt32Property)KvP.Value).GetValue(), + "UInt16Property" => ((UInt16Property)KvP.Value).GetValue(), + "Int64Property" => ((Int64Property)KvP.Value).GetValue(), + "Int16Property" => ((Int16Property)KvP.Value).GetValue(), + "Int8Property" => ((Int8Property)KvP.Value).GetValue(), + "MapProperty" => ((MapProperty)KvP.Value).GetValue(), + "SetProperty" => ((SetProperty)KvP.Value).GetValue(), + "EnumProperty" => ((EnumProperty)KvP.Value).GetValue(), + "UObject" => ((UObject)KvP.Value).GetValue(), + _ => KvP.Value, + }; + } + return ret; + } + return null; + } public T GetExport() where T : IUExport { @@ -99,8 +165,15 @@ namespace PakReader.Pak // hacky way to get the package to be a readonly struct, essentially a double pointer i guess sealed class ExportList { + public string JsonData; + public FName[] ExportTypes; public IUExport[] Exports; - public string[] ExportTypes; + } + + sealed class JsonExport + { + public string ExportType; + public object ExportValue; } } } diff --git a/FModel/PakReader/Parsers/Class/IUExport.cs b/FModel/PakReader/Parsers/Class/IUExport.cs index f8683506..02d24bf8 100644 --- a/FModel/PakReader/Parsers/Class/IUExport.cs +++ b/FModel/PakReader/Parsers/Class/IUExport.cs @@ -7,7 +7,9 @@ namespace PakReader.Parsers.Class /// The derived class must have a "readonly Dictionary" of properties /// public interface IUExport : IReadOnlyDictionary - { } + { + + } public static class IUExportExtension { @@ -15,7 +17,7 @@ namespace PakReader.Parsers.Class { foreach (string name in names) { - if (export.TryGetValue(name, out var obj) && obj is T) + if (export != null && export.TryGetValue(name, out var obj) && obj is T) return (T)obj; } return default; diff --git a/FModel/PakReader/Parsers/Class/UObject.cs b/FModel/PakReader/Parsers/Class/UObject.cs index f6b45d15..fea1285a 100644 --- a/FModel/PakReader/Parsers/Class/UObject.cs +++ b/FModel/PakReader/Parsers/Class/UObject.cs @@ -9,11 +9,8 @@ namespace PakReader.Parsers.Class { public class UObject : IUExport, IUStruct { - public FObjectExport ExportInfo { get; internal set; } readonly Dictionary Dict; - readonly FGuid GUID; - // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp#L930 public UObject(PackageReader reader) : this(reader, reader.ExportMap.Sum(e => e.SerialSize), false) { } public UObject(PackageReader reader, bool structFallback) : this(reader, reader.ExportMap.Sum(e => e.SerialSize), structFallback) { } @@ -23,7 +20,7 @@ namespace PakReader.Parsers.Class // https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp#L2197 internal UObject(PackageReader reader, long maxSize, bool structFallback) { - var props = new Dictionary(); + var properties = new Dictionary(); int i = 1; while (true) @@ -33,27 +30,65 @@ namespace PakReader.Parsers.Class break; var pos = reader.Position; - if (props.ContainsKey(Tag.Name.String)) // FortniteGame/Content/Balance/RarityData.uasset i really need this - props[$"{Tag.Name.String}_NK{i++}"] = BaseProperty.ReadProperty(reader, Tag, Tag.Type, ReadType.NORMAL) ?? null; // NK = NewKey - else - props[Tag.Name.String] = BaseProperty.ReadProperty(reader, Tag, Tag.Type, ReadType.NORMAL) ?? null; - if (props[Tag.Name.String] is null) - break; + var obj = BaseProperty.ReadAsObject(reader, Tag, Tag.Type, ReadType.NORMAL) ?? null; + + var key = properties.ContainsKey(Tag.Name.String) ? $"{Tag.Name.String}_NK{i++}" : Tag.Name.String; + properties[key] = obj; + if (obj == null) break; if (Tag.Size + pos != reader.Position) { - System.Diagnostics.Debug.WriteLine($"Didn't read {Tag.Type.String} correctly (at {reader.Position}, should be {Tag.Size + pos}, {Tag.Size + pos - reader.Position} behind)"); +#if DEBUG + System.Diagnostics.Debug.WriteLine($"Didn't read {key} correctly (at {reader.Position}, should be {Tag.Size + pos}, {Tag.Size + pos - reader.Position} behind)"); +#endif reader.Position = Tag.Size + pos; } } - Dict = props; + Dict = properties; if (!structFallback && reader.ReadInt32() != 0 && reader.Position + 16 <= maxSize) { - GUID = new FGuid(reader); + new FGuid(reader); } } + public Dictionary GetValue() + { + var ret = new Dictionary(Dict.Count); + foreach (KeyValuePair KvP in Dict) + { + if (KvP.Value == null) + ret[KvP.Key] = null; + else + ret[KvP.Key] = KvP.Value.GetType().Name switch + { + "ByteProperty" => ((ByteProperty)KvP.Value).GetValue(), + "BoolProperty" => ((BoolProperty)KvP.Value).GetValue(), + "IntProperty" => ((IntProperty)KvP.Value).GetValue(), + "FloatProperty" => ((FloatProperty)KvP.Value).GetValue(), + "ObjectProperty" => ((ObjectProperty)KvP.Value).GetValue(), + "NameProperty" => ((NameProperty)KvP.Value).GetValue(), + "DoubleProperty" => ((DoubleProperty)KvP.Value).GetValue(), + "ArrayProperty" => ((ArrayProperty)KvP.Value).GetValue(), + "StructProperty" => ((StructProperty)KvP.Value).GetValue(), + "StrProperty" => ((StrProperty)KvP.Value).GetValue(), + "TextProperty" => ((TextProperty)KvP.Value).GetValue(), + "InterfaceProperty" => ((InterfaceProperty)KvP.Value).GetValue(), + "SoftObjectProperty" => ((SoftObjectProperty)KvP.Value).GetValue(), + "UInt64Property" => ((UInt64Property)KvP.Value).GetValue(), + "UInt32Property" => ((UInt32Property)KvP.Value).GetValue(), + "UInt16Property" => ((UInt16Property)KvP.Value).GetValue(), + "Int64Property" => ((Int64Property)KvP.Value).GetValue(), + "Int16Property" => ((Int16Property)KvP.Value).GetValue(), + "Int8Property" => ((Int8Property)KvP.Value).GetValue(), + "MapProperty" => ((MapProperty)KvP.Value).GetValue(), + "SetProperty" => ((SetProperty)KvP.Value).GetValue(), + "EnumProperty" => ((EnumProperty)KvP.Value).GetValue(), + _ => KvP.Value, + }; + } + return ret; + } public object this[string key] => Dict[key]; public IEnumerable Keys => Dict.Keys; public IEnumerable Values => Dict.Values; diff --git a/FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs b/FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs new file mode 100644 index 00000000..ba6f488b --- /dev/null +++ b/FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs @@ -0,0 +1,18 @@ +namespace PakReader.Parsers.Objects +{ + public enum ERichCurveExtrapolation + { + /** Repeat the curve without an offset. */ + RCCE_Cycle, + /** Repeat the curve with an offset relative to the first or last key's value. */ + RCCE_CycleWithOffset, + /** Sinusoidally extrapolate. */ + RCCE_Oscillate, + /** Use a linearly increasing value for extrapolation.*/ + RCCE_Linear, + /** Use a constant value for extrapolation */ + RCCE_Constant, + /** No Extrapolation */ + RCCE_None, + } +} diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs new file mode 100644 index 00000000..ad8c98ac --- /dev/null +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs @@ -0,0 +1,16 @@ +namespace PakReader.Parsers.Objects +{ + public readonly struct FMovieSceneFloatChannel : IUStruct + { + public readonly ERichCurveExtrapolation PreInfinityExtrap; + public readonly ERichCurveExtrapolation PostInfinityExtrap; + + internal FMovieSceneFloatChannel(PackageReader reader) + { + PreInfinityExtrap = (ERichCurveExtrapolation)reader.ReadByte(); + PostInfinityExtrap = (ERichCurveExtrapolation)reader.ReadByte(); + + //todo https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Runtime/MovieScene/Private/Channels/MovieSceneFloatChannel.cpp#L1092 + } + } +} diff --git a/FModel/PakReader/Parsers/Objects/FPackageIndex.cs b/FModel/PakReader/Parsers/Objects/FPackageIndex.cs index a094dc21..369df8e5 100644 --- a/FModel/PakReader/Parsers/Objects/FPackageIndex.cs +++ b/FModel/PakReader/Parsers/Objects/FPackageIndex.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System.Collections.Generic; namespace PakReader.Parsers.Objects { @@ -37,6 +38,20 @@ namespace PakReader.Parsers.Objects Reader = reader; } + public object GetValue() + { + if (Resource != null) + { + var ret = new Dictionary + { + ["ObjectName"] = Resource.ObjectName.String, + ["OuterIndex"] = Resource.OuterIndex.GetValue() + }; + return ret; + } + return null; + } + [JsonIgnore] public bool IsNull => Index == 0; [JsonIgnore] diff --git a/FModel/PakReader/Parsers/Objects/FPakEntry.cs b/FModel/PakReader/Parsers/Objects/FPakEntry.cs index c4086962..6d84a769 100644 --- a/FModel/PakReader/Parsers/Objects/FPakEntry.cs +++ b/FModel/PakReader/Parsers/Objects/FPakEntry.cs @@ -17,7 +17,6 @@ namespace PakReader.Parsers.Objects public readonly long Offset; public readonly long Size; public readonly long UncompressedSize; - public readonly byte[] Hash; // why isn't this an FShaHash? public readonly FPakCompressedBlock[] CompressionBlocks; public readonly uint CompressionBlockSize; public readonly uint CompressionMethodIndex; @@ -72,12 +71,8 @@ namespace PakReader.Parsers.Objects else CompressionMethodIndex = reader.ReadUInt32(); } - if (Version <= EPakVersion.INITIAL) - { - // Timestamp of type FDateTime, but the serializer only reads to the Ticks property (int64) - reader.ReadInt64(); - } - Hash = reader.ReadBytes(20); + if (Version <= EPakVersion.INITIAL) reader.ReadInt64(); // Timestamp + reader.ReadBytes(20); // Hash if (Version >= EPakVersion.COMPRESSION_ENCRYPTION) { if (CompressionMethodIndex != 0) @@ -108,7 +103,7 @@ namespace PakReader.Parsers.Objects Size = reader.ReadInt64(); UncompressedSize = reader.ReadInt64(); CompressionMethodIndex = reader.ReadUInt32(); - Hash = reader.ReadBytes(20); + reader.ReadBytes(20); // Hash if (CompressionMethodIndex != 0) { CompressionBlocks = reader.ReadTArray(() => new FPakCompressedBlock(reader)); @@ -120,14 +115,13 @@ namespace PakReader.Parsers.Objects StructSize = (int)(reader.BaseStream.Position - StartOffset); } - internal FPakEntry(string pakName, string name, long offset, long size, long uncompressedSize, byte[] hash, FPakCompressedBlock[] compressionBlocks, uint compressionBlockSize, uint compressionMethodIndex, byte flags) + internal FPakEntry(string pakName, string name, long offset, long size, long uncompressedSize, FPakCompressedBlock[] compressionBlocks, uint compressionBlockSize, uint compressionMethodIndex, byte flags) { PakFileName = pakName; Name = name; Offset = offset; Size = size; UncompressedSize = uncompressedSize; - Hash = hash; CompressionBlocks = compressionBlocks; CompressionBlockSize = compressionBlockSize; CompressionMethodIndex = compressionMethodIndex; diff --git a/FModel/PakReader/Parsers/Objects/UScriptStruct.cs b/FModel/PakReader/Parsers/Objects/UScriptStruct.cs index 5500722b..02fddb6d 100644 --- a/FModel/PakReader/Parsers/Objects/UScriptStruct.cs +++ b/FModel/PakReader/Parsers/Objects/UScriptStruct.cs @@ -46,6 +46,7 @@ namespace PakReader.Parsers.Objects "MovieSceneFrameRange" => new FMovieSceneFrameRange(reader), "MovieSceneEvaluationKey" => new FMovieSceneEvaluationKey(reader), "MovieSceneFloatValue" => new FRichCurveKey(reader), + "MovieSceneFloatChannel" => new FMovieSceneFloatChannel(reader), "MovieSceneEvaluationTemplate" => new FMovieSceneEvaluationTemplate(reader), "SkeletalMeshSamplingLODBuiltData" => new FSkeletalMeshSamplingLODBuiltData(reader), //"BodyInstance" => new FBodyInstance(reader), // if uncommented, can't parse .umap diff --git a/FModel/PakReader/Parsers/PackageReader.cs b/FModel/PakReader/Parsers/PackageReader.cs index f064a223..0307599e 100644 --- a/FModel/PakReader/Parsers/PackageReader.cs +++ b/FModel/PakReader/Parsers/PackageReader.cs @@ -15,8 +15,8 @@ namespace PakReader.Parsers public FObjectImport[] ImportMap { get; } public FObjectExport[] ExportMap { get; } - public IUExport[] Exports { get; } - public string[] ExportTypes { get; } + public IUExport[] DataExports { get; } + public FName[] DataExportTypes { get; } public PackageReader(string path) : this(path + ".uasset", path + ".uexp", path + ".ubulk") { } public PackageReader(string uasset, string uexp, string ubulk) : this(File.OpenRead(uasset), File.OpenRead(uexp), File.Exists(ubulk) ? File.OpenRead(ubulk) : null) { } @@ -30,45 +30,41 @@ namespace PakReader.Parsers NameMap = SerializeNameMap(); ImportMap = SerializeImportMap(); ExportMap = SerializeExportMap(); - Exports = new IUExport[ExportMap.Length]; - ExportTypes = new string[ExportMap.Length]; + DataExports = new IUExport[ExportMap.Length]; + DataExportTypes = new FName[ExportMap.Length]; Loader = uexp; for(int i = 0; i < ExportMap.Length; i++) { - var Export = ExportMap[i]; - // Serialize everything, not just specifically assets - // if (Export.bIsAsset) + FName ObjectClassName; + if (ExportMap[i].ClassIndex.IsNull) + ObjectClassName = DataExportTypes[i] = ReadFName(); // check if this is true, I don't know if Fortnite ever uses this + else if (ExportMap[i].ClassIndex.IsExport) + ObjectClassName = DataExportTypes[i] = ExportMap[ExportMap[i].ClassIndex.AsExport].ObjectName; + else if (ExportMap[i].ClassIndex.IsImport) + ObjectClassName = DataExportTypes[i] = ImportMap[ExportMap[i].ClassIndex.AsImport].ObjectName; + else + throw new FileLoadException("Can't get class name"); // Shouldn't reach this unless the laws of math have bent to MagmaReef's will + + if (ObjectClassName.String.Equals("BlueprintGeneratedClass")) continue; + + var pos = Position = ExportMap[i].SerialOffset - PackageFileSummary.TotalHeaderSize; + DataExports[i] = ObjectClassName.String switch { - // We need to get the class name from the import/export maps - FName ObjectClassName; - if (Export.ClassIndex.IsNull) - ObjectClassName = ReadFName(); // check if this is true, I don't know if Fortnite ever uses this - else if (Export.ClassIndex.IsExport) - ObjectClassName = ExportMap[Export.ClassIndex.AsExport].ObjectName; - else if (Export.ClassIndex.IsImport) - ObjectClassName = ImportMap[Export.ClassIndex.AsImport].ObjectName; - else - throw new FileLoadException("Can't get class name"); // Shouldn't reach this unless the laws of math have bent to MagmaReef's will - if (ObjectClassName.String.Equals("BlueprintGeneratedClass")) continue; + "Texture2D" => new UTexture2D(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), + "CurveTable" => new UCurveTable(this), + "DataTable" => new UDataTable(this), + "FontFace" => new UFontFace(this, ubulk), + "SoundWave" => new USoundWave(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), + "StringTable" => new UStringTable(this), + _ => new UObject(this), + }; - var pos = Position = Export.SerialOffset - PackageFileSummary.TotalHeaderSize; - ExportTypes[i] = ObjectClassName.String; - Exports[i] = ObjectClassName.String switch - { - "Texture2D" => new UTexture2D(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), - "CurveTable" => new UCurveTable(this), - "DataTable" => new UDataTable(this), - "FontFace" => new UFontFace(this, ubulk), - "SoundWave" => new USoundWave(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), - "StringTable" => new UStringTable(this), - _ => new UObject(this), - }; - - if (pos + Export.SerialSize != Position) - { - System.Diagnostics.Debug.WriteLine($"[ExportType={ObjectClassName.String}] Didn't read {Export.ObjectName} correctly (at {Position}, should be {pos + Export.SerialSize}, {pos + Export.SerialSize - Position} behind)"); - } +#if DEBUG + if (pos + ExportMap[i].SerialSize != Position) + { + System.Diagnostics.Debug.WriteLine($"[ExportType={ObjectClassName.String}] Didn't read {ExportMap[i].ObjectName} correctly (at {Position}, should be {pos + ExportMap[i].SerialSize}, {pos + ExportMap[i].SerialSize - Position} behind)"); } +#endif } return; } diff --git a/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs index 120868ed..e560f1ba 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs @@ -2,14 +2,14 @@ namespace PakReader.Parsers.PropertyTagData { - public sealed class ArrayProperty : BaseProperty + public sealed class ArrayProperty : BaseProperty { internal ArrayProperty(PackageReader reader, FPropertyTag tag) { Position = reader.Position; int length = reader.ReadInt32(); - Value = new BaseProperty[length]; + Value = new object[length]; FPropertyTag InnerTag = default; // Execute if UE4 version is at least VER_UE4_INNER_ARRAY_TAG_INFO @@ -20,8 +20,46 @@ namespace PakReader.Parsers.PropertyTagData } for (int i = 0; i < length; i++) { - Value[i] = ReadProperty(reader, InnerTag, tag.InnerType, ReadType.ARRAY); + Value[i] = BaseProperty.ReadAsObject(reader, InnerTag, tag.InnerType, ReadType.ARRAY); } } + + public object[] GetValue() + { + var ret = new object[Value.Length]; + for (int i = 0; i < ret.Length; i++) + { + if (Value[i] == null) + ret[i] = null; + else + ret[i] = ((BaseProperty)Value[i]).GetType().Name switch + { + "ByteProperty" => ((ByteProperty)Value[i]).GetValue(), + "BoolProperty" => ((BoolProperty)Value[i]).GetValue(), + "IntProperty" => ((IntProperty)Value[i]).GetValue(), + "FloatProperty" => ((FloatProperty)Value[i]).GetValue(), + "ObjectProperty" => ((ObjectProperty)Value[i]).GetValue(), + "NameProperty" => ((NameProperty)Value[i]).GetValue(), + "DoubleProperty" => ((DoubleProperty)Value[i]).GetValue(), + "ArrayProperty" => ((ArrayProperty)Value[i]).GetValue(), + "StructProperty" => ((StructProperty)Value[i]).GetValue(), + "StrProperty" => ((StrProperty)Value[i]).GetValue(), + "TextProperty" => ((TextProperty)Value[i]).GetValue(), + "InterfaceProperty" => ((InterfaceProperty)Value[i]).GetValue(), + "SoftObjectProperty" => ((SoftObjectProperty)Value[i]).GetValue(), + "UInt64Property" => ((UInt64Property)Value[i]).GetValue(), + "UInt32Property" => ((UInt32Property)Value[i]).GetValue(), + "UInt16Property" => ((UInt16Property)Value[i]).GetValue(), + "Int64Property" => ((Int64Property)Value[i]).GetValue(), + "Int16Property" => ((Int16Property)Value[i]).GetValue(), + "Int8Property" => ((Int8Property)Value[i]).GetValue(), + "MapProperty" => ((MapProperty)Value[i]).GetValue(), + "SetProperty" => ((SetProperty)Value[i]).GetValue(), + "EnumProperty" => ((EnumProperty)Value[i]).GetValue(), + _ => Value[i], + }; + } + return ret; + } } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs index e4d06a01..902880d6 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs @@ -4,7 +4,7 @@ namespace PakReader.Parsers.PropertyTagData { public class BaseProperty { - internal static BaseProperty ReadProperty(PackageReader reader, FPropertyTag tag, FName type, ReadType readType) + internal static BaseProperty ReadAsObject(PackageReader reader, FPropertyTag tag, FName type, ReadType readType) { BaseProperty prop = type.String switch { @@ -37,6 +37,40 @@ namespace PakReader.Parsers.PropertyTagData }; return prop; } + + internal static object ReadAsValue(PackageReader reader, FPropertyTag tag, FName type, ReadType readType) + { + var prop = type.String switch + { + "ByteProperty" => new ByteProperty(reader, tag, readType).Value, + "BoolProperty" => new BoolProperty(reader, tag, readType).Value, + "IntProperty" => new IntProperty(reader, tag).Value, + "FloatProperty" => new FloatProperty(reader, tag).Value, + "ObjectProperty" => new ObjectProperty(reader, tag).Value, + "NameProperty" => new NameProperty(reader, tag).Value, + "DelegateProperty" => new DelegateProperty(reader, tag), + "DoubleProperty" => new DoubleProperty(reader, tag).Value, + "ArrayProperty" => new ArrayProperty(reader, tag).Value, + "StructProperty" => new StructProperty(reader, tag).Value, + "StrProperty" => new StrProperty(reader, tag).Value, + "TextProperty" => new TextProperty(reader, tag).Value, + "InterfaceProperty" => new InterfaceProperty(reader, tag).Value, + "MulticastDelegateProperty" => new MulticastDelegateProperty(reader, tag).Value, + "LazyObjectProperty" => new LazyObjectProperty(reader, tag).Value, + "SoftObjectProperty" => new SoftObjectProperty(reader, tag, readType).Value, + "UInt64Property" => new UInt64Property(reader, tag).Value, + "UInt32Property" => new UInt32Property(reader, tag).Value, + "UInt16Property" => new UInt16Property(reader, tag).Value, + "Int64Property" => new Int64Property(reader, tag).Value, + "Int16Property" => new Int16Property(reader, tag).Value, + "Int8Property" => new Int8Property(reader, tag).Value, + "MapProperty" => new MapProperty(reader, tag).Value, + "SetProperty" => new SetProperty(reader, tag).Value, + "EnumProperty" => new EnumProperty(reader, tag).Value, + _ => null, //throw new NotImplementedException($"Parsing of {type.String} types aren't supported yet."), + }; + return prop; + } } public class BaseProperty : BaseProperty diff --git a/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs index 7d267af6..355856ec 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs @@ -22,5 +22,7 @@ namespace PakReader.Parsers.PropertyTagData throw new ArgumentOutOfRangeException(nameof(readType)); } } + + public bool GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs index 52332e48..5f782fe0 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs @@ -16,5 +16,7 @@ namespace PakReader.Parsers.PropertyTagData _ => throw new ArgumentOutOfRangeException(nameof(readType)), }; } + + public byte GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs index 2c733e41..4a26c0a9 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadDouble(); } + + public double GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs index 94f726a9..3db14697 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadFName(); } + + public string GetValue() => Value.String; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs index cf26fa7d..19fb546e 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadFloat(); } + + public float GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs b/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs index 7f6cfbcc..95acb139 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadInt16(); } + + public short GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs b/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs index 9722e174..5d849014 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadInt64(); } + + public long GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs b/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs index 8d80947b..47b4ca6d 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadByte(); } + + public byte GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs index 4bb5c195..a015604f 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadInt32(); } + + public int GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs index c8583318..99cf0316 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs @@ -10,5 +10,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadUInt32(); } + + public uint GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs index f44299ed..a0180857 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs @@ -4,7 +4,7 @@ using PakReader.Parsers.Objects; namespace PakReader.Parsers.PropertyTagData { - public sealed class MapProperty : BaseProperty> + public sealed class MapProperty : BaseProperty> { // https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyMap.cpp#L243 internal MapProperty(PackageReader reader, FPropertyTag tag) @@ -18,12 +18,50 @@ namespace PakReader.Parsers.PropertyTagData } var NumEntries = reader.ReadInt32(); - var dict = new Dictionary(NumEntries); + var dict = new Dictionary(NumEntries); for (int i = 0; i < NumEntries; i++) { - dict[ReadProperty(reader, tag, tag.InnerType, ReadType.MAP)] = ReadProperty(reader, tag, tag.ValueType, ReadType.MAP); + dict[ReadAsValue(reader, tag, tag.InnerType, ReadType.MAP)] = BaseProperty.ReadAsObject(reader, tag, tag.ValueType, ReadType.MAP); } Value = dict; } + + public Dictionary GetValue() + { + var ret = new Dictionary(Value.Count); + foreach (KeyValuePair KvP in Value) + { + if (KvP.Value == null) + ret[KvP.Key] = null; + else + ret[KvP.Key] = KvP.Value.GetType().Name switch + { + "ByteProperty" => ((ByteProperty)KvP.Value).GetValue(), + "BoolProperty" => ((BoolProperty)KvP.Value).GetValue(), + "IntProperty" => ((IntProperty)KvP.Value).GetValue(), + "FloatProperty" => ((FloatProperty)KvP.Value).GetValue(), + "ObjectProperty" => ((ObjectProperty)KvP.Value).GetValue(), + "NameProperty" => ((NameProperty)KvP.Value).GetValue(), + "DoubleProperty" => ((DoubleProperty)KvP.Value).GetValue(), + "ArrayProperty" => ((ArrayProperty)KvP.Value).GetValue(), + "StructProperty" => ((StructProperty)KvP.Value).GetValue(), + "StrProperty" => ((StrProperty)KvP.Value).GetValue(), + "TextProperty" => ((TextProperty)KvP.Value).GetValue(), + "InterfaceProperty" => ((InterfaceProperty)KvP.Value).GetValue(), + "SoftObjectProperty" => ((SoftObjectProperty)KvP.Value).GetValue(), + "UInt64Property" => ((UInt64Property)KvP.Value).GetValue(), + "UInt32Property" => ((UInt32Property)KvP.Value).GetValue(), + "UInt16Property" => ((UInt16Property)KvP.Value).GetValue(), + "Int64Property" => ((Int64Property)KvP.Value).GetValue(), + "Int16Property" => ((Int16Property)KvP.Value).GetValue(), + "Int8Property" => ((Int8Property)KvP.Value).GetValue(), + "MapProperty" => ((MapProperty)KvP.Value).GetValue(), + "SetProperty" => ((SetProperty)KvP.Value).GetValue(), + "EnumProperty" => ((EnumProperty)KvP.Value).GetValue(), + _ => KvP.Value, + }; + } + return ret; + } } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs index 87590d51..3860abbd 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadFName(); } + + public string GetValue() => Value.String; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs index 1b873bbc..38f450ea 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs @@ -1,4 +1,5 @@ using PakReader.Parsers.Objects; +using System.Collections.Generic; namespace PakReader.Parsers.PropertyTagData { @@ -9,5 +10,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = new FPackageIndex(reader); } + + public object GetValue() => Value.GetValue(); } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs index 11d664d0..c66fb5bd 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs @@ -3,7 +3,7 @@ using PakReader.Parsers.Objects; namespace PakReader.Parsers.PropertyTagData { - public sealed class SetProperty : BaseProperty + public sealed class SetProperty : BaseProperty { // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertySet.cpp#L216 internal SetProperty(PackageReader reader, FPropertyTag tag) @@ -17,11 +17,49 @@ namespace PakReader.Parsers.PropertyTagData } var NumEntries = reader.ReadInt32(); - Value = new BaseProperty[NumEntries]; + Value = new object[NumEntries]; for (int i = 0; i < NumEntries; i++) { - Value[i] = ReadProperty(reader, tag, tag.InnerType, ReadType.ARRAY); + Value[i] = BaseProperty.ReadAsObject(reader, tag, tag.InnerType, ReadType.ARRAY); } } + + public object[] GetValue() + { + var ret = new object[Value.Length]; + for (int i = 0; i < ret.Length; i++) + { + if (Value[i] == null) + ret[i] = null; + else + ret[i] = ((BaseProperty)Value[i]).GetType().Name switch + { + "ByteProperty" => ((ByteProperty)Value[i]).GetValue(), + "BoolProperty" => ((BoolProperty)Value[i]).GetValue(), + "IntProperty" => ((IntProperty)Value[i]).GetValue(), + "FloatProperty" => ((FloatProperty)Value[i]).GetValue(), + "ObjectProperty" => ((ObjectProperty)Value[i]).GetValue(), + "NameProperty" => ((NameProperty)Value[i]).GetValue(), + "DoubleProperty" => ((DoubleProperty)Value[i]).GetValue(), + "ArrayProperty" => ((ArrayProperty)Value[i]).GetValue(), + "StructProperty" => ((StructProperty)Value[i]).GetValue(), + "StrProperty" => ((StrProperty)Value[i]).GetValue(), + "TextProperty" => ((TextProperty)Value[i]).GetValue(), + "InterfaceProperty" => ((InterfaceProperty)Value[i]).GetValue(), + "SoftObjectProperty" => ((SoftObjectProperty)Value[i]).GetValue(), + "UInt64Property" => ((UInt64Property)Value[i]).GetValue(), + "UInt32Property" => ((UInt32Property)Value[i]).GetValue(), + "UInt16Property" => ((UInt16Property)Value[i]).GetValue(), + "Int64Property" => ((Int64Property)Value[i]).GetValue(), + "Int16Property" => ((Int16Property)Value[i]).GetValue(), + "Int8Property" => ((Int8Property)Value[i]).GetValue(), + "MapProperty" => ((MapProperty)Value[i]).GetValue(), + "SetProperty" => ((SetProperty)Value[i]).GetValue(), + "EnumProperty" => ((EnumProperty)Value[i]).GetValue(), + _ => Value[i], + }; + } + return ret; + } } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs index e275518a..5024e321 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs @@ -11,5 +11,7 @@ namespace PakReader.Parsers.PropertyTagData if (readType == ReadType.MAP) reader.Position += 16 - (reader.Position - Position); // skip ahead, putting the total bytes read to 16 } + + public FSoftObjectPath GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs index 31dc0c0f..700efc11 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadFString(); } + + public string GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs index 5ab7a8e7..87d29ee3 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs @@ -1,4 +1,6 @@ -using PakReader.Parsers.Objects; +using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using System.Collections.Generic; namespace PakReader.Parsers.PropertyTagData { @@ -9,5 +11,60 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = new UScriptStruct(reader, tag.StructName).Struct; } + + public object GetValue() + { + if (Value is UObject obj) + { + var ret = new Dictionary(obj.Count); + foreach (KeyValuePair KvP in obj) + { + if (KvP.Value == null) + ret[KvP.Key] = null; + else + ret[KvP.Key] = KvP.Value.GetType().Name switch + { + "ByteProperty" => ((ByteProperty)KvP.Value).GetValue(), + "BoolProperty" => ((BoolProperty)KvP.Value).GetValue(), + "IntProperty" => ((IntProperty)KvP.Value).GetValue(), + "FloatProperty" => ((FloatProperty)KvP.Value).GetValue(), + "ObjectProperty" => ((ObjectProperty)KvP.Value).GetValue(), + "NameProperty" => ((NameProperty)KvP.Value).GetValue(), + "DoubleProperty" => ((DoubleProperty)KvP.Value).GetValue(), + "ArrayProperty" => ((ArrayProperty)KvP.Value).GetValue(), + "StructProperty" => ((StructProperty)KvP.Value).GetValue(), + "StrProperty" => ((StrProperty)KvP.Value).GetValue(), + "TextProperty" => ((TextProperty)KvP.Value).GetValue(), + "InterfaceProperty" => ((InterfaceProperty)KvP.Value).GetValue(), + "SoftObjectProperty" => ((SoftObjectProperty)KvP.Value).GetValue(), + "UInt64Property" => ((UInt64Property)KvP.Value).GetValue(), + "UInt32Property" => ((UInt32Property)KvP.Value).GetValue(), + "UInt16Property" => ((UInt16Property)KvP.Value).GetValue(), + "Int64Property" => ((Int64Property)KvP.Value).GetValue(), + "Int16Property" => ((Int16Property)KvP.Value).GetValue(), + "Int8Property" => ((Int8Property)KvP.Value).GetValue(), + "MapProperty" => ((MapProperty)KvP.Value).GetValue(), + "SetProperty" => ((SetProperty)KvP.Value).GetValue(), + "EnumProperty" => ((EnumProperty)KvP.Value).GetValue(), + _ => KvP.Value, + }; + } + return ret; + } + else if (Value is FGameplayTagContainer gTags) + { + var ret = new string[gTags.GameplayTags.Length]; + for (int i = 0; i < ret.Length; i++) + { + ret[i] = gTags.GameplayTags[i].String; + } + return ret; + } + else if (Value is FGuid guid) + { + return guid.Hex; + } + return Value; + } } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs index 17d03ef4..21a82c73 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = new FText(reader); } + + public FText GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs b/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs index 13841ef3..da1d654c 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadUInt16(); } + + public ushort GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs b/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs index 4ff5947a..025bba98 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadUInt32(); } + + public uint GetValue() => Value; } } diff --git a/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs b/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs index ee91f2aa..d0d6b7c2 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs @@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData Position = reader.Position; Value = reader.ReadUInt64(); } + + public ulong GetValue() => Value; } } diff --git a/FModel/Properties/Resources.Designer.cs b/FModel/Properties/Resources.Designer.cs index 18e3e621..5e5fdb17 100644 --- a/FModel/Properties/Resources.Designer.cs +++ b/FModel/Properties/Resources.Designer.cs @@ -1419,7 +1419,7 @@ namespace FModel.Properties { } /// - /// Recherche une chaîne localisée semblable à Idling. + /// Recherche une chaîne localisée semblable à {0} - Idling. /// public static string Idling { get { @@ -1567,6 +1567,15 @@ namespace FModel.Properties { } } + /// + /// Recherche une chaîne localisée semblable à JSON Type. + /// + public static string JsonType { + get { + return ResourceManager.GetString("JsonType", resourceCulture); + } + } + /// /// Recherche une chaîne localisée semblable à KB. /// @@ -2909,6 +2918,15 @@ namespace FModel.Properties { } } + /// + /// Recherche une chaîne localisée semblable à With Position. + /// + public static string WithPosition { + get { + return ResourceManager.GetString("WithPosition", resourceCulture); + } + } + /// /// Recherche une chaîne localisée semblable à Yes. /// diff --git a/FModel/Properties/Resources.ar.resx b/FModel/Properties/Resources.ar.resx index c6e6f63e..908836cb 100644 --- a/FModel/Properties/Resources.ar.resx +++ b/FModel/Properties/Resources.ar.resx @@ -446,7 +446,7 @@ It's now the most used free software to leak on Fortnite. File not found, watermarking disabled - Idling + {0} - Idling الصور diff --git a/FModel/Properties/Resources.de-DE.resx b/FModel/Properties/Resources.de-DE.resx index a1f01d70..c72ba8e9 100644 --- a/FModel/Properties/Resources.de-DE.resx +++ b/FModel/Properties/Resources.de-DE.resx @@ -416,7 +416,7 @@ Jetzt ist es die am häufigsten genutzte freie Software um mit Fortnite zu leake Datei nicht gefunden, Wasserzeichen deaktiviert - Leerlauf + {0} - Leerlauf Bild erfolgreich gespeichert diff --git a/FModel/Properties/Resources.es.resx b/FModel/Properties/Resources.es.resx index 312c7b2b..d7e6455d 100644 --- a/FModel/Properties/Resources.es.resx +++ b/FModel/Properties/Resources.es.resx @@ -561,7 +561,7 @@ Ahora es el software gratuito más utilizado para filtrar en Fortnite. ..\Resources\icon-creator.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - Inactivo + {0} - Inactivo Imágenes diff --git a/FModel/Properties/Resources.fr-FR.resx b/FModel/Properties/Resources.fr-FR.resx index e2c9a8d1..e5451ff3 100644 --- a/FModel/Properties/Resources.fr-FR.resx +++ b/FModel/Properties/Resources.fr-FR.resx @@ -461,7 +461,7 @@ C'est maintenant le logiciel gratuit le plus utilisé pour leak sur Fortnite.Fichier introuvable, filigrane désactivé - En Attente + {0} - En Attente Images @@ -865,4 +865,10 @@ C'est maintenant le logiciel gratuit le plus utilisé pour leak sur Fortnite. Pas de fond + + Type de JSON + + + Avec Position + \ No newline at end of file diff --git a/FModel/Properties/Resources.it-IT.resx b/FModel/Properties/Resources.it-IT.resx index d3ce5585..18025527 100644 --- a/FModel/Properties/Resources.it-IT.resx +++ b/FModel/Properties/Resources.it-IT.resx @@ -440,7 +440,7 @@ Col tempo sono state aggiunte nuove funzioni e molti altri utenti hanno comincia File non trovato, filigrana disabilitata - Nessun incarico assegnato + {0} - Nessun incarico assegnato Immagini diff --git a/FModel/Properties/Resources.ja-JP.resx b/FModel/Properties/Resources.ja-JP.resx index 44917c57..9d37640a 100644 --- a/FModel/Properties/Resources.ja-JP.resx +++ b/FModel/Properties/Resources.ja-JP.resx @@ -214,7 +214,7 @@ 新規および変更されたファイルを読み込む - アイドリング + {0} - アイドリング テキストなし diff --git a/FModel/Properties/Resources.resx b/FModel/Properties/Resources.resx index b50d9dc5..55b88c9b 100644 --- a/FModel/Properties/Resources.resx +++ b/FModel/Properties/Resources.resx @@ -574,7 +574,7 @@ It's now the most used free software to leak on Fortnite. ..\Resources\icon-creator.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - Idling + {0} - Idling Images @@ -1109,4 +1109,10 @@ It's now the most used free software to leak on Fortnite. ..\Resources\borderlands3.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + JSON Type + + + With Position + \ No newline at end of file diff --git a/FModel/Properties/Settings.Designer.cs b/FModel/Properties/Settings.Designer.cs index 103e43dd..5fe6af11 100644 --- a/FModel/Properties/Settings.Designer.cs +++ b/FModel/Properties/Settings.Designer.cs @@ -299,6 +299,18 @@ namespace FModel.Properties { } } + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public long AssetsJsonType { + get { + return ((long)(this["AssetsJsonType"])); + } + set { + this["AssetsJsonType"] = value; + } + } + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("0")] diff --git a/FModel/Properties/Settings.settings b/FModel/Properties/Settings.settings index 27ff1761..6c9430e4 100644 --- a/FModel/Properties/Settings.settings +++ b/FModel/Properties/Settings.settings @@ -71,6 +71,9 @@ 0 + + 0 + 0 diff --git a/FModel/Utils/Assets.cs b/FModel/Utils/Assets.cs index f46969cf..ab04b96b 100644 --- a/FModel/Utils/Assets.cs +++ b/FModel/Utils/Assets.cs @@ -20,10 +20,11 @@ using System.Windows; using FModel.Windows.CustomNotifier; using FModel.ViewModels.Buttons; using System.Threading; -using static FModel.Creator.Creator; using SkiaSharp; using System.Text; using FModel.ViewModels.DataGrid; +using static FModel.Creator.FortniteCreator; +using static FModel.Creator.ValorantCreator; namespace FModel.Utils { @@ -173,7 +174,9 @@ namespace FModel.Utils { PakPackage p = GetPakPackage(entry, mount, loadContent); if (!p.Equals(default)) - return JsonConvert.SerializeObject(p.GetAllExports(), Formatting.Indented); + { + return p.JsonData; + } return string.Empty; } @@ -238,8 +241,10 @@ namespace FModel.Utils return p; } - // Creator Image - if (TryDrawIcon(entry.Name, p.GetFirstExportType(), p.GetFirstExport())) + // Image Creator + if (Globals.Game.ActualGame == EGame.Fortnite && TryDrawFortniteIcon(entry.Name, p.ExportTypes[0].String, p.Exports[0])) + return p; + else if (Globals.Game.ActualGame == EGame.Valorant && TryDrawValorantIcon(entry.Name, p.Exports.Length > 1 ? p.Exports[1] : p.Exports[0])) return p; } diff --git a/FModel/Utils/EGL2.cs b/FModel/Utils/EGL2.cs index ebf3ece0..6e896231 100644 --- a/FModel/Utils/EGL2.cs +++ b/FModel/Utils/EGL2.cs @@ -8,7 +8,7 @@ namespace FModel.Utils static class EGL2 { const uint FILE_CONFIG_MAGIC = 0x279B21E6; - const ushort FILE_CONFIG_VERSION = (ushort)ESettingsVersion.Version13; + const ushort FILE_CONFIG_VERSION = (ushort)ESettingsVersion.Latest; public static string GetEGL2PakFilesPath() { @@ -18,10 +18,10 @@ namespace FModel.Utils using Stream stream = new BufferedStream(new FileInfo(configFile).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); using BinaryReader reader = new BinaryReader(stream, Encoding.Default); if (reader.ReadUInt32() != FILE_CONFIG_MAGIC) - throw new FileLoadException("Invalid file magic"); + throw new FileLoadException("Invalid EGL2 Config Magic"); - if (reader.ReadUInt16BE() != FILE_CONFIG_VERSION) - throw new FileLoadException("Invalid egl2 version"); + if (reader.ReadUInt16BE() < FILE_CONFIG_VERSION) + throw new FileLoadException("Invalid EGL2 Config Version"); int stringLength = reader.ReadUInt16BE(); string cacheDirectory = Encoding.UTF8.GetString(reader.ReadBytes(stringLength)); diff --git a/FModel/Utils/Paks.cs b/FModel/Utils/Paks.cs index 78f97c5d..0d98b2b6 100644 --- a/FModel/Utils/Paks.cs +++ b/FModel/Utils/Paks.cs @@ -116,7 +116,10 @@ namespace FModel.Utils files = new Dictionary(); foreach (FPakEntry entry in tempFiles.Values) { - if (files.ContainsKey(mount + entry.GetPathWithoutExtension()) || entry.GetExtension().Equals(".uptnl")) + if (files.ContainsKey(mount + entry.GetPathWithoutExtension()) || + entry.GetExtension().Equals(".uptnl") || + entry.GetExtension().Equals(".uexp") || + entry.GetExtension().Equals(".ubulk")) continue; if (entry.IsUE4Package()) // if .uasset diff --git a/FModel/ViewModels/ComboBox/ComboBoxViewModel.cs b/FModel/ViewModels/ComboBox/ComboBoxViewModel.cs index 26c954fa..2bb4c466 100644 --- a/FModel/ViewModels/ComboBox/ComboBoxViewModel.cs +++ b/FModel/ViewModels/ComboBox/ComboBoxViewModel.cs @@ -23,6 +23,12 @@ namespace FModel.ViewModels.ComboBox new ComboBoxViewModel { Id = 14, Content = Properties.Resources.TraditionalChinese, Property = ELanguage.TraditionalChinese } }; + public static ObservableCollection jsonCbViewModel = new ObservableCollection + { + new ComboBoxViewModel { Id = 0, Content = Properties.Resources.Default, Property = EJsonType.Default }, + new ComboBoxViewModel { Id = 1, Content = Properties.Resources.WithPosition, Property = EJsonType.Positioned } + }; + public static ObservableCollection designCbViewModel = new ObservableCollection { new ComboBoxViewModel { Id = 0, Content = Properties.Resources.Default, Property = EIconDesign.Default }, diff --git a/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs b/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs index 5e3c83e5..05aa1043 100644 --- a/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs +++ b/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs @@ -279,7 +279,7 @@ namespace FModel.ViewModels.MenuItem int compressionMethodIndex = reader.ReadInt32(); // we only need name and uncompressedSize to compare - FPakEntry entry = new FPakEntry("CatsWillDominateTheWorld.pak", name, offset, size, uncompressedSize, new byte[20], null, 0, (uint)compressionMethodIndex, 0); + FPakEntry entry = new FPakEntry("CatsWillDominateTheWorld.pak", name, offset, size, uncompressedSize, null, 0, (uint)compressionMethodIndex, 0); oldFilesTemp[entry.Name] = entry; } } diff --git a/FModel/Windows/Search/Search.xaml.cs b/FModel/Windows/Search/Search.xaml.cs index a8404f90..aeaebb22 100644 --- a/FModel/Windows/Search/Search.xaml.cs +++ b/FModel/Windows/Search/Search.xaml.cs @@ -22,6 +22,7 @@ namespace FModel.Windows.Search private void OnLoaded(object sender, RoutedEventArgs e) { AssetFilter_TxtBox.Focus(); + AssetFilter_TxtBox.SelectAll(); TotalAssets_Lbl.Text = string.Format(Properties.Resources.TotalAssetsLoaded, DataGridVm.dataGridViewModel.Count.ToString("# ### ###", new NumberFormatInfo { NumberGroupSeparator = " " }).Trim()); Assets_DtGrd.ItemsSource = DataGridVm.dataGridViewModel; } diff --git a/FModel/Windows/Settings/General.xaml b/FModel/Windows/Settings/General.xaml index 67f53cfe..e4222dad 100644 --- a/FModel/Windows/Settings/General.xaml +++ b/FModel/Windows/Settings/General.xaml @@ -81,6 +81,7 @@ + @@ -99,21 +100,12 @@ BorderBrush="#7F748198" Background="#FF333C46" Height="20" VerticalAlignment="Top" Margin="0,3,0,0"/> - - - - - - - - - - - +