mirror of
https://github.com/4sval/FModel.git
synced 2026-08-24 10:24:32 -05:00
added basic valorant icon support + json type chooser
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using FModel.Creator.Icons;
|
||||
using FModel.Creator.Icons;
|
||||
using FModel.Creator.Rarities;
|
||||
using FModel.Creator.Stats;
|
||||
using FModel.Creator.Texts;
|
||||
|
||||
90
FModel/Creator/BaseUIData.cs
Normal file
90
FModel/Creator/BaseUIData.cs
Normal file
@@ -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<TextProperty>("DisplayName") is TextProperty displayName)
|
||||
DisplayName = Text.GetTextPropertyBase(displayName);
|
||||
if (export.GetExport<TextProperty>("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<ObjectProperty>("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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,11 @@ namespace FModel.Creator
|
||||
if (export.GetExport<TextProperty>("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<ArrayProperty>("OptionValues") is ArrayProperty optionValues)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -10,14 +10,14 @@ using System.IO;
|
||||
|
||||
namespace FModel.Creator
|
||||
{
|
||||
static class Creator
|
||||
static class FortniteCreator
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <returns>true if an icon has been drawn</returns>
|
||||
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;
|
||||
@@ -1,4 +1,4 @@
|
||||
using PakReader.Pak;
|
||||
using PakReader.Pak;
|
||||
using PakReader.Parsers.Class;
|
||||
using PakReader.Parsers.PropertyTagData;
|
||||
using SkiaSharp;
|
||||
|
||||
@@ -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("<Emphasized>", string.Empty).Replace("</>", string.Empty);
|
||||
else if (text.Text is FTextHistory.StringTableEntry s)
|
||||
{
|
||||
|
||||
@@ -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<byte>[] t = Utils.GetPropertyArraySegmentByte(_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK);
|
||||
ArraySegment<byte>[] 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<byte>[] 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 ?
|
||||
|
||||
36
FModel/Creator/ValorantCreator.cs
Normal file
36
FModel/Creator/ValorantCreator.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -55,6 +55,12 @@
|
||||
TraditionalChinese
|
||||
}
|
||||
|
||||
public enum EJsonType: long
|
||||
{
|
||||
Default,
|
||||
Positioned
|
||||
}
|
||||
|
||||
public enum EIconDesign : long
|
||||
{
|
||||
Default,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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<byte> UExp;
|
||||
readonly ArraySegment<byte> 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<string, object> GetJsonDict(IUExport export)
|
||||
{
|
||||
if (export != null)
|
||||
{
|
||||
var ret = new Dictionary<string, object>(export.Count);
|
||||
foreach (KeyValuePair<string, object> 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<T>() 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ namespace PakReader.Parsers.Class
|
||||
/// The derived class must have a "readonly Dictionary<string, object>" of properties
|
||||
/// </summary>
|
||||
public interface IUExport : IReadOnlyDictionary<string, object>
|
||||
{ }
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -9,11 +9,8 @@ namespace PakReader.Parsers.Class
|
||||
{
|
||||
public class UObject : IUExport, IUStruct
|
||||
{
|
||||
public FObjectExport ExportInfo { get; internal set; }
|
||||
readonly Dictionary<string, object> 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<string, object>();
|
||||
var properties = new Dictionary<string, object>();
|
||||
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<string, object> GetValue()
|
||||
{
|
||||
var ret = new Dictionary<string, object>(Dict.Count);
|
||||
foreach (KeyValuePair<string, object> 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<string> Keys => Dict.Keys;
|
||||
public IEnumerable<object> Values => Dict.Values;
|
||||
|
||||
18
FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs
Normal file
18
FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
16
FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs
Normal file
16
FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<string, object>
|
||||
{
|
||||
["ObjectName"] = Resource.ObjectName.String,
|
||||
["OuterIndex"] = Resource.OuterIndex.GetValue()
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsNull => Index == 0;
|
||||
[JsonIgnore]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace PakReader.Parsers.PropertyTagData
|
||||
{
|
||||
public sealed class ArrayProperty : BaseProperty<BaseProperty[]>
|
||||
public sealed class ArrayProperty : BaseProperty<object[]>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T> : BaseProperty
|
||||
|
||||
@@ -22,5 +22,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
throw new ArgumentOutOfRangeException(nameof(readType));
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,5 +16,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(readType)),
|
||||
};
|
||||
}
|
||||
|
||||
public byte GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadDouble();
|
||||
}
|
||||
|
||||
public double GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadFName();
|
||||
}
|
||||
|
||||
public string GetValue() => Value.String;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadFloat();
|
||||
}
|
||||
|
||||
public float GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadInt16();
|
||||
}
|
||||
|
||||
public short GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadInt64();
|
||||
}
|
||||
|
||||
public long GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadByte();
|
||||
}
|
||||
|
||||
public byte GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public int GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public uint GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using PakReader.Parsers.Objects;
|
||||
|
||||
namespace PakReader.Parsers.PropertyTagData
|
||||
{
|
||||
public sealed class MapProperty : BaseProperty<IReadOnlyDictionary<BaseProperty, BaseProperty>>
|
||||
public sealed class MapProperty : BaseProperty<IReadOnlyDictionary<object, object>>
|
||||
{
|
||||
// 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<BaseProperty, BaseProperty>(NumEntries);
|
||||
var dict = new Dictionary<object, object>(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<object, object> GetValue()
|
||||
{
|
||||
var ret = new Dictionary<object, object>(Value.Count);
|
||||
foreach (KeyValuePair<object, object> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadFName();
|
||||
}
|
||||
|
||||
public string GetValue() => Value.String;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using PakReader.Parsers.Objects;
|
||||
|
||||
namespace PakReader.Parsers.PropertyTagData
|
||||
{
|
||||
public sealed class SetProperty : BaseProperty<BaseProperty[]>
|
||||
public sealed class SetProperty : BaseProperty<object[]>
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadFString();
|
||||
}
|
||||
|
||||
public string GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<string, object>(obj.Count);
|
||||
foreach (KeyValuePair<string, object> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = new FText(reader);
|
||||
}
|
||||
|
||||
public FText GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
public ushort GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public uint GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ namespace PakReader.Parsers.PropertyTagData
|
||||
Position = reader.Position;
|
||||
Value = reader.ReadUInt64();
|
||||
}
|
||||
|
||||
public ulong GetValue() => Value;
|
||||
}
|
||||
}
|
||||
|
||||
20
FModel/Properties/Resources.Designer.cs
generated
20
FModel/Properties/Resources.Designer.cs
generated
@@ -1419,7 +1419,7 @@ namespace FModel.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Idling.
|
||||
/// Recherche une chaîne localisée semblable à {0} - Idling.
|
||||
/// </summary>
|
||||
public static string Idling {
|
||||
get {
|
||||
@@ -1567,6 +1567,15 @@ namespace FModel.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à JSON Type.
|
||||
/// </summary>
|
||||
public static string JsonType {
|
||||
get {
|
||||
return ResourceManager.GetString("JsonType", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à KB.
|
||||
/// </summary>
|
||||
@@ -2909,6 +2918,15 @@ namespace FModel.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à With Position.
|
||||
/// </summary>
|
||||
public static string WithPosition {
|
||||
get {
|
||||
return ResourceManager.GetString("WithPosition", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Yes.
|
||||
/// </summary>
|
||||
|
||||
@@ -446,7 +446,7 @@ It's now the most used free software to leak on Fortnite.</value>
|
||||
<value>File not found, watermarking disabled</value>
|
||||
</data>
|
||||
<data name="Idling" xml:space="preserve">
|
||||
<value>Idling</value>
|
||||
<value>{0} - Idling</value>
|
||||
</data>
|
||||
<data name="Images" xml:space="preserve">
|
||||
<value>الصور</value>
|
||||
|
||||
@@ -416,7 +416,7 @@ Jetzt ist es die am häufigsten genutzte freie Software um mit Fortnite zu leake
|
||||
<value>Datei nicht gefunden, Wasserzeichen deaktiviert</value>
|
||||
</data>
|
||||
<data name="Idling" xml:space="preserve">
|
||||
<value>Leerlauf</value>
|
||||
<value>{0} - Leerlauf</value>
|
||||
</data>
|
||||
<data name="ImageSaved" xml:space="preserve">
|
||||
<value>Bild erfolgreich gespeichert</value>
|
||||
|
||||
@@ -561,7 +561,7 @@ Ahora es el software gratuito más utilizado para filtrar en Fortnite.</value>
|
||||
<value>..\Resources\icon-creator.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Idling" xml:space="preserve">
|
||||
<value>Inactivo</value>
|
||||
<value>{0} - Inactivo</value>
|
||||
</data>
|
||||
<data name="Images" xml:space="preserve">
|
||||
<value>Imágenes</value>
|
||||
|
||||
@@ -461,7 +461,7 @@ C'est maintenant le logiciel gratuit le plus utilisé pour leak sur Fortnite.</v
|
||||
<value>Fichier introuvable, filigrane désactivé</value>
|
||||
</data>
|
||||
<data name="Idling" xml:space="preserve">
|
||||
<value>En Attente</value>
|
||||
<value>{0} - En Attente</value>
|
||||
</data>
|
||||
<data name="Images" xml:space="preserve">
|
||||
<value>Images</value>
|
||||
@@ -865,4 +865,10 @@ C'est maintenant le logiciel gratuit le plus utilisé pour leak sur Fortnite.</v
|
||||
<data name="NoBackground" xml:space="preserve">
|
||||
<value>Pas de fond</value>
|
||||
</data>
|
||||
<data name="JsonType" xml:space="preserve">
|
||||
<value>Type de JSON</value>
|
||||
</data>
|
||||
<data name="WithPosition" xml:space="preserve">
|
||||
<value>Avec Position</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -440,7 +440,7 @@ Col tempo sono state aggiunte nuove funzioni e molti altri utenti hanno comincia
|
||||
<value>File non trovato, filigrana disabilitata</value>
|
||||
</data>
|
||||
<data name="Idling" xml:space="preserve">
|
||||
<value>Nessun incarico assegnato</value>
|
||||
<value>{0} - Nessun incarico assegnato</value>
|
||||
</data>
|
||||
<data name="Images" xml:space="preserve">
|
||||
<value>Immagini</value>
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
<value>新規および変更されたファイルを読み込む</value>
|
||||
</data>
|
||||
<data name="Idling" xml:space="preserve">
|
||||
<value>アイドリング</value>
|
||||
<value>{0} - アイドリング</value>
|
||||
</data>
|
||||
<data name="NoText" xml:space="preserve">
|
||||
<value>テキストなし</value>
|
||||
|
||||
@@ -574,7 +574,7 @@ It's now the most used free software to leak on Fortnite.</value>
|
||||
<value>..\Resources\icon-creator.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Idling" xml:space="preserve">
|
||||
<value>Idling</value>
|
||||
<value>{0} - Idling</value>
|
||||
</data>
|
||||
<data name="Images" xml:space="preserve">
|
||||
<value>Images</value>
|
||||
@@ -1109,4 +1109,10 @@ It's now the most used free software to leak on Fortnite.</value>
|
||||
<data name="borderlands3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\borderlands3.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="JsonType" xml:space="preserve">
|
||||
<value>JSON Type</value>
|
||||
</data>
|
||||
<data name="WithPosition" xml:space="preserve">
|
||||
<value>With Position</value>
|
||||
</data>
|
||||
</root>
|
||||
12
FModel/Properties/Settings.Designer.cs
generated
12
FModel/Properties/Settings.Designer.cs
generated
@@ -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")]
|
||||
|
||||
@@ -71,6 +71,9 @@
|
||||
<Setting Name="AssetsLanguage" Type="System.Int64" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="AssetsJsonType" Type="System.Int64" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="AssetsIconDesign" Type="System.Int64" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -116,7 +116,10 @@ namespace FModel.Utils
|
||||
files = new Dictionary<string, FPakEntry>();
|
||||
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
|
||||
|
||||
@@ -23,6 +23,12 @@ namespace FModel.ViewModels.ComboBox
|
||||
new ComboBoxViewModel { Id = 14, Content = Properties.Resources.TraditionalChinese, Property = ELanguage.TraditionalChinese }
|
||||
};
|
||||
|
||||
public static ObservableCollection<ComboBoxViewModel> jsonCbViewModel = new ObservableCollection<ComboBoxViewModel>
|
||||
{
|
||||
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<ComboBoxViewModel> designCbViewModel = new ObservableCollection<ComboBoxViewModel>
|
||||
{
|
||||
new ComboBoxViewModel { Id = 0, Content = Properties.Resources.Default, Property = EIconDesign.Default },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="5"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -99,21 +100,12 @@
|
||||
BorderBrush="#7F748198" Background="#FF333C46"
|
||||
Height="20" VerticalAlignment="Top" Margin="0,3,0,0"/>
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="5,0,0,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="10"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="10" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="{x:Static properties:Resources.FyiTitle}"
|
||||
FontWeight="Bold" Foreground="White" Grid.Row="1"
|
||||
FontFamily="Calibri" FontSize="18"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.FyiDetails}"
|
||||
FontWeight="Light" Foreground="White" Grid.Row="2"
|
||||
TextWrapping="Wrap" FontSize="11" MaxWidth="350"/>
|
||||
</Grid>
|
||||
<Label Grid.Row="2" Grid.Column="1"
|
||||
Content="{x:Static properties:Resources.JsonType}"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
<ComboBox x:Name="Json_CbBox" Grid.Row="2" Grid.Column="2"
|
||||
BorderBrush="#7F748198" Background="#FF333C46"
|
||||
Height="20" VerticalAlignment="Top" Margin="0,3,0,0"/>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="4" Grid.RowSpan="3">
|
||||
<Grid.RowDefinitions>
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace FModel.Windows.Settings
|
||||
_useEnglish = Properties.Settings.Default.UseEnglish;
|
||||
Languages_CbBox.ItemsSource = ComboBoxVm.languageCbViewModel;
|
||||
Languages_CbBox.SelectedItem = ComboBoxVm.languageCbViewModel.Where(x => x.Id == Properties.Settings.Default.AssetsLanguage).FirstOrDefault();
|
||||
Json_CbBox.ItemsSource = ComboBoxVm.jsonCbViewModel;
|
||||
Json_CbBox.SelectedItem = ComboBoxVm.jsonCbViewModel.Where(x => x.Id == Properties.Settings.Default.AssetsJsonType).FirstOrDefault();
|
||||
}
|
||||
|
||||
private async Task SaveAndExit()
|
||||
@@ -52,7 +54,11 @@ namespace FModel.Windows.Settings
|
||||
Properties.Settings.Default.AssetsLanguage = Languages_CbBox.SelectedIndex;
|
||||
await Localizations.SetLocalization(Properties.Settings.Default.AssetsLanguage, true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (Properties.Settings.Default.AssetsJsonType != Json_CbBox.SelectedIndex)
|
||||
{
|
||||
Properties.Settings.Default.AssetsJsonType = Json_CbBox.SelectedIndex;
|
||||
Assets.ClearCachedFiles();
|
||||
}
|
||||
|
||||
if (!_inputPath.Equals(Properties.Settings.Default.PakPath) ||
|
||||
!_outputPath.Equals(Properties.Settings.Default.OutputPath) ||
|
||||
|
||||
Reference in New Issue
Block a user