diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index b0c1dd5a..c803bf70 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -111,6 +111,7 @@ + diff --git a/FModel/Options.Designer.cs b/FModel/Options.Designer.cs index 3bf76ed1..a36e3210 100644 --- a/FModel/Options.Designer.cs +++ b/FModel/Options.Designer.cs @@ -244,9 +244,9 @@ this.checkBox8.AutoSize = true; this.checkBox8.Location = new System.Drawing.Point(6, 79); this.checkBox8.Name = "checkBox8"; - this.checkBox8.Size = new System.Drawing.Size(177, 17); + this.checkBox8.Size = new System.Drawing.Size(233, 17); this.checkBox8.TabIndex = 26; - this.checkBox8.Text = "Use Featured Image If Available"; + this.checkBox8.Text = "Use Characters\' Featured Image If Available"; this.checkBox8.UseVisualStyleBackColor = true; this.checkBox8.CheckedChanged += new System.EventHandler(this.checkBox8_CheckedChanged); // diff --git a/FModel/PAKWindow.cs b/FModel/PAKWindow.cs index b2224695..8a202203 100644 --- a/FModel/PAKWindow.cs +++ b/FModel/PAKWindow.cs @@ -2,6 +2,7 @@ using FModel.Parser.Featured; using FModel.Challenges; using FModel.Quest; +using FModel.RenderMat; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -166,9 +167,6 @@ namespace FModel Properties.Settings.Default.ExtractAndSerialize = true; //SERIALIZE BY DEFAULT docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).ToString() + "\\FModel"; - if (!Directory.Exists(docPath)) - Directory.CreateDirectory(docPath); - if (string.IsNullOrEmpty(Properties.Settings.Default.ExtractOutput)) { Properties.Settings.Default.ExtractOutput = docPath; @@ -179,6 +177,9 @@ namespace FModel docPath = Properties.Settings.Default.ExtractOutput; } + if (!Directory.Exists(docPath)) + Directory.CreateDirectory(docPath); + if (!Directory.Exists(Properties.Settings.Default.FortnitePAKs)) { loadAllPAKsToolStripMenuItem.Enabled = false; @@ -1915,7 +1916,117 @@ namespace FModel } try { - if (filesPath2 != null) + if (filesPath2 != null && filesPath2.Contains("MI_UI_FeaturedRenderSwitch_")) + { + AppendText("✔ ", Color.Green); + AppendText(textureFile, Color.DarkRed); + AppendText(" successfully extracted to ", Color.Black); + AppendText(filesPath2.Substring(0, filesPath2.LastIndexOf('.')), Color.SteelBlue, true); + try + { + await Task.Run(() => + { + jwpmProcess("serialize \"" + filesPath2.Substring(0, filesPath2.LastIndexOf('.')) + "\""); + }); + var filesJSON3 = Directory.GetFiles(docPath, textureFile + ".json", SearchOption.AllDirectories).FirstOrDefault(); + var json3 = JToken.Parse(File.ReadAllText(filesJSON3)).ToString(); + File.Delete(filesJSON3); + AppendText("✔ ", Color.Green); + AppendText(textureFile, Color.DarkRed); + AppendText(" successfully serialized", Color.Black, true); + + var RenderParser = RenderSwitchMaterial.FromJson(json3); + for (int i2 = 0; i2 < RenderParser.Length; i2++) + { + if (RenderParser[i2].TextureParameterValues.FirstOrDefault().ParameterValue != null) + { + string textureFile2 = RenderParser[i2].TextureParameterValues.FirstOrDefault().ParameterValue; + AppendText("✔ ", Color.Green); + AppendText(textureFile2, Color.DarkRed); + AppendText(" detected as a ", Color.Black); + AppendText("Texture2D file", Color.SteelBlue, true); + + var filesPath3 = Directory.GetFiles(docPath + "\\Extracted", textureFile2 + ".*", SearchOption.AllDirectories).FirstOrDefault(); + if (!File.Exists(filesPath3)) + { + if (currentGUID != "0-0-0-0") + { + await Task.Run(() => + { + jwpmProcess("extract \"" + Properties.Settings.Default.FortnitePAKs + "\\" + currentPAK + "\" \"" + textureFile2 + "\" \"" + docPath + "\""); + }); + filesPath3 = Directory.GetFiles(docPath + "\\Extracted", textureFile2 + ".*", SearchOption.AllDirectories).FirstOrDefault(); + } + else + { + if (isAllPAKs == false) + { + await Task.Run(() => + { + jwpmProcess("extract \"" + Properties.Settings.Default.FortnitePAKs + "\\pakchunk0_s7-WindowsClient.pak" + "\" \"" + textureFile2 + "\" \"" + docPath + "\""); + }); + } + if (isAllPAKs == true) + { + await Task.Run(() => { + try + { + jwpmProcess("extract \"" + Properties.Settings.Default.FortnitePAKs + "\\" + AllPAKsDict[textureFile2] + "\" \"" + textureFile2 + "\" \"" + docPath + "\""); + } + catch (KeyNotFoundException ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.Write("[ERROR] "); + Console.ForegroundColor = ConsoleColor.White; + Console.Write(ex.Message); + } + }); + } + filesPath3 = Directory.GetFiles(docPath + "\\Extracted", textureFile2 + ".*", SearchOption.AllDirectories).FirstOrDefault(); + } + } + try + { + if (filesPath3 != null) + { + AppendText("✔ ", Color.Green); + AppendText(textureFile2, Color.DarkRed); + AppendText(" successfully extracted to ", Color.Black); + AppendText(filesPath3.Substring(0, filesPath3.LastIndexOf('.')), Color.SteelBlue, true); + + itemIconPath = filesPath3.Substring(0, filesPath3.LastIndexOf('.')) + ".png"; + if (!File.Exists(itemIconPath)) + { + await Task.Run(() => + { + jwpmProcess("texture \"" + filesPath3.Substring(0, filesPath3.LastIndexOf('.')) + "\""); + }); + itemIconPath = filesPath3.Substring(0, filesPath3.LastIndexOf('.')) + ".png"; + } + + AppendText("✔ ", Color.Green); + AppendText(textureFile2, Color.DarkRed); + AppendText(" successfully converted to a PNG image with path ", Color.Black); + AppendText(itemIconPath, Color.SteelBlue, true); + } + } + catch (IndexOutOfRangeException) + { + AppendText("[IndexOutOfRangeException] ", Color.Red); + AppendText("Can't extract ", Color.Black); + AppendText(textureFile2, Color.SteelBlue); + AppendText(" in ", Color.Black); + AppendText("pakchunk0_s7-WindowsClient.pak", Color.DarkRed, true); + } + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + else if (filesPath2 != null && !filesPath2.Contains("MI_UI_FeaturedRenderSwitch_")) { AppendText("✔ ", Color.Green); AppendText(textureFile, Color.DarkRed); diff --git a/FModel/Parser/RenderSwitchMaterial.cs b/FModel/Parser/RenderSwitchMaterial.cs new file mode 100644 index 00000000..befb3989 --- /dev/null +++ b/FModel/Parser/RenderSwitchMaterial.cs @@ -0,0 +1,106 @@ +// +// +// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do: +// +// using FModel.RenderMat; +// +// var renderSwitchMaterial = RenderSwitchMaterial.FromJson(jsonString); + +namespace FModel.RenderMat +{ + using System; + using System.Collections.Generic; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class RenderSwitchMaterial + { + [JsonProperty("export_type")] + public string ExportType { get; set; } + + [JsonProperty("Parent")] + public string Parent { get; set; } + + [JsonProperty("ScalarParameterValues")] + public ScalarParameterValue[] ScalarParameterValues { get; set; } + + [JsonProperty("TextureParameterValues")] + public TextureParameterValue[] TextureParameterValues { get; set; } + + [JsonProperty("BasePropertyOverrides")] + public BasePropertyOverrides BasePropertyOverrides { get; set; } + } + + public partial class BasePropertyOverrides + { + [JsonProperty("BlendMode")] + public string BlendMode { get; set; } + + [JsonProperty("ShadingModel")] + public string ShadingModel { get; set; } + + [JsonProperty("OpacityMaskClipValue")] + public double OpacityMaskClipValue { get; set; } + } + + public partial class ScalarParameterValue + { + [JsonProperty("ParameterInfo")] + public ParameterInfo ParameterInfo { get; set; } + + [JsonProperty("ParameterValue")] + public long ParameterValue { get; set; } + + [JsonProperty("ExpressionGUID")] + public string ExpressionGuid { get; set; } + } + + public partial class ParameterInfo + { + [JsonProperty("Name")] + public string Name { get; set; } + + [JsonProperty("Association")] + public string Association { get; set; } + + [JsonProperty("Index")] + public long Index { get; set; } + } + + public partial class TextureParameterValue + { + [JsonProperty("ParameterInfo")] + public ParameterInfo ParameterInfo { get; set; } + + [JsonProperty("ParameterValue")] + public string ParameterValue { get; set; } + + [JsonProperty("ExpressionGUID")] + public string ExpressionGuid { get; set; } + } + + public partial class RenderSwitchMaterial + { + public static RenderSwitchMaterial[] FromJson(string json) => JsonConvert.DeserializeObject(json, FModel.RenderMat.Converter.Settings); + } + + public static class Serialize + { + public static string ToJson(this RenderSwitchMaterial[] self) => JsonConvert.SerializeObject(self, FModel.RenderMat.Converter.Settings); + } + + internal static class Converter + { + public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings + { + MetadataPropertyHandling = MetadataPropertyHandling.Ignore, + DateParseHandling = DateParseHandling.None, + Converters = + { + new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } + }, + }; + } +} diff --git a/README.md b/README.md index 25f02cee..e0c12b5a 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ I'd highly suggest you to use [UModel](https://github.com/gildor2/UModel) instea - [x] Quest viewer or something - [x] Load all paks - [ ] Shop loader ? +- [ ] Update mode (auto extraction and icon creation of every useful thing) - [x] Load only difference between 2 paks version - [x] Custom watermark option on icons - [x] Choose between extracted filename or displayName for icons file name