From 720035bbf1b231cf00e64d4737529b322b478005 Mon Sep 17 00:00:00 2001 From: Lunaretic Date: Sun, 7 Jul 2024 17:52:47 -0400 Subject: [PATCH 1/7] Moving WizardData and ModpackUpgrader classes into core project, + many config changes. --- ConsoleTools/App.config | 8 + ConsoleTools/ConsoleTools.csproj | 26 + ConsoleTools/Program.cs | 145 ++ ConsoleTools/Properties/launchSettings.json | 8 + FFXIV_TexTools.sln | 59 +- FFXIV_TexTools/App.xaml.cs | 12 - FFXIV_TexTools/Console/ConsoleManager.cs | 65 - FFXIV_TexTools/FFXIV_TexTools.csproj | 42 +- FFXIV_TexTools/Helpers/FlexibleMessageBox.cs | 5 +- FFXIV_TexTools/Helpers/ModpackUpgrader.cs | 202 --- .../Helpers/ModpackUpgraderWrapper.cs | 79 + FFXIV_TexTools/MainWindow.xaml.cs | 8 +- .../Models/PenumbraUpgradeStatus.cs | 1 + FFXIV_TexTools/Properties/launchSettings.json | 7 + .../ModPack/Wizard/EditImcGroupWindow.xaml.cs | 1 + .../Wizard/EditableOptionControl.xaml.cs | 1 + .../ModPack/Wizard/ExportWizardWindow.xaml.cs | 1 + .../Views/ModPack/Wizard/ImcOptionRow.xaml.cs | 1 + .../ModPack/Wizard/ImportWizardWindow.xaml.cs | 2 + .../Wizard/ManipulationEditorWindow.xaml.cs | 1 + .../Views/ModPack/Wizard/WizardData.cs | 1527 ----------------- .../ModPack/Wizard/WizardPageControl.xaml.cs | 1 + FFXIV_TexTools/Views/OnboardingWindow.xaml.cs | 124 +- .../Views/Textures/EyeDiffuseCreator.xaml.cs | 1 + .../ForceUpdateAssembly.csproj | 6 +- lib/xivModdingFramework | 2 +- 26 files changed, 399 insertions(+), 1936 deletions(-) create mode 100644 ConsoleTools/App.config create mode 100644 ConsoleTools/ConsoleTools.csproj create mode 100644 ConsoleTools/Program.cs create mode 100644 ConsoleTools/Properties/launchSettings.json delete mode 100644 FFXIV_TexTools/Console/ConsoleManager.cs delete mode 100644 FFXIV_TexTools/Helpers/ModpackUpgrader.cs create mode 100644 FFXIV_TexTools/Helpers/ModpackUpgraderWrapper.cs create mode 100644 FFXIV_TexTools/Properties/launchSettings.json delete mode 100644 FFXIV_TexTools/Views/ModPack/Wizard/WizardData.cs diff --git a/ConsoleTools/App.config b/ConsoleTools/App.config new file mode 100644 index 00000000..3c5edad4 --- /dev/null +++ b/ConsoleTools/App.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ConsoleTools/ConsoleTools.csproj b/ConsoleTools/ConsoleTools.csproj new file mode 100644 index 00000000..6e7fbb91 --- /dev/null +++ b/ConsoleTools/ConsoleTools.csproj @@ -0,0 +1,26 @@ + + + + Exe + net8.0 + disable + enable + ..\\bin\\$(Configuration)\\ + false + + + echo Moving DLL Files + mkdir $(TargetDir)lib + xcopy $(TargetDir)*.dll $(TargetDir)lib /y + del *.dll + del *.cso + move $(TargetDir)lib\\ConsoleTools.dll $(TargetDir)ConsoleTools.dll + + + + + + + + + diff --git a/ConsoleTools/Program.cs b/ConsoleTools/Program.cs new file mode 100644 index 00000000..c1450a54 --- /dev/null +++ b/ConsoleTools/Program.cs @@ -0,0 +1,145 @@ +using HelixToolkit.SharpDX.Core.Utilities; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using xivModdingFramework.Cache; +using xivModdingFramework.Mods; + +namespace ConsoleTools +{ + public class ConsoleTools + { + private static string[] _Args; + public static int Main(string[] args) + { + // Manual lib loader because the app.config method isn't working for some reason. + var cwd = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "lib"); + var referenceFiles = Directory.GetFiles(cwd, "*.dll", SearchOption.AllDirectories); + + AppDomain.CurrentDomain.AssemblyResolve += (obj, arg) => + { + var name = $"{new AssemblyName(arg.Name).Name}.dll"; + var assemblyFile = referenceFiles.Where(x => x.EndsWith(name)) + .FirstOrDefault(); + if (assemblyFile != null) + return Assembly.LoadFrom(assemblyFile); + return null; + }; + + return Run(args).GetAwaiter().GetResult(); + } + + + public static async Task Run(string[] args) + { + _Args = args; + await ConsoleConfig.InitCacheFromConfig(); + + return await HandleConsoleArgs(); + } + + private static bool GetFlag(string flag) + { + if (_Args.Any(x => x == flag)) + { + return true; + } + return false; + } + private static string GetArg(string arg) + { + var idx = Array.IndexOf(_Args, arg); + if (idx >= 0) + { + return _Args[idx]; + } + return null; + } + public static async Task HandleConsoleArgs() + { + if (_Args == null || _Args.Length < 1) + { + return await ShowHelp(); + } + var cmd = _Args[0]; + + var code = -1; + if (cmd == "/?") + { + code = await ShowHelp(); + } + else if (cmd == "/u") + { + code = await HandleUpgrade(); + } + else + { + await ShowHelp(); + code = -1; + } + + return code; + } + + public static async Task HandleUpgrade() + { + if (_Args.Length < 4) + { + return -1; + } + + var src = _Args[2]; + var dest = _Args[3]; + System.Console.Write("Upgrading Modpack: " + src); + + try + { + await xivModdingFramework.Mods.ModpackUpgrader.UpgradeModpack(src, dest); + + System.Console.Write("Upgraded Modpack saved to: " + dest); + } + catch (Exception ex) + { + Trace.WriteLine(ex); + return -1; + } + return 0; + } + + public static async Task ShowHelp() + { + System.Console.WriteLine("==== ConsoleTools Help ===="); + System.Console.WriteLine(""); + System.Console.WriteLine("== Commands =="); + System.Console.WriteLine("\t/? - Help => You're looking at it."); + System.Console.WriteLine("\t/u [PathToSource] [PathToDestination] - Updates a given Modpack for Dawntrail."); + System.Console.WriteLine("\t/s [ModpackFilePath] [OutputFilePath] - Saves a given modpack file to a new path or type, after performing basic file processing."); + System.Console.WriteLine("\t/e [FfxivFilePath] [OutputFileName] - Extracts a given file from FFXIV. May be SQPacked with /sqpack"); + System.Console.WriteLine("\t/i [SourceFilePath] [OutputFilePath] - Creates an FFXIV packed file from the given source file. May be SQPacked with /sqpack"); + System.Console.WriteLine(""); + System.Console.WriteLine("== FORMATS =="); + System.Console.WriteLine("\tModpacks may be read or written in .ttmp2, .pmp, or unzipped PMP folder path formats."); + System.Console.WriteLine("\tImages may be saved as DDS, TEX, TGA, PNG, BMP."); + System.Console.WriteLine("\tModels may be either DB or FBX (or other formats if you have other external converters set up)."); + System.Console.WriteLine(""); + System.Console.WriteLine("== CURRENT CONFIG =="); + + var config = ConsoleConfig.Get(); + foreach (PropertyInfo prop in typeof(ConsoleConfig).GetProperties()) + { + var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; + System.Console.WriteLine(prop.Name + " : " + prop.GetValue(config, null).ToString()); + } + + return 0; + } + } +} + diff --git a/ConsoleTools/Properties/launchSettings.json b/ConsoleTools/Properties/launchSettings.json new file mode 100644 index 00000000..49d68e40 --- /dev/null +++ b/ConsoleTools/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "ConsoleTools": { + "commandName": "Project", + "commandLineArgs": "/?" + } + } +} \ No newline at end of file diff --git a/FFXIV_TexTools.sln b/FFXIV_TexTools.sln index ef4e37b4..1c4dd309 100644 --- a/FFXIV_TexTools.sln +++ b/FFXIV_TexTools.sln @@ -4,22 +4,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIV_TexTools", "FFXIV_TexTools\FFXIV_TexTools.csproj", "{4A5F7AB1-F296-450B-8F57-2FB82465964E}" + ProjectSection(ProjectDependencies) = postProject + {60DC3C4C-9911-4536-90A7-171C8336ED0A} = {60DC3C4C-9911-4536-90A7-171C8336ED0A} + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xivModdingFramework", "lib\xivModdingFramework\xivModdingFramework\xivModdingFramework.csproj", "{CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ForceUpdateAssembly", "ForceUpdateAssembly\ForceUpdateAssembly.csproj", "{734ACC29-8F05-4193-B981-F5266150F11F}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTools", "ConsoleTools\ConsoleTools.csproj", "{60DC3C4C-9911-4536-90A7-171C8336ED0A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Endwalker Debug|Any CPU = Endwalker Debug|Any CPU - Endwalker Debug|x64 = Endwalker Debug|x64 - Endwalker Debug|x86 = Endwalker Debug|x86 - Endwalker Release|Any CPU = Endwalker Release|Any CPU - Endwalker Release|x64 = Endwalker Release|x64 - Endwalker Release|x86 = Endwalker Release|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 @@ -31,18 +30,6 @@ Global {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Debug|x64.Build.0 = Debug|Any CPU {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Debug|x86.ActiveCfg = Debug|Any CPU {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Debug|x86.Build.0 = Debug|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Debug|Any CPU.ActiveCfg = Endwalker Debug|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Debug|Any CPU.Build.0 = Endwalker Debug|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Debug|x64.ActiveCfg = Endwalker Debug|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Debug|x64.Build.0 = Endwalker Debug|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Debug|x86.ActiveCfg = Endwalker Debug|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Debug|x86.Build.0 = Endwalker Debug|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Release|Any CPU.ActiveCfg = Endwalker Release|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Release|Any CPU.Build.0 = Endwalker Release|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Release|x64.ActiveCfg = Endwalker Release|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Release|x64.Build.0 = Endwalker Release|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Release|x86.ActiveCfg = Endwalker Release|Any CPU - {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Endwalker Release|x86.Build.0 = Endwalker Release|Any CPU {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Release|Any CPU.Build.0 = Release|Any CPU {4A5F7AB1-F296-450B-8F57-2FB82465964E}.Release|x64.ActiveCfg = Release|Any CPU @@ -55,18 +42,6 @@ Global {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Debug|x64.Build.0 = Debug|Any CPU {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Debug|x86.ActiveCfg = Debug|Any CPU {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Debug|x86.Build.0 = Debug|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Debug|Any CPU.ActiveCfg = Endwalker Debug|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Debug|Any CPU.Build.0 = Endwalker Debug|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Debug|x64.ActiveCfg = Endwalker Debug|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Debug|x64.Build.0 = Endwalker Debug|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Debug|x86.ActiveCfg = Endwalker Debug|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Debug|x86.Build.0 = Endwalker Debug|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Release|Any CPU.ActiveCfg = Endwalker Release|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Release|Any CPU.Build.0 = Endwalker Release|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Release|x64.ActiveCfg = Endwalker Release|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Release|x64.Build.0 = Endwalker Release|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Release|x86.ActiveCfg = Endwalker Release|Any CPU - {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Endwalker Release|x86.Build.0 = Endwalker Release|Any CPU {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Release|Any CPU.ActiveCfg = Release|Any CPU {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Release|Any CPU.Build.0 = Release|Any CPU {CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}.Release|x64.ActiveCfg = Release|Any CPU @@ -79,24 +54,24 @@ Global {734ACC29-8F05-4193-B981-F5266150F11F}.Debug|x64.Build.0 = Debug|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Debug|x86.ActiveCfg = Debug|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Debug|x86.Build.0 = Debug|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Debug|Any CPU.ActiveCfg = Endwalker Debug|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Debug|Any CPU.Build.0 = Endwalker Debug|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Debug|x64.ActiveCfg = Endwalker Debug|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Debug|x64.Build.0 = Endwalker Debug|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Debug|x86.ActiveCfg = Endwalker Debug|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Debug|x86.Build.0 = Endwalker Debug|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Release|Any CPU.ActiveCfg = Endwalker Release|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Release|Any CPU.Build.0 = Endwalker Release|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Release|x64.ActiveCfg = Endwalker Release|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Release|x64.Build.0 = Endwalker Release|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Release|x86.ActiveCfg = Endwalker Release|Any CPU - {734ACC29-8F05-4193-B981-F5266150F11F}.Endwalker Release|x86.Build.0 = Endwalker Release|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Release|Any CPU.ActiveCfg = Release|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Release|Any CPU.Build.0 = Release|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Release|x64.ActiveCfg = Release|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Release|x64.Build.0 = Release|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Release|x86.ActiveCfg = Release|Any CPU {734ACC29-8F05-4193-B981-F5266150F11F}.Release|x86.Build.0 = Release|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Debug|x64.ActiveCfg = Debug|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Debug|x64.Build.0 = Debug|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Debug|x86.ActiveCfg = Debug|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Debug|x86.Build.0 = Debug|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Release|Any CPU.Build.0 = Release|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Release|x64.ActiveCfg = Release|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Release|x64.Build.0 = Release|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Release|x86.ActiveCfg = Release|Any CPU + {60DC3C4C-9911-4536-90A7-171C8336ED0A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/FFXIV_TexTools/App.xaml.cs b/FFXIV_TexTools/App.xaml.cs index fa755b6c..64ae2525 100644 --- a/FFXIV_TexTools/App.xaml.cs +++ b/FFXIV_TexTools/App.xaml.cs @@ -15,18 +15,6 @@ namespace FFXIV_TexTools { - public static class EntryPoint - { - [STAThread] - public static int Main(string[] args) - { - var application = new App(); - var r = application.Run(); - return r; - } - - } - /// /// Interaction logic for App.xaml /// diff --git a/FFXIV_TexTools/Console/ConsoleManager.cs b/FFXIV_TexTools/Console/ConsoleManager.cs deleted file mode 100644 index d879d54b..00000000 --- a/FFXIV_TexTools/Console/ConsoleManager.cs +++ /dev/null @@ -1,65 +0,0 @@ -using FFXIV_TexTools.Helpers; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using xivModdingFramework.Cache; -using xivModdingFramework.General.Enums; - -namespace FFXIV_TexTools.Console -{ - - internal static class ConsoleManager - { - - public static async Task HandleConsoleArgs(string[] args) - { - if(args == null || args.Length < 1 || args[0] != "/c") - { - return false; - } - - var gameDir = new DirectoryInfo(Properties.Settings.Default.FFXIV_Directory); - var lang = XivLanguages.GetXivLanguage(Properties.Settings.Default.Application_Language); - await XivCache.SetGameInfo(gameDir, lang, false); - - var cmd = args[1]; - - var code = -1; - if(cmd == "/u") - { - code = await HandleUpgrade(args); - } - - Application.Current.Shutdown(code); - return true; - } - - public static async Task HandleUpgrade(string[] args) - { - if(args.Length < 4) - { - return -1; - } - - var src = args[2]; - var dest = args[3]; - - try - { - await ModpackUpgrader.UpgradeModpack(src, dest); - } catch (Exception ex) - { - Trace.WriteLine(ex); - return -1; - } - return 0; - } - - } -} diff --git a/FFXIV_TexTools/FFXIV_TexTools.csproj b/FFXIV_TexTools/FFXIV_TexTools.csproj index 4df7164b..cd295911 100644 --- a/FFXIV_TexTools/FFXIV_TexTools.csproj +++ b/FFXIV_TexTools/FFXIV_TexTools.csproj @@ -17,52 +17,43 @@ false true 0 - 2.0.0.0 false true FFXIV_TexTools FFXIV_TexTools Copyright © 2024 + + 3.0.3.2 3.0.3.2 3.0.3.2 + 9.0 - bin\$(Configuration)\ true + ..\\bin\\$(Configuration)\\ + false true - mkdir $(TargetDir)lib -move $(TargetDir)*.dll $(TargetDir)lib - mkdir $(TargetDir)lib -move $(TargetDir)*.dll $(TargetDir)lib - mkdir $(TargetDir)lib -move $(TargetDir)*.dll $(TargetDir)lib - Debug;Release;Endwalker Debug;Endwalker Release + + echo Moving DLL Files + mkdir $(TargetDir)lib + xcopy $(TargetDir)*.dll $(TargetDir)lib /y + del *.dll + del *.cso + move $(TargetDir)lib\\ConsoleTools.dll $(TargetDir)ConsoleTools.dll + + Debug;Release full $(DefineConstants);DAWNTRAIL - - full - $(DefineConstants);ENDWALKER - pdbonly $(DefineConstants);DAWNTRAIL - - pdbonly - $(DefineConstants);ENDWALKER - ffxiv2.ico - - app.manifest - - - mkdir $(TargetDir)lib -move $(TargetDir)*.dll $(TargetDir)lib - FFXIV_TexTools.EntryPoint + FFXIV_TexTools.App @@ -232,4 +223,7 @@ move $(TargetDir)*.dll $(TargetDir)lib Designer + + + diff --git a/FFXIV_TexTools/Helpers/FlexibleMessageBox.cs b/FFXIV_TexTools/Helpers/FlexibleMessageBox.cs index 0fe4598e..032bf76c 100644 --- a/FFXIV_TexTools/Helpers/FlexibleMessageBox.cs +++ b/FFXIV_TexTools/Helpers/FlexibleMessageBox.cs @@ -831,7 +831,10 @@ public static DialogResult Show(IWin32Window owner, string text, string caption, try { var mainWindow = MainWindow.GetMainWindow(); - owner = mainWindow.Win32Window; + if (mainWindow != null) + { + owner = mainWindow.Win32Window; + } } catch { // No-Op. diff --git a/FFXIV_TexTools/Helpers/ModpackUpgrader.cs b/FFXIV_TexTools/Helpers/ModpackUpgrader.cs deleted file mode 100644 index e3eb5c75..00000000 --- a/FFXIV_TexTools/Helpers/ModpackUpgrader.cs +++ /dev/null @@ -1,202 +0,0 @@ -using FFXIV_TexTools.Properties; -using FFXIV_TexTools.Views.Wizard; -using FFXIV_TexTools.Views; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using xivModdingFramework.Helpers; -using System.Windows.Forms; -using System.IO; -using System.Diagnostics; - -namespace FFXIV_TexTools.Helpers -{ - /// - /// Full modpack upgrade handler. - /// This lives in the UI project as it relies on the WizardData handler for simplification of modpack type handling. - /// - public static class ModpackUpgrader - { - public static async Task UpgradeModpackPrompted(bool includePartials = true) - { - var mw = MainWindow.GetMainWindow(); - var ofd = new OpenFileDialog() - { - Filter = ViewHelpers.LoadModpackFilter, - InitialDirectory = Path.GetFullPath(Settings.Default.ModPack_Directory), - }; - - if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK) - { - return; - } - - var path = ofd.FileName; - - - await mw.LockUi("Upgrading Modpack"); - try - { - - var data = await UpgradeModpack(path, includePartials); - - var ext = Path.GetExtension(path); - - var name = Path.GetFileNameWithoutExtension(path); - if (ext == ".json") - { - name = IOUtil.MakePathSafe(data.MetaPage.Name, false); - } - - if(ext != ".ttmp2" && ext != ".pmp") - { - ext = ".pmp"; - } - - - // Final Save location - var dir = Path.GetDirectoryName(path); - var fName = name + "_dt" + ext; - var sfd = new SaveFileDialog() - { - FileName = fName, - Filter = ViewHelpers.ModpackFileFilter, - InitialDirectory = dir, - }; - if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.OK) - { - return; - } - var newPath = sfd.FileName; - await data.WriteModpack(newPath); - } - catch (Exception ex) - { - ViewHelpers.ShowError("Modpack Upgrade Error", "An error occurred while upgrading the modpack:\n\n" + ex.Message); - } - finally - { - await mw.UnlockUi(); - } - } - - public static async Task UpgradeModpack(string path, bool includePartials = true) - { - if (Directory.Exists(path)) - { - path = Path.GetFullPath(Path.Combine(path, "meta.json")); - } - - var data = await WizardData.FromModpack(path); - var textureUpgradeTargets = new Dictionary(); - - var allTextures = new HashSet(); - - // First Round Upgrade - - // This does models and base MTRLS only. - foreach (var p in data.DataPages) - { - foreach (var g in p.Groups) - { - if (g == null) continue; - foreach (var o in g.Options) - { - if (o.StandardData != null) - { - try - { - var missing = await EndwalkerUpgrade.UpdateEndwalkerFiles(o.StandardData.Files); - foreach (var kv in missing) - { - if (!textureUpgradeTargets.ContainsKey(kv.Key)) - { - textureUpgradeTargets.Add(kv.Key, kv.Value); - } - } - - var textures = o.StandardData.Files.Select(x => x.Key).Where(x => x.EndsWith(".tex")); - allTextures.UnionWith(textures); - } - catch (Exception ex) - { - var mes = "An error occurred while updating Group: " + g.Name + " - Option: " + o.Name + "\n\n" + ex.Message; ; - throw new Exception(mes); - } - } - } - } - } - - - // Second Round Upgrade - This does textures based on the collated upgrade information from the previous pass - foreach (var p in data.DataPages) - { - foreach (var g in p.Groups) - { - if (g == null) continue; - foreach (var o in g.Options) - { - if (o.StandardData != null) - { - try - { - await EndwalkerUpgrade.UpgradeRemainingTextures(o.StandardData.Files, textureUpgradeTargets); - } - catch (Exception ex) - { - var mes = "An error occurred while updating Group: " + g.Name + " - Option: " + o.Name + "\n\n" + ex.Message; ; - throw new Exception(mes); - } - } - } - } - } - - - if (includePartials) - { - // Find all un-referenced textures. - var unusedTextures = new HashSet( - allTextures.Where(t => - !textureUpgradeTargets.Any(x => - x.Value.Files.ContainsValue(t) - ))); - - - // Third Round Upgrade - This inspects as-of-yet unupgraded textures for possible jank-upgrades, - // Which is to say, upgrades where we can infer their usage and pairing, but the base mtrl was not included. - foreach (var p in data.DataPages) - { - foreach (var g in p.Groups) - { - if (g == null) continue; - foreach (var o in g.Options) - { - if (o.StandardData != null) - { - var contained = unusedTextures.Where(x => o.StandardData.Files.ContainsKey(x)); - await EndwalkerUpgrade.UpdateUnclaimedHairTextures(contained.ToList(), "Unused", null, null, o.StandardData.Files); - - foreach (var possibleMask in contained) - { - await EndwalkerUpgrade.UpdateEyeMask(possibleMask, "Unused", null, null, o.StandardData.Files); - } - } - } - } - } - } - - return data; - } - - public static async Task UpgradeModpack(string path, string newPath, bool includePartials = true) - { - var data = await UpgradeModpack(path, includePartials); - - await data.WriteModpack(newPath); - } - } -} diff --git a/FFXIV_TexTools/Helpers/ModpackUpgraderWrapper.cs b/FFXIV_TexTools/Helpers/ModpackUpgraderWrapper.cs new file mode 100644 index 00000000..a0c5d9ef --- /dev/null +++ b/FFXIV_TexTools/Helpers/ModpackUpgraderWrapper.cs @@ -0,0 +1,79 @@ +using FFXIV_TexTools.Properties; +using FFXIV_TexTools.Views; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using xivModdingFramework.Helpers; + +namespace FFXIV_TexTools.Helpers +{ + internal class ModpackUpgraderWrapper + { + public static async Task UpgradeModpackPrompted(bool includePartials = true) + { + var mw = MainWindow.GetMainWindow(); + var ofd = new OpenFileDialog() + { + Filter = ViewHelpers.LoadModpackFilter, + InitialDirectory = Path.GetFullPath(Settings.Default.ModPack_Directory), + }; + + if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK) + { + return; + } + + var path = ofd.FileName; + + + await mw.LockUi("Upgrading Modpack"); + try + { + + var data = await xivModdingFramework.Mods.ModpackUpgrader.UpgradeModpack(path, includePartials); + + var ext = Path.GetExtension(path); + + var name = Path.GetFileNameWithoutExtension(path); + if (ext == ".json") + { + name = IOUtil.MakePathSafe(data.MetaPage.Name, false); + } + + if (ext != ".ttmp2" && ext != ".pmp") + { + ext = ".pmp"; + } + + + // Final Save location + var dir = Path.GetDirectoryName(path); + var fName = name + "_dt" + ext; + var sfd = new SaveFileDialog() + { + FileName = fName, + Filter = ViewHelpers.ModpackFileFilter, + InitialDirectory = dir, + }; + if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.OK) + { + return; + } + var newPath = sfd.FileName; + await data.WriteModpack(newPath); + } + catch (Exception ex) + { + ViewHelpers.ShowError("Modpack Upgrade Error", "An error occurred while upgrading the modpack:\n\n" + ex.Message); + } + finally + { + await mw.UnlockUi(); + } + } + } +} diff --git a/FFXIV_TexTools/MainWindow.xaml.cs b/FFXIV_TexTools/MainWindow.xaml.cs index 059c3da7..0e77cb62 100644 --- a/FFXIV_TexTools/MainWindow.xaml.cs +++ b/FFXIV_TexTools/MainWindow.xaml.cs @@ -14,7 +14,6 @@ // along with this program. If not, see . using AutoUpdaterDotNET; -using FFXIV_TexTools.Console; using FFXIV_TexTools.Helpers; using FFXIV_TexTools.Properties; using FFXIV_TexTools.Resources; @@ -404,11 +403,6 @@ public MainWindow(string[] args) private async Task HandleArgs(string[] args) { - if(await ConsoleManager.HandleConsoleArgs(args)) - { - return; - } - OnlyImport(args[0]); } @@ -2102,7 +2096,7 @@ private async void UpdateModpack_Click(object sender, RoutedEventArgs e) // Should we use this setting here? Or just always upgrade for modpacks? //includePartials = Settings.Default.FixPreDawntrailPartialOnImport; - await ModpackUpgrader.UpgradeModpackPrompted(includePartials); + await ModpackUpgraderWrapper.UpgradeModpackPrompted(includePartials); } catch { diff --git a/FFXIV_TexTools/Models/PenumbraUpgradeStatus.cs b/FFXIV_TexTools/Models/PenumbraUpgradeStatus.cs index 9227c8be..c98f2920 100644 --- a/FFXIV_TexTools/Models/PenumbraUpgradeStatus.cs +++ b/FFXIV_TexTools/Models/PenumbraUpgradeStatus.cs @@ -9,6 +9,7 @@ using xivModdingFramework.Helpers; using FFXIV_TexTools.Helpers; using System.Diagnostics; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Models { diff --git a/FFXIV_TexTools/Properties/launchSettings.json b/FFXIV_TexTools/Properties/launchSettings.json new file mode 100644 index 00000000..39b4fd7d --- /dev/null +++ b/FFXIV_TexTools/Properties/launchSettings.json @@ -0,0 +1,7 @@ +{ + "profiles": { + "FFXIV_TexTools": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/EditImcGroupWindow.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/EditImcGroupWindow.xaml.cs index 038edc07..79c504dc 100644 --- a/FFXIV_TexTools/Views/ModPack/Wizard/EditImcGroupWindow.xaml.cs +++ b/FFXIV_TexTools/Views/ModPack/Wizard/EditImcGroupWindow.xaml.cs @@ -20,6 +20,7 @@ using xivModdingFramework.Cache; using xivModdingFramework.Items.Interfaces; using xivModdingFramework.Variants.FileTypes; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Views.Wizard { diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/EditableOptionControl.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/EditableOptionControl.xaml.cs index d994dd4c..4fe13969 100644 --- a/FFXIV_TexTools/Views/ModPack/Wizard/EditableOptionControl.xaml.cs +++ b/FFXIV_TexTools/Views/ModPack/Wizard/EditableOptionControl.xaml.cs @@ -14,6 +14,7 @@ using System.Windows.Navigation; using System.Windows.Shapes; using xivModdingFramework.Mods.DataContainers; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Views { diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/ExportWizardWindow.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/ExportWizardWindow.xaml.cs index a49e985b..fe32fa79 100644 --- a/FFXIV_TexTools/Views/ModPack/Wizard/ExportWizardWindow.xaml.cs +++ b/FFXIV_TexTools/Views/ModPack/Wizard/ExportWizardWindow.xaml.cs @@ -37,6 +37,7 @@ using xivModdingFramework.Mods.FileTypes.PMP; using xivModdingFramework.Mods.Interfaces; using Image = SixLabors.ImageSharp.Image; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Views { diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/ImcOptionRow.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/ImcOptionRow.xaml.cs index 88222283..1079b596 100644 --- a/FFXIV_TexTools/Views/ModPack/Wizard/ImcOptionRow.xaml.cs +++ b/FFXIV_TexTools/Views/ModPack/Wizard/ImcOptionRow.xaml.cs @@ -16,6 +16,7 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using UserControl = System.Windows.Controls.UserControl; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Views.Wizard { diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/ImportWizardWindow.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/ImportWizardWindow.xaml.cs index 3ce0386d..93247cb4 100644 --- a/FFXIV_TexTools/Views/ModPack/Wizard/ImportWizardWindow.xaml.cs +++ b/FFXIV_TexTools/Views/ModPack/Wizard/ImportWizardWindow.xaml.cs @@ -38,6 +38,8 @@ using xivModdingFramework.Mods.DataContainers; using xivModdingFramework.Mods.FileTypes; using xivModdingFramework.Mods.FileTypes.PMP; +using xivModdingFramework.Mods; + namespace FFXIV_TexTools.Views.Wizard { /// diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditorWindow.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditorWindow.xaml.cs index 520ce1fb..3a222578 100644 --- a/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditorWindow.xaml.cs +++ b/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditorWindow.xaml.cs @@ -8,6 +8,7 @@ using System.Windows.Controls; using System.Windows.Input; using xivModdingFramework.Mods.FileTypes; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Views.Wizard { diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/WizardData.cs b/FFXIV_TexTools/Views/ModPack/Wizard/WizardData.cs deleted file mode 100644 index 9c3e79bc..00000000 --- a/FFXIV_TexTools/Views/ModPack/Wizard/WizardData.cs +++ /dev/null @@ -1,1527 +0,0 @@ -using SixLabors.ImageSharp.Formats.Png; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using xivModdingFramework.Cache; -using xivModdingFramework.General; -using xivModdingFramework.General.DataContainers; -using xivModdingFramework.Helpers; -using xivModdingFramework.Mods; -using xivModdingFramework.Mods.DataContainers; -using xivModdingFramework.Mods.FileTypes; -using xivModdingFramework.Mods.FileTypes.PMP; -using xivModdingFramework.SqPack.FileTypes; -using xivModdingFramework.Variants.DataContainers; -using xivModdingFramework.Variants.FileTypes; -using static xivModdingFramework.Mods.FileTypes.TTMP; -using Image = SixLabors.ImageSharp.Image; - -// ================================ // - -/// This file contains all of the Data Classes for the Advanced Modpack Wizard, both import and export. -/// This, thus, also contains all of the logic necessary for generating these classes from the -/// TTMP or PMP Json formats, and converting them back into those formats/into TTMP/PMP files. -/// -/// This borders a little on being too heavy to maintain as a TexTools class, but inevitably the -/// UI Model in this case are very close to the final product by definition, and difficult to break -/// apart without adding layers of inefficiency and redundancy that would make maintaining them even worse. - -// ================================ // - -namespace FFXIV_TexTools.Views.Wizard -{ - public enum EOptionType - { - Single, - Multi - }; - - public enum EGroupType - { - Standard, - Imc - }; - - internal static class WizardHelpers - { - public static string WriteImage(string currentPath, string tempFolder, string newName) { - - if (string.IsNullOrWhiteSpace(currentPath)) - { - return ""; - } - - if (!File.Exists(currentPath)) - { - return ""; - } - - var path = Path.Combine("images", newName + ".png"); - - var img = SixLabors.ImageSharp.Image.Load(currentPath); - var fName = Path.Combine(tempFolder, path); - var dir = Path.GetDirectoryName(fName); - Directory.CreateDirectory(dir); - - using var fs = File.OpenWrite(fName); - var enc = new PngEncoder(); - enc.BitDepth = PngBitDepth.Bit16; - img.Save(fs, enc); - - return path; - } - - } - - public class WizardStandardOptionData : WizardOptionData - { - public Dictionary Files = new Dictionary(); - - public List Manipulations = new List(); - - public int Priority; - - protected override bool CheckHasData() - { - return Files.Count > 0 || Manipulations.Count > 0; - } - - private static List ManipulationTypeSortOrder = new List() - { - "Imc", - "Eqp", - "Eqdp", - "Est", - "Gmp", - "Rsp", - "GlobalEqp" - }; - - public void SortManipulations() - { - Manipulations.Sort((a,b) => - { - if(a == null || b == null) - { - return -1; - } - var aType = ManipulationTypeSortOrder.IndexOf(a.Type); - var bType = ManipulationTypeSortOrder.IndexOf(b.Type); - - aType = aType < 0 ? int.MaxValue : aType; - bType = bType < 0 ? int.MaxValue : bType; - - if(aType != bType) - { - return aType - bType; - } - - if(a.Type == "Rsp") - { - var aRsp = a.GetManipulation() as PMPRspManipulationJson; - var bRsp = b.GetManipulation() as PMPRspManipulationJson; - - var aVal = (int)aRsp.GetRaceGenderHash(); - var bVal = (int)bRsp.GetRaceGenderHash(); - - aVal = aVal * 100 + (int)aRsp.Attribute; - bVal = bVal * 100 + (int)aRsp.Attribute; - return aVal - bVal; - } - - var aIm = a.GetManipulation() as IPMPItemMetadata; - var bIm = b.GetManipulation() as IPMPItemMetadata; - - if(aIm == null) - { - // No defined order for non Item, Non-Rsp types. - return 0; - } - - // Sort by root information. - var diff = GetSortOrder(aIm) - GetSortOrder(bIm); - if(diff != 0 || a.Type != "Imc") - { - return diff; - } - - var aImc = a.GetManipulation() as PMPImcManipulationJson; - var bImc = b.GetManipulation() as PMPImcManipulationJson; - - if(aImc == null) - { - return 0; - } - - return (int)aImc.Variant - (int)bImc.Variant; - }); - } - - private static int GetSortOrder (IPMPItemMetadata manipulation) - { - //Generic sort-order resolver for root using manipulations. - var root = manipulation.GetRoot(); - - // 6x shift - var val = (int)root.Info.PrimaryType * 1000000; - - // 2x shift - val += root.Info.PrimaryId * 100; - - // 0x shift - if (root.Info.Slot == null || !Imc.SlotOffsetDictionary.ContainsKey(root.Info.Slot)) - { - val += 0; - } - else - { - val += (Imc.SlotOffsetDictionary.Keys.ToList().IndexOf(root.Info.Slot) + 1); - } - - return val; - } - } - - public class WizardImcOptionData : WizardOptionData - { - public bool IsDisableOption; - public ushort AttributeMask; - - protected override bool CheckHasData() - { - if(AttributeMask > 0 || IsDisableOption) - { - return true; - } - return false; - } - } - - public class WizardOptionData - { - - public bool HasData - { - get - { - return CheckHasData(); - } - } - - protected virtual bool CheckHasData() - { - return false; - } - - } - - /// - /// Class representing a single, clickable [Option], - /// Aka a Radio Button or Checkbox the user can select, that internally resolves - /// to a single list of files to be imported. - /// - public class WizardOptionEntry : INotifyPropertyChanged - { - public string Name { get; set; } - public string Description { get; set; } - public string Image { get; set; } - - public string NoDataIndicator - { - get - { - if (HasData) - { - return ""; - } - - if(!_Group.Options.Any(x => x.HasData)) - { - // Group needs valid data. - return " (Empty)"; - } - - if(OptionType == EOptionType.Single) - { - if(_Group.Options.FirstOrDefault(x => !x.HasData) == this) - { - // First empty is preserved in single select. - return ""; - } - } - - return " (Empty)"; - } - } - - public bool HasData - { - get { - - if(_Group.ModOption != null) - { - // Read mode. - return true; - } - - if (StandardData != null) - { - return StandardData.HasData; - } else if(ImcData != null) - { - return ImcData.HasData; - } - return false; - } - } - - - private bool _Selected; - public bool Selected - { - get - { - return _Selected; - } - set - { - if (_Selected == value) return; - _Selected = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Selected))); - - var index = _Group.Options.IndexOf(this); - if (index < 0) return; - - if(GroupType == EGroupType.Imc && Selected == true) - { - if (ImcData.IsDisableOption) - { - foreach(var opt in _Group.Options) - { - if(!opt.ImcData.IsDisableOption) - { - opt.Selected = false; - } - } - } - else - { - foreach (var opt in _Group.Options) - { - if (opt.ImcData.IsDisableOption) - { - opt.Selected = false; - } - } - } - } - } - } - - private WizardGroupEntry _Group; - - // Group name is used by the UI template binding for establishing radio button groupings. - public string GroupName - { - get - { - return _Group.Name; - } - } - - // Option type is used by the UI template binding to determine template type. - public EOptionType OptionType - { - get - { - return _Group.OptionType; - } - } - public EGroupType GroupType - { - get - { - return _Group.GroupType; - } - } - - private WizardOptionData _Data = new WizardStandardOptionData(); - - public WizardImcOptionData ImcData - { - get - { - if(GroupType == EGroupType.Imc) - { - return _Data as WizardImcOptionData; - } else - { - return null; - } - } - set - { - if(GroupType == EGroupType.Imc) - { - _Data = value; - } - } - } - - public WizardStandardOptionData StandardData - { - get - { - if (GroupType == EGroupType.Standard) - { - return _Data as WizardStandardOptionData; - } - else - { - return null; - } - } - set - { - if (GroupType == EGroupType.Standard) - { - _Data = value; - } - } - } - - - public event PropertyChangedEventHandler PropertyChanged; - - public WizardOptionEntry(WizardGroupEntry owningGroup) - { - _Group = owningGroup; - } - - public async Task ToModOption() - { - Image img = null; - if (!string.IsNullOrWhiteSpace(Image)) - { - img = SixLabors.ImageSharp.Image.Load(Image); - } - - var mo = new ModOption() - { - Description = Description, - Name = Name, - GroupName = _Group.Name, - ImageFileName = Image, - IsChecked = Selected, - SelectionType = OptionType.ToString(), - Image = img, - }; - - if(StandardData == null) - { - throw new NotImplementedException("TTMP Export does not support one or more of the selected Option types."); - } - - foreach(var fkv in StandardData.Files) - { - var path = fkv.Key; - var forceType2 = path.EndsWith(".atex"); - if (!File.Exists(fkv.Value.RealPath)) - { - // Sometimes poorly behaved PMPs or Penumbra folders may have been used as a source, - // where they are missing files that they claim to have. - continue; - } - var data = await TransactionDataHandler.GetCompressedFile(fkv.Value, forceType2); - - var root = await XivCache.GetFirstRoot(path); - var itemCategory = "Unknown"; - var itemName = "Unknown"; - if(root != null) - { - var item = root.GetFirstItem(); - if(item != null) - { - itemCategory = item.SecondaryCategory; - itemName = item.Name; - } - } - - var mData = new ModData() - { - Name = itemName, - Category = itemCategory, - FullPath = path, - ModDataBytes = data, - }; - mo.Mods.Add(path, mData); - } - - if (StandardData.Manipulations != null && StandardData.Manipulations.Count > 0) { - // Readonly TX for retrieving base values. - var tx = ModTransaction.BeginReadonlyTransaction(); - var manips = await PMP.ManipulationsToMetadata(this.StandardData.Manipulations, tx); - - foreach(var meta in manips.Metadatas) - { - // Need to convert these and add them to the file array. - var item = meta.Root.GetFirstItem(); - var path = meta.Root.Info.GetRootFile(); - var mData = new ModData() - { - Name = item.Name, - Category = item.SecondaryCategory, - FullPath = path, - ModDataBytes = await SmartImport.CreateCompressedFile(await ItemMetadata.Serialize(meta), true), - }; - mo.Mods.Add(path, mData); - } - - foreach(var rgsp in manips.Rgsps) - { - // Need to convert these and add them to the file array. - var data = await SmartImport.CreateCompressedFile(rgsp.GetBytes(), true); - var path = CMP.GetRgspPath(rgsp); - var item = CMP.GetDummyItem(rgsp); - - var mData = new ModData() - { - Name = item.Name, - Category = item.SecondaryCategory, - FullPath = path, - ModDataBytes = data, - }; - mo.Mods.Add(path, mData); - } - } - - - return mo; - } - - public async Task ToPmpOption(string tempFolder, IEnumerable identifiers, string imageName) - { - PMPOptionJson op; - if(GroupType == EGroupType.Imc) - { - if (ImcData.IsDisableOption) - { - var io = new PmpDisableImcOptionJson(); - op = io; - io.IsDisableSubMod = true; - } else - { - var io = new PmpImcOptionJson(); - op = io; - io.AttributeMask = ImcData.AttributeMask; - } - op.Name = Name; - op.Description = Description; - } else - { - // This unpacks our deduplicated files as needed. - op = await PMP.CreatePmpStandardOption(tempFolder, Name, Description, identifiers, StandardData.Manipulations, null, StandardData.Priority); - } - - op.Image = WizardHelpers.WriteImage(Image, tempFolder, imageName); - - - return op; - } - } - - - public class WizardImcGroupData - { - public XivDependencyRoot Root = new XivDependencyRoot(new XivDependencyRootInfo() - { - PrimaryType = xivModdingFramework.Items.Enums.XivItemType.equipment, - PrimaryId = 1, - Slot = "top" - }); - public ushort Variant; - public XivImc BaseEntry = new XivImc(); - public bool AllVariants; - } - - /// - /// Class represnting a Group of options. - /// Aka a collection of radio buttons or checkboxes. - /// - public class WizardGroupEntry - { - public string Name; - public string Description; - public string Image; - - // Int or Bitflag depending on OptionType. - public int Selection - { - get - { - if(this.OptionType == EOptionType.Single) - { - var op = Options.FirstOrDefault(x => x.Selected); - if(op == null) - { - return 0; - } - return Options.IndexOf(op); - } - else - { - var total = 0; - for(int i = 0; i < Options.Count; i++) - { - if (Options[i].Selected) - { - uint mask = 1; - uint shifted = mask << i; - total |= (int)shifted; - } - } - return total; - } - } - } - - public EOptionType OptionType; - - public EGroupType GroupType - { - get - { - if(ImcData != null) - { - return EGroupType.Imc; - } - return EGroupType.Standard; - } - } - - public bool HasData - { - get - { - return Options.Any(x => x.HasData); - } - } - - - public List Options = new List(); - - /// - /// Option Data for Penumbra style Imc-Mask Option Groups. - /// - public WizardImcGroupData ImcData = null; - - public int Priority; - - /// - /// Handler to the base modpack option. - /// Typically either a ModGroupJson or PMPGroupJson - /// - public object ModOption; - - public static async Task FromWizardGroup(ModGroupJson tGroup, string unzipPath, bool needsTexFix) - { - var group = new WizardGroupEntry(); - group.Options = new List(); - group.ModOption = tGroup; - - group.Name = tGroup.GroupName; - group.OptionType = tGroup.SelectionType == "Single" ? EOptionType.Single : EOptionType.Multi; - - var mpdPath = Path.Combine(unzipPath, "TTMPD.mpd"); - - foreach(var o in tGroup.OptionList) - { - var wizOp = new WizardOptionEntry(group); - wizOp.Name = o.Name; - wizOp.Description = o.Description; - if(!String.IsNullOrWhiteSpace(o.ImagePath)) - { - wizOp.Image = Path.Combine(unzipPath, o.ImagePath); - } - wizOp.Selected = o.IsChecked; - - var data = new WizardStandardOptionData(); - - foreach(var mj in o.ModsJsons) - { - var finfo = new FileStorageInformation() - { - StorageType = EFileStorageType.CompressedBlob, - FileSize = mj.ModSize, - RealOffset = mj.ModOffset, - RealPath = mpdPath - }; - - // Data may not be unzipped here if we're in import mode. - if (File.Exists(finfo.RealPath)) - { - if (mj.FullPath.EndsWith(".meta") || mj.FullPath.EndsWith(".rgsp")) - { - var raw = await TransactionDataHandler.GetUncompressedFile(finfo); - if (mj.FullPath.EndsWith(".meta")) - { - var meta = await ItemMetadata.Deserialize(raw); - data.Manipulations.AddRange(PMPExtensions.MetadataToManipulations(meta)); - } - else - { - var rgsp = new RacialGenderScalingParameter(raw); - data.Manipulations.AddRange(PMPExtensions.RgspToManipulations(rgsp)); - } - } - else - { - if (needsTexFix && mj.FullPath.EndsWith(".tex")) - { - try - { - finfo = await TTMP.FixOldTexData(finfo); - } - catch(Exception ex) - { - Trace.WriteLine(ex); - // File majorly broken, skip it. - continue; - } - } else if(needsTexFix && mj.FullPath.EndsWith(".mdl")) - { - try - { - // Have to fix old busted models. - finfo = await EndwalkerUpgrade.FixOldModel(finfo); - } - catch (Exception ex) - { - Trace.WriteLine(ex); - // Hmm... What should we do about this? - // Skip the file? - continue; - } - } - - data.Files.Add(mj.FullPath, finfo); - } - } - } - - wizOp.StandardData = data; - - - - group.Options.Add(wizOp); - } - - if(group.Options.Count == 0) - { - // Empty group. - return null; - } - - if(group.OptionType == EOptionType.Single && !group.Options.Any(x => x.Selected)) - { - group.Options[0].Selected = true; - } - - return group; - } - - public static async Task FromPMPGroup(PMPGroupJson pGroup, string unzipPath) - { - var group = new WizardGroupEntry(); - group.Options = new List(); - group.ModOption = pGroup; - - group.OptionType = pGroup.Type == "Single" ? EOptionType.Single : EOptionType.Multi; - group.Name = pGroup.Name; - group.Priority = pGroup.Priority; - - if (!string.IsNullOrWhiteSpace(pGroup.Image)) - { - group.Image = Path.Combine(unzipPath, pGroup.Image); - } else - { - group.Image = ""; - } - - group.Description = pGroup.Description; - - var imcGroup = pGroup as PMPImcGroupJson; - if (imcGroup != null) - { - group.ImcData = new WizardImcGroupData() - { - Variant = imcGroup.Identifier.Variant, - Root = imcGroup.Identifier.GetRoot(), - BaseEntry = imcGroup.DefaultEntry.ToXivImc(), - AllVariants = imcGroup.AllVariants, - }; - } - - var idx = 0; - foreach(var o in pGroup.Options) - { - var wizOp = new WizardOptionEntry(group); - wizOp.Name = o.Name; - wizOp.Description = o.Description; - wizOp.Image = null; - - if (group.OptionType == EOptionType.Single) - { - wizOp.Selected = pGroup.DefaultSettings == idx; - } - else - { - var bit = 1 << idx; - wizOp.Selected = (pGroup.DefaultSettings & bit) != 0; - } - group.Options.Add(wizOp); - - if(group.GroupType == EGroupType.Standard) - { - var data = await PMP.UnpackPmpOption(o, null, unzipPath, false); - wizOp.StandardData.Files = data.Files; - wizOp.StandardData.Manipulations = data.OtherManipulations; - var sop = o as PmpStandardOptionJson; - if (sop != null) { - wizOp.StandardData.Priority = sop.Priority; - } - - } else if(group.GroupType == EGroupType.Imc) - { - var imcData = new WizardImcOptionData(); - var imcOp = o as PmpImcOptionJson; - if (imcOp != null) - { - imcData.IsDisableOption = false; - imcData.AttributeMask = imcOp.AttributeMask; - } - var defOp = o as PmpDisableImcOptionJson; - if(defOp != null) - { - imcData.IsDisableOption = defOp.IsDisableSubMod; - imcData.AttributeMask = 0; - } - wizOp.ImcData = imcData; - } - - if (!string.IsNullOrWhiteSpace(o.Image)) - { - wizOp.Image = Path.Combine(unzipPath, o.Image); - } - else - { - wizOp.Image = ""; - } - - idx++; - } - - if (group.Options.Count == 0) - { - // Empty group. - return null; - } - - if (group.OptionType == EOptionType.Single && !group.Options.Any(x => x.Selected)) - { - group.Options[0].Selected = true; - } - - - return group; - } - - public async Task ToModGroup() - { - if(this.ImcData != null) - { - throw new InvalidDataException("TTMP Does not support IMC Groups."); - } - - var mg = new ModGroup() - { - GroupName = Name, - OptionList = new List(), - SelectionType = OptionType.ToString(), - }; - - foreach(var option in Options) - { - var tOpt = await option.ToModOption(); - mg.OptionList.Add(tOpt); - } - - return mg; - } - - public async Task ToPmpGroup(string tempFolder, string groupPrefix, Dictionary> identifiers, int page, bool oneOption = false) - { - var pg = new PMPGroupJson(); - - if (this.ImcData != null) - { - var imcG = new PMPImcGroupJson(); - pg = imcG; - pg.Type = "Imc"; - - imcG.Identifier = PmpIdentifierJson.FromRoot(ImcData.Root.Info, ImcData.Variant); - imcG.DefaultEntry = PMPImcManipulationJson.PMPImcEntry.FromXivImc(ImcData.BaseEntry); - imcG.AllVariants = ImcData.AllVariants; - } - else - { - pg.Type = OptionType.ToString(); - } - - pg.Name = Name.Trim(); - pg.Description = Description; - pg.Options = new List(); - pg.Priority = Priority; - pg.DefaultSettings = Selection; - pg.SelectedSettings = Selection; - pg.Page = page; - - pg.Image = WizardHelpers.WriteImage(Image, tempFolder, IOUtil.MakePathSafe(Name)); - - foreach (var option in Options) - { - option.Name = option.Name.Trim(); - var optionPrefix = WizardData.MakeOptionPrefix(groupPrefix, this, option); - var imgName = optionPrefix; - if(imgName.Length > 0) - { - // Remove trailing slash - imgName = imgName.Substring(0, imgName.Length - 1); - } - - if (oneOption) - { - imgName = "default_image"; - } - identifiers.TryGetValue(optionPrefix, out var files); - var opt = await option.ToPmpOption(tempFolder, files, imgName); - pg.Options.Add(opt); - } - - return pg; - } - } - - /// - /// Class representing a Page of Groups. - /// - public class WizardPageEntry - { - public string Name; - public List Groups = new List(); - - public bool HasData - { - get - { - return Groups.Any(x => x.HasData); - } - } - - public static async Task FromWizardModpackPage(ModPackPageJson jp, string unzipPath, bool needsTexFix) - { - var page = new WizardPageEntry(); - page.Name = "Page " + (jp.PageIndex + 1); - - page.Groups = new List(); - foreach(var p in jp.ModGroups) - { - var g = await WizardGroupEntry.FromWizardGroup(p, unzipPath, needsTexFix); - if (g == null) continue; - page.Groups.Add(g); - } - return page; - } - - public async Task ToModPackPage(int index) - { - var mpp = new ModPackData.ModPackPage() { - PageIndex = index, - ModGroups = new List(), - }; - - foreach(var group in Groups) - { - var mpg = await group.ToModGroup(); - mpp.ModGroups.Add(mpg); - } - - return mpp; - } - } - - /// - /// Class representing the description/cover page of a Modpack. - /// - public class WizardMetaEntry - { - public string Name = ""; - public string Author = ""; - public string Description = ""; - public string Url = ""; - public string Version = "1.0"; - public string Image = ""; - - public static WizardMetaEntry FromPMP(PMPJson pmp, string unzipPath) - { - var meta = pmp.Meta; - var page = new WizardMetaEntry(); - page.Url = meta.Website; - page.Version = meta.Version; - page.Author = meta.Author; - page.Description = meta.Description; - page.Name = meta.Name; - - - if (!string.IsNullOrWhiteSpace(meta.Image)) - { - page.Image = Path.Combine(unzipPath, meta.Image); - } - else - { - page.Image = ""; - var hImage = pmp.GetHeaderImage(); - if (!string.IsNullOrWhiteSpace(hImage)) - { - meta.Image = Path.Combine(unzipPath, hImage); - } - } - return page; - } - - public static WizardMetaEntry FromTtmp(ModPackJson wiz, string unzipPath) - { - var page = new WizardMetaEntry(); - page.Url = wiz.Url; - page.Name = wiz.Name; - page.Version = wiz.Version; - page.Author = wiz.Author; - page.Description = wiz.Description; - - var img = wiz.GetHeaderImagePath(); - if (!string.IsNullOrWhiteSpace(img)) - { - page.Image = Path.Combine(unzipPath, img); - } - - - return page; - } - } - - - /// - /// The full set of data necessary to render and display a wizard modpack install. - /// - public class WizardData - { - public WizardMetaEntry MetaPage = new WizardMetaEntry(); - public List DataPages = new List(); - public EModpackType ModpackType; - public ModPack ModPack; - - public bool HasData - { - get - { - return DataPages.Any(x => x.HasData); - } - } - - /// - /// Original source this Wizard Data was generated from. - /// Null if the user created a fresh modpack in the UI. - /// - public object RawSource; - - public static async Task FromPmp(PMPJson pmp, string unzipPath) - { - var data = new WizardData(); - data.MetaPage = WizardMetaEntry.FromPMP(pmp, unzipPath); - data.DataPages = new List(); - data.ModpackType = EModpackType.Pmp; - - var mp = new ModPack(null); - mp.Author = data.MetaPage.Author; - mp.Version = data.MetaPage.Version; - mp.Name = data.MetaPage.Name; - mp.Url = data.MetaPage.Url; - data.ModPack = mp; - data.RawSource = pmp; - - if (pmp.Groups.Count > 0 && pmp.Groups.Any(x => x.Options.Count > 0)) - { - // Create sufficient pages. - var pageMax = pmp.Groups.Max(x => x.Page); - for (int i = 0; i <= pageMax; i++) - { - var page = new WizardPageEntry(); - page.Name = "Page " + (i+1).ToString(); - page.Groups = new List(); - data.DataPages.Add(page); - } - - // Assign groups to pages. - foreach (var g in pmp.Groups) - { - var page = data.DataPages[g.Page]; - page.Groups.Add(await WizardGroupEntry.FromPMPGroup(g, unzipPath)); - } - } else - { - - // Just drum up a basic group containing the default option. - var fakeGroup = new PMPGroupJson(); - fakeGroup.Name = "Default"; - fakeGroup.Options = new List() { pmp.DefaultMod }; - fakeGroup.SelectedSettings = 1; - fakeGroup.Type = "Single"; - - if (string.IsNullOrWhiteSpace(pmp.DefaultMod.Name)) - { - pmp.DefaultMod.Name = "Default"; - } - - var page = new WizardPageEntry(); - page.Name = "Page 1"; - page.Groups = new List(); - page.Groups.Add(await WizardGroupEntry.FromPMPGroup(fakeGroup, unzipPath)); - data.DataPages.Add(page); - } - return data; - } - - public static async Task FromWizardTtmp(ModPackJson mpl, string unzipPath) - { - var data = new WizardData(); - data.ModpackType = EModpackType.TtmpWizard; - data.MetaPage = WizardMetaEntry.FromTtmp(mpl, unzipPath); - - var mp = new ModPack(null); - mp.Author = data.MetaPage.Author; - mp.Version = data.MetaPage.Version; - mp.Name = data.MetaPage.Name; - mp.Url = data.MetaPage.Url; - data.ModPack = mp; - data.RawSource = mpl; - - var needsTexFix = TTMP.DoesModpackNeedTexFix(mpl); - - - data.DataPages = new List(); - foreach (var p in mpl.ModPackPages) - { - data.DataPages.Add(await WizardPageEntry.FromWizardModpackPage(p, unzipPath, needsTexFix)); - } - return data; - } - public static async Task FromSimpleTtmp(ModPackJson mpl, string unzipPath) - { - var data = new WizardData(); - data.ModpackType = EModpackType.TtmpWizard; - data.MetaPage = WizardMetaEntry.FromTtmp(mpl, unzipPath); - - var mp = new ModPack(null); - mp.Author = data.MetaPage.Author; - mp.Version = data.MetaPage.Version; - mp.Name = data.MetaPage.Name; - mp.Url = data.MetaPage.Url; - data.ModPack = mp; - data.RawSource = mpl; - - var needsTexFix = TTMP.DoesModpackNeedTexFix(mpl); - - // Create a fake page/group. - data.DataPages = new List(); - var page = new WizardPageEntry() - { - Groups = new List(), - Name = "Page 1" - }; - data.DataPages.Add(page); - - var mgj = new ModGroupJson() - { - GroupName = "Default Group", - SelectionType = "Single", - OptionList = new List() - { - new ModOptionJson() - { - Name = "Default Option", - IsChecked = true, - SelectionType = "Single", - GroupName = "Default Group", - ModsJsons = mpl.SimpleModsList, - }, - }, - }; - - var g = await WizardGroupEntry.FromWizardGroup(mgj, unzipPath, needsTexFix); - page.Groups.Add(g); - return data; - } - - - public void ClearEmpties() - { - var pages = DataPages.ToList(); - foreach(var p in pages) - { - if (!p.HasData) - { - DataPages.Remove(p); - continue; - } - - var groups = p.Groups.ToList(); - foreach(var g in groups) - { - if (g == null || !g.HasData) - { - p.Groups.Remove(g); - continue; - } - - var options = g.Options.ToList(); - var firstEmpty = false; - foreach (var o in options) - { - if (!o.HasData) - { - if (!firstEmpty && g.OptionType == EOptionType.Single) - { - // Allow one empty option for single selects. - firstEmpty = true; - continue; - } - g.Options.Remove(o); - continue; - } - } - } - } - - } - - public async Task WriteModpack(string targetPath) - { - if (targetPath.ToLower().EndsWith(".pmp")) - { - await WritePmp(targetPath); - } - else if(targetPath.ToLower().EndsWith(".ttmp2")) - { - await WriteWizardPack(targetPath); - } - else if (Directory.Exists(targetPath) || !Path.GetFileName(targetPath).Contains(".")) - { - Directory.CreateDirectory(targetPath); - await WritePmp(targetPath, false); - } - else - { - throw new ArgumentException("Invalid Modpack Path: " + targetPath); - } - } - public async Task WriteWizardPack(string targetPath) - { - ClearEmpties(); - - Version.TryParse(MetaPage.Version, out var ver); - - ver ??= new Version("1.0"); - var modPackData = new ModPackData() - { - Name = MetaPage.Name, - Author = MetaPage.Author, - Url = MetaPage.Url, - Version = ver, - Description = MetaPage.Description, - ModPackPages = new List(), - }; - - int i = 0; - foreach(var page in DataPages) - { - if (!page.HasData) - { - continue; - } - modPackData.ModPackPages.Add(await page.ToModPackPage(i)); - i++; - } - - await TTMP.CreateWizardModPack(modPackData, targetPath, null, true); - } - - private string MakePagePrefix(WizardPageEntry page) - { - var pagePrefix = ""; - if (DataPages.Count > 1) - { - var pIdx = DataPages.IndexOf(page); - pagePrefix = "p" + pIdx + "/"; - } - else if (page.Groups.Count == 1) - { - return ""; - } - return pagePrefix; - } - private string MakeGroupPrefix(WizardPageEntry page, WizardGroupEntry group) - { - var pagePrefix = MakePagePrefix(page); - if(page.Groups.Count == 1) - { - return pagePrefix; - } - var optionPrefix = pagePrefix + IOUtil.MakePathSafe(group.Name) + "/"; - return optionPrefix; - } - private string MakeOptionPrefix(WizardPageEntry page, WizardGroupEntry group, WizardOptionEntry option) - { - return MakeOptionPrefix(MakeGroupPrefix(page, group), group, option); - } - internal static string MakeOptionPrefix(string groupPrefix, WizardGroupEntry group, WizardOptionEntry option) - { - if (group.Options.Count > 1) - { - return groupPrefix + IOUtil.MakePathSafe(option.Name) + "/"; - } - else - { - return groupPrefix; - } - } - - public async Task WritePmp(string targetPath, bool zip = true) - { - ClearEmpties(); - - var pmp = new PMPJson() - { - DefaultMod = new PMPOptionJson(), - Groups = new List(), - Meta = new PMPMetaJson(), - }; - - var tempFolder = IOUtil.GetFrameworkTempSubfolder("PMP"); - Directory.CreateDirectory(tempFolder); - try - { - Version.TryParse(MetaPage.Version, out var ver); - ver ??= new Version("1.0"); - - pmp.Meta.Name = MetaPage.Name; - pmp.Meta.Author = MetaPage.Author; - pmp.Meta.Website = MetaPage.Url; - pmp.Meta.Description = MetaPage.Description; - pmp.Meta.Version = ver.ToString(); - pmp.Meta.Tags = new List(); - pmp.Meta.FileVersion = PMP._WriteFileVersion; - pmp.Meta.Image = WizardHelpers.WriteImage(MetaPage.Image, tempFolder, "_MetaImage"); - - var optionCount = DataPages.Sum(p => p.Groups.Sum(x => x.Options.Count)); - - // We need to compose a list of all the file storage information we're going to use. - // Grouped by option folder. - var allFiles = new Dictionary>(); - var pIdx = 1; - foreach(var p in DataPages) - { - foreach (var g in p.Groups) - { - g.Name = g.Name.Trim(); - foreach (var o in g.Options) - { - if(o.GroupType != EGroupType.Standard) - { - continue; - } - - var files = o.StandardData.Files; - - if(string.IsNullOrWhiteSpace(o.Name) || string.IsNullOrWhiteSpace(g.Name)) - { - throw new InvalidDataException("PMP Files must have valid group and option names."); - } - - - var optionPrefix = MakeOptionPrefix(p, g, o); - - if (allFiles.ContainsKey(optionPrefix)) - { - foreach(var f in files) - { - allFiles[optionPrefix].Add(f.Key, f.Value); - } - } - else - { - allFiles.Add(optionPrefix, files); - } - } - } - pIdx++; - } - - // These are de-duplicated internal write paths for the final PMP folder structure, coupled with - // their file identifier and internal path information - var identifiers = await FileIdentifier.IdentifierListFromDictionaries(allFiles); - - if(optionCount == 1) - { - pmp.DefaultMod = (await DataPages.First(x => x.Groups.Count > 0).Groups.First(x => x.Options.Count > 0).ToPmpGroup(tempFolder, "", identifiers, 0, true)).Options[0]; - } else - { - // This both constructs the JSON structure and writes our files to their - // real location in the folder tree in the temp folder. - var page = 0; - foreach (var p in DataPages) - { - foreach (var g in p.Groups) - { - var gPrefix = MakeGroupPrefix(p, g); - var pg = await g.ToPmpGroup(tempFolder, gPrefix, identifiers, page); - pmp.Groups.Add(pg); - } - page++; - } - } - - - // This performs the final json serialization/writing and zipping. - if (zip) - { - await PMP.WritePmp(pmp, tempFolder, targetPath); - } else - { - await PMP.WritePmp(pmp, tempFolder); - Directory.CreateDirectory(targetPath); - IOUtil.CopyFolder(tempFolder, targetPath); - } - } - finally - { - IOUtil.DeleteTempDirectory(tempFolder); - } - } - - /// - /// Updates the base Penumbra groups with the new user-selected values. - /// - public void FinalizePmpSelections() - { - // Need to go through and assign the Selected values back to the PMP. - foreach(var p in DataPages) - { - foreach(var g in p.Groups) - { - var pg = (g.ModOption as PMPGroupJson); - pg.SelectedSettings = g.Selection; - } - } - } - - - /// - /// Returns the list of selected mod files that the TTMP importers expect, based on user selection(s). - /// - /// - public List FinalizeTttmpSelections() - { - List modFiles = new List(); - // Need to go through and compile the final ModJson list. - foreach (var p in DataPages) - { - foreach (var g in p.Groups) - { - var ttGroup = g.ModOption as ModGroupJson; - if (ttGroup == null) - { - continue; - } - - var selected = 0; - for (int i = 0; i < g.Options.Count; i++) - { - var opt = g.Options[i]; - if (opt.Selected) - { - if (opt.GroupType == EGroupType.Standard) - { - if (opt.StandardData.Manipulations != null && opt.StandardData.Manipulations.Count > 0) - { - // We shouldn't actually be able to get to this path, but safety is good. - throw new NotImplementedException("Importing TTMPs with Meta Manipulations is not supported. How did you get here though?"); - } - - var ttOpt = ttGroup.OptionList[i]; - modFiles.AddRange(ttOpt.ModsJsons); - } else - { - // We shouldn't actually be able to get to this path, but safety is good. - throw new NotImplementedException("Importing TTMPs with IMC Groups is not supported. How did you get here though?"); - } - } - } - } - } - - // Assign mod pack linkage that the framework expects. - foreach(var mj in modFiles) - { - mj.ModPackEntry = ModPack; - } - - return modFiles; - } - - - /// - /// The simplest method for generating fully constructed wizard data. - /// Unzips the entire modpack in the process. - /// - /// - /// - public static async Task FromModpack(string modpack) - { - return await Task.Run(async () => - { - var modpackType = TTMP.GetModpackType(modpack); - - if (modpackType == TTMP.EModpackType.Pmp) - { - var pmp = await PMP.LoadPMP(modpack, false, true); - return await WizardData.FromPmp(pmp.pmp, pmp.path); - } - else if (modpackType == TTMP.EModpackType.TtmpWizard) - { - var ttmp = await TTMP.UnzipTtmp(modpack); - return await WizardData.FromWizardTtmp(ttmp.Mpl, ttmp.UnzipFolder); - } - else if (modpackType == TTMP.EModpackType.TtmpSimple || modpackType == TTMP.EModpackType.TtmpOriginal || modpackType == TTMP.EModpackType.TtmpBackup) - { - var ttmp = await TTMP.UnzipTtmp(modpack); - return await WizardData.FromSimpleTtmp(ttmp.Mpl, ttmp.UnzipFolder); - } - return null; - }); - } - } -} diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/WizardPageControl.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/WizardPageControl.xaml.cs index 2f0b03ac..6b81e646 100644 --- a/FFXIV_TexTools/Views/ModPack/Wizard/WizardPageControl.xaml.cs +++ b/FFXIV_TexTools/Views/ModPack/Wizard/WizardPageControl.xaml.cs @@ -29,6 +29,7 @@ using System.Windows.Media.Imaging; using xivModdingFramework.Mods.DataContainers; using Image = SixLabors.ImageSharp.Image; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Views.Wizard { diff --git a/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs b/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs index 2eb9ea11..2e50f732 100644 --- a/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs +++ b/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs @@ -189,6 +189,71 @@ public static void OnboardAndInitialize() CheckRerunAdmin(); ValidateModlist(); } + public static void InitializeSettings() + { + SetDirectories(); + XivCache.FrameworkSettings.DefaultTextureFormat = Settings.Default.CompressEndwalkerUpgradeTextures ? xivModdingFramework.Textures.Enums.XivTexFormat.BC7 : xivModdingFramework.Textures.Enums.XivTexFormat.A8R8G8B8; + + if (Enum.TryParse(Settings.Default.ModelingTool, true, out var mt)) + { + XivCache.FrameworkSettings.ModelingTool = mt; + } + XivCache.FrameworkSettings.DefaultTextureFormat = Settings.Default.CompressEndwalkerUpgradeTextures ? xivModdingFramework.Textures.Enums.XivTexFormat.BC7 : xivModdingFramework.Textures.Enums.XivTexFormat.A8R8G8B8; + + UpdateConsoleConfig(); + Properties.Settings.Default.SettingsSaving += (object sender, System.ComponentModel.CancelEventArgs e) => { + UpdateConsoleConfig(); + }; + + } + + private static void UpdateConsoleConfig() + { + ConsoleConfig.Update(x => + { + x.XivPath = Settings.Default.FFXIV_Directory; + x.Language = Settings.Default.Application_Language; + }); + } + + + + /// + /// Validates the various directories TexTools relies on. + /// + private static void SetDirectories() + { + // Create/assign directories if they don't exist already. + SetSaveDirectory(); + + SetBackupsDirectory(); + + SetModPackDirectory(); + } + + private static void SetSaveDirectory() + { + if (!Directory.Exists(Properties.Settings.Default.Save_Directory)) + { + Directory.CreateDirectory(Properties.Settings.Default.Save_Directory); + } + } + + private static void SetBackupsDirectory() + { + if (!Directory.Exists(Properties.Settings.Default.Backup_Directory)) + { + Directory.CreateDirectory(Properties.Settings.Default.Backup_Directory); + } + } + + private static void SetModPackDirectory() + { + if (!Directory.Exists(Properties.Settings.Default.ModPack_Directory)) + { + Directory.CreateDirectory(Properties.Settings.Default.ModPack_Directory); + } + } public static void ValidateModlist() { @@ -241,7 +306,7 @@ public static bool CheckRerunAdminSimple() } return true; } - public static void CheckRerunAdmin() + public static void CheckRerunAdmin(bool throwErrors = false) { var cwd = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); var converterFolder = Path.GetFullPath(Path.Combine(cwd, "converters")); @@ -255,6 +320,11 @@ public static void CheckRerunAdmin() if (!allSuccess && !IsRunningAsAdministrator()) { + if (throwErrors) + { + throw new ApplicationException("Application must be run as administrator for proper file access due to current folder configurations."); + } + // Setting up start info of the new process of the same application ProcessStartInfo processStartInfo = new ProcessStartInfo(Assembly.GetEntryAssembly().CodeBase); @@ -362,19 +432,6 @@ public static string GetDefaultInstallDirectory() return installDirectory; } - public static void InitializeSettings() - { - SetDirectories(); - XivCache.FrameworkSettings.DefaultTextureFormat = Settings.Default.CompressEndwalkerUpgradeTextures ? xivModdingFramework.Textures.Enums.XivTexFormat.BC7 : xivModdingFramework.Textures.Enums.XivTexFormat.A8R8G8B8; - - if (Enum.TryParse(Settings.Default.ModelingTool, true, out var mt)) - { - XivCache.FrameworkSettings.ModelingTool = mt; - } - XivCache.FrameworkSettings.DefaultTextureFormat = Settings.Default.CompressEndwalkerUpgradeTextures ? xivModdingFramework.Textures.Enums.XivTexFormat.BC7 : xivModdingFramework.Textures.Enums.XivTexFormat.A8R8G8B8; - - } - public static bool IsGameDirectoryValid(string dir) { if (string.IsNullOrEmpty(dir)) @@ -396,45 +453,6 @@ public static bool IsGameDirectoryValid(string dir) } - - - /// - /// Validates the various directories TexTools relies on. - /// - private static void SetDirectories() - { - // Create/assign directories if they don't exist already. - SetSaveDirectory(); - - SetBackupsDirectory(); - - SetModPackDirectory(); - } - - private static void SetSaveDirectory() - { - if (!Directory.Exists(Properties.Settings.Default.Save_Directory)) - { - Directory.CreateDirectory(Properties.Settings.Default.Save_Directory); - } - } - - private static void SetBackupsDirectory() - { - if (!Directory.Exists(Properties.Settings.Default.Backup_Directory)) - { - Directory.CreateDirectory(Properties.Settings.Default.Backup_Directory); - } - } - - private static void SetModPackDirectory() - { - if (!Directory.Exists(Properties.Settings.Default.ModPack_Directory)) - { - Directory.CreateDirectory(Properties.Settings.Default.ModPack_Directory); - } - } - /// /// Resolves a valid TexTools desired FFXIV folder from a given user folder, if at all possible. /// diff --git a/FFXIV_TexTools/Views/Textures/EyeDiffuseCreator.xaml.cs b/FFXIV_TexTools/Views/Textures/EyeDiffuseCreator.xaml.cs index ffd602c9..60ad8f6a 100644 --- a/FFXIV_TexTools/Views/Textures/EyeDiffuseCreator.xaml.cs +++ b/FFXIV_TexTools/Views/Textures/EyeDiffuseCreator.xaml.cs @@ -25,6 +25,7 @@ using SixLabors.ImageSharp; using Point = SixLabors.ImageSharp.Point; using xivModdingFramework.Helpers; +using xivModdingFramework.Mods; namespace FFXIV_TexTools.Views.Textures { diff --git a/ForceUpdateAssembly/ForceUpdateAssembly.csproj b/ForceUpdateAssembly/ForceUpdateAssembly.csproj index beb71fe3..5539c433 100644 --- a/ForceUpdateAssembly/ForceUpdateAssembly.csproj +++ b/ForceUpdateAssembly/ForceUpdateAssembly.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -9,7 +9,9 @@ A stub library with version 0.0.0.0 for use when forcing updates. ForceUpdateAssembly Branch Change Update - Debug;Release;Endwalker Debug;Endwalker Release + Debug;Release + ..\\bin\\$(Configuration)\\lib\\ + false diff --git a/lib/xivModdingFramework b/lib/xivModdingFramework index 20825119..0f2faeea 160000 --- a/lib/xivModdingFramework +++ b/lib/xivModdingFramework @@ -1 +1 @@ -Subproject commit 2082511953559dd9e6b0dd0a50fec6146305b1a5 +Subproject commit 0f2faeeae5958aac6ce542bb679c025c4bd15900 From a689f0a49320d8eaef350dab4281954290b650a6 Mon Sep 17 00:00:00 2001 From: Lunaretic Date: Sun, 7 Jul 2024 18:05:54 -0400 Subject: [PATCH 2/7] Adjusting build order --- ConsoleTools/ConsoleTools.csproj | 2 +- FFXIV_TexTools.sln | 3 --- FFXIV_TexTools/FFXIV_TexTools.csproj | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ConsoleTools/ConsoleTools.csproj b/ConsoleTools/ConsoleTools.csproj index 6e7fbb91..68749641 100644 --- a/ConsoleTools/ConsoleTools.csproj +++ b/ConsoleTools/ConsoleTools.csproj @@ -7,7 +7,7 @@ enable ..\\bin\\$(Configuration)\\ false - + echo Moving DLL Files mkdir $(TargetDir)lib diff --git a/FFXIV_TexTools.sln b/FFXIV_TexTools.sln index 1c4dd309..6645e8b7 100644 --- a/FFXIV_TexTools.sln +++ b/FFXIV_TexTools.sln @@ -4,9 +4,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.4.33205.214 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIV_TexTools", "FFXIV_TexTools\FFXIV_TexTools.csproj", "{4A5F7AB1-F296-450B-8F57-2FB82465964E}" - ProjectSection(ProjectDependencies) = postProject - {60DC3C4C-9911-4536-90A7-171C8336ED0A} = {60DC3C4C-9911-4536-90A7-171C8336ED0A} - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xivModdingFramework", "lib\xivModdingFramework\xivModdingFramework\xivModdingFramework.csproj", "{CDC45CC3-60E7-4CB1-A267-BE1CB3BDE340}" EndProject diff --git a/FFXIV_TexTools/FFXIV_TexTools.csproj b/FFXIV_TexTools/FFXIV_TexTools.csproj index cd295911..2657050d 100644 --- a/FFXIV_TexTools/FFXIV_TexTools.csproj +++ b/FFXIV_TexTools/FFXIV_TexTools.csproj @@ -38,7 +38,6 @@ xcopy $(TargetDir)*.dll $(TargetDir)lib /y del *.dll del *.cso - move $(TargetDir)lib\\ConsoleTools.dll $(TargetDir)ConsoleTools.dll Debug;Release From 3368b86146d7a9d1778ce65cad48d51b108cd16c Mon Sep 17 00:00:00 2001 From: Lunaretic Date: Sun, 7 Jul 2024 19:08:02 -0400 Subject: [PATCH 3/7] Change console project to use the same targets as main TT app. --- ConsoleTools/ConsoleTools.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ConsoleTools/ConsoleTools.csproj b/ConsoleTools/ConsoleTools.csproj index 68749641..ba471046 100644 --- a/ConsoleTools/ConsoleTools.csproj +++ b/ConsoleTools/ConsoleTools.csproj @@ -2,7 +2,8 @@ Exe - net8.0 + net48 + 9.0 disable enable ..\\bin\\$(Configuration)\\ @@ -14,7 +15,6 @@ xcopy $(TargetDir)*.dll $(TargetDir)lib /y del *.dll del *.cso - move $(TargetDir)lib\\ConsoleTools.dll $(TargetDir)ConsoleTools.dll From 60950ec501fabcec368f2add6e43e3f03ab3e06e Mon Sep 17 00:00:00 2001 From: Lunaretic Date: Sun, 7 Jul 2024 20:26:15 -0400 Subject: [PATCH 4/7] Console app settings/etc. --- ConsoleTools/App.config | 2 +- ConsoleTools/ConsoleTools.csproj | 7 +- ConsoleTools/Program.cs | 203 ++++++++++++++++++++++++++- FFXIV_TexTools/FFXIV_TexTools.csproj | 9 +- FFXIV_TexTools/MainWindow.xaml.cs | 1 - 5 files changed, 209 insertions(+), 13 deletions(-) diff --git a/ConsoleTools/App.config b/ConsoleTools/App.config index 3c5edad4..95cd819c 100644 --- a/ConsoleTools/App.config +++ b/ConsoleTools/App.config @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/ConsoleTools/ConsoleTools.csproj b/ConsoleTools/ConsoleTools.csproj index ba471046..9cd0ec34 100644 --- a/ConsoleTools/ConsoleTools.csproj +++ b/ConsoleTools/ConsoleTools.csproj @@ -10,9 +10,10 @@ false - echo Moving DLL Files - mkdir $(TargetDir)lib - xcopy $(TargetDir)*.dll $(TargetDir)lib /y + + echo Moving DLL Files + mkdir $(TargetDir)console_lib + xcopy $(TargetDir)*.dll $(TargetDir)console_lib /y del *.dll del *.cso diff --git a/ConsoleTools/Program.cs b/ConsoleTools/Program.cs index c1450a54..5b8cbd01 100644 --- a/ConsoleTools/Program.cs +++ b/ConsoleTools/Program.cs @@ -1,4 +1,5 @@ using HelixToolkit.SharpDX.Core.Utilities; +using SharpDX.WIC; using System; using System.Collections.Generic; using System.Diagnostics; @@ -10,7 +11,13 @@ using System.Threading.Tasks; using System.Windows; using xivModdingFramework.Cache; +using xivModdingFramework.Models.DataContainers; +using xivModdingFramework.Models.FileTypes; using xivModdingFramework.Mods; +using xivModdingFramework.SqPack.FileTypes; +using xivModdingFramework.Textures.DataContainers; +using xivModdingFramework.Textures.FileTypes; +using xivModdingFramework.VFX.FileTypes; namespace ConsoleTools { @@ -20,7 +27,7 @@ public class ConsoleTools public static int Main(string[] args) { // Manual lib loader because the app.config method isn't working for some reason. - var cwd = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "lib"); + var cwd = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "console_lib"); var referenceFiles = Directory.GetFiles(cwd, "*.dll", SearchOption.AllDirectories); AppDomain.CurrentDomain.AssemblyResolve += (obj, arg) => @@ -79,6 +86,22 @@ public static async Task HandleConsoleArgs() { code = await HandleUpgrade(); } + else if(cmd == "/s") + { + code = await HandleResaveModpack(); + } + else if (cmd == "/e") + { + code = await ExtractFile(); + } + else if (cmd == "/wrap") + { + code = await WrapFile(); + } + else if (cmd == "/unwrap") + { + code = await UnwrapFile(); + } else { await ShowHelp(); @@ -113,16 +136,186 @@ public static async Task HandleUpgrade() return 0; } + public static async Task HandleResaveModpack() + { + if (_Args.Length < 4) + { + return -1; + } + + var src = _Args[2]; + var dest = _Args[3]; + System.Console.Write("Resaving Modpack: " + src); + try + { + var data = await WizardData.FromModpack(src); + await data.WriteModpack(dest); + + System.Console.Write("Modpack Saved to: " + dest); + } + catch (Exception ex) + { + Trace.WriteLine(ex); + return -1; + } + return 0; + } + + public static async Task ExtractFile() + { + if (_Args.Length < 4) + { + return -1; + } + + var sqpack = GetFlag("/sqpack"); + var src = _Args[2]; + var dest = _Args[3]; + + var rtx = ModTransaction.BeginReadonlyTransaction(); + if (Path.GetExtension(src).ToLower() == Path.GetExtension(dest).ToLower()) + { + var data = await rtx.ReadFile(src, false, sqpack); + File.WriteAllBytes(dest, data); + return 0; + } + + if (src.EndsWith(".tex") || src.EndsWith(".atex")) + { + var data = await rtx.ReadFile(src); + var tex = XivTex.FromUncompressedTex(data); + await tex.SaveAs(dest); + } + else if (src.EndsWith(".mdl")) + { + await Mdl.ExportMdlToFile(src, dest, 1, null, false, rtx); + } + else + { + var data = await rtx.ReadFile(src); + File.WriteAllBytes(dest, data); + } + + return 0; + } + public static async Task WrapFile() + { + if (_Args.Length < 4) + { + return -1; + } + + var src = _Args[2]; + var dest = _Args[3]; + + // Just dub something in with same extention if we weren't given one. + // This will work for anything other than MDL. + var ffPath = "chara/file" + Path.GetExtension(dest); + if (_Args.Length > 4) + { + ffPath = _Args[4]; + } + Console.WriteLine("Converting File: " + src); + + var sqpack = GetFlag("/sqpack"); + var parsed = new byte[0]; + if (sqpack) + { + parsed = await SmartImport.CreateCompressedFile(src, ffPath); + } else + { + parsed = await SmartImport.CreateUncompressedFile(src, ffPath); + } + + File.WriteAllBytes(dest, parsed); + return 0; + } + + public static async Task UnwrapFile() + { + if (_Args.Length < 4) + { + return -1; + } + + if (_Args.Length < 4) + { + return -1; + } + + var ffPath = ""; + if(_Args.Length > 4) + { + ffPath = _Args[4]; + } + + var src = _Args[2]; + var dest = _Args[3]; + + Console.WriteLine("Unwrapping file: " + src); + var data = File.ReadAllBytes(src); + + using var br = new BinaryReader(new MemoryStream(data)); + var type = Dat.GetSqPackType(br); + + if(type > 1 && type < 4) + { + try + { + Console.WriteLine("Un-Sqpacking file..."); + data = await Dat.ReadSqPackFile(data); + } + catch + { + // If this failed to parse, it may not be SqPacked. + Console.WriteLine("Un-Sqpack failed, continuing with file as-is..."); + } + } + + var rtx = ModTransaction.BeginReadonlyTransaction(); + if (Path.GetExtension(src).ToLower() == Path.GetExtension(dest).ToLower()) + { + File.WriteAllBytes(dest, data); + return 0; + } + + if (src.EndsWith(".tex") || src.EndsWith(".atex")) + { + var tex = XivTex.FromUncompressedTex(data); + await tex.SaveAs(dest); + } + else if (src.EndsWith(".mdl")) + { + var mdl = Mdl.GetXivMdl(data); + var ttm = TTModel.FromRaw(mdl); + ttm.Source = ffPath; + await Mdl.ExportTTModelToFile(ttm, ffPath, 1, null, rtx); + } + else + { + File.WriteAllBytes(dest, data); + } + + return 0; + } + + public static async Task ShowHelp() { System.Console.WriteLine("==== ConsoleTools Help ===="); System.Console.WriteLine(""); System.Console.WriteLine("== Commands =="); System.Console.WriteLine("\t/? - Help => You're looking at it."); - System.Console.WriteLine("\t/u [PathToSource] [PathToDestination] - Updates a given Modpack for Dawntrail."); - System.Console.WriteLine("\t/s [ModpackFilePath] [OutputFilePath] - Saves a given modpack file to a new path or type, after performing basic file processing."); - System.Console.WriteLine("\t/e [FfxivFilePath] [OutputFileName] - Extracts a given file from FFXIV. May be SQPacked with /sqpack"); - System.Console.WriteLine("\t/i [SourceFilePath] [OutputFilePath] - Creates an FFXIV packed file from the given source file. May be SQPacked with /sqpack"); + System.Console.WriteLine(""); + System.Console.WriteLine("\t/u [ModpackFilePath] [DestFilePath] - Updates a given Modpack for Dawntrail."); + System.Console.WriteLine(""); + System.Console.WriteLine("\t/s [ModpackFilePath] [DestFilePath] - Saves a given modpack file to a new path or type, after performing basic file processing."); + System.Console.WriteLine(""); + System.Console.WriteLine("\t/e [FfxivInternalPath] [DestFilePath] - Extracts a given file from FFXIV. May be SQPacked with /sqpack"); + System.Console.WriteLine(""); + System.Console.WriteLine("\t/wrap [SourceFilePath] [DestFilePath] [IntendedFfxivFilePath] - Creates an FFXIV format file from the given source file. May be SQPacked with /sqpack. FF Path only needed for MDLs."); + System.Console.WriteLine(""); + System.Console.WriteLine("\t/unwrap [SourceFilePath] [DestFilePath] [IntendedFfxivFilePath] - Unwraps a given on-disk SqPacked or Flat FFXIV file into the given format. FF Path only needed for MDLs Skeleton/Texture info."); System.Console.WriteLine(""); System.Console.WriteLine("== FORMATS =="); System.Console.WriteLine("\tModpacks may be read or written in .ttmp2, .pmp, or unzipped PMP folder path formats."); diff --git a/FFXIV_TexTools/FFXIV_TexTools.csproj b/FFXIV_TexTools/FFXIV_TexTools.csproj index 2657050d..459dd45f 100644 --- a/FFXIV_TexTools/FFXIV_TexTools.csproj +++ b/FFXIV_TexTools/FFXIV_TexTools.csproj @@ -54,6 +54,12 @@ app.manifest FFXIV_TexTools.App + + + + + + @@ -222,7 +228,4 @@ Designer - - - diff --git a/FFXIV_TexTools/MainWindow.xaml.cs b/FFXIV_TexTools/MainWindow.xaml.cs index 0e77cb62..cfc6703f 100644 --- a/FFXIV_TexTools/MainWindow.xaml.cs +++ b/FFXIV_TexTools/MainWindow.xaml.cs @@ -1822,7 +1822,6 @@ await Task.Run(async () => var res = (FlexibleMessageBox.Show("Successfully downloaded fresh index backups.\nWould you like to delete all mods and apply these backups/[Start Over]?.".L(), "Backup Download Success".L(), MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1)); if (res == System.Windows.Forms.DialogResult.Yes) { - _lockProgressController.SetTitle("Removing All Mods"); Menu_StartOver_Click(null, null); } } From 9450f205f88e1001072a9cef7fb4a88e7e468bc1 Mon Sep 17 00:00:00 2001 From: Lunaretic Date: Sun, 7 Jul 2024 20:39:46 -0400 Subject: [PATCH 5/7] Misc console app work. --- ConsoleTools/Program.cs | 73 ++++++++++++++++++++++------------------- lib/xivModdingFramework | 2 +- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/ConsoleTools/Program.cs b/ConsoleTools/Program.cs index 5b8cbd01..c98b12a8 100644 --- a/ConsoleTools/Program.cs +++ b/ConsoleTools/Program.cs @@ -113,13 +113,13 @@ public static async Task HandleConsoleArgs() public static async Task HandleUpgrade() { - if (_Args.Length < 4) + if (_Args.Length < 3) { return -1; } - var src = _Args[2]; - var dest = _Args[3]; + var src = _Args[1]; + var dest = _Args[2]; System.Console.Write("Upgrading Modpack: " + src); try @@ -138,24 +138,31 @@ public static async Task HandleUpgrade() public static async Task HandleResaveModpack() { - if (_Args.Length < 4) + if (_Args.Length < 3) { + Console.WriteLine("Insufficient argument count for function."); return -1; } - var src = _Args[2]; - var dest = _Args[3]; - System.Console.Write("Resaving Modpack: " + src); + var src = _Args[1]; + var dest = _Args[2]; + System.Console.WriteLine("Loading Modpack: " + src); try { var data = await WizardData.FromModpack(src); + if(data == null) + { + Console.WriteLine("Failed to load Modpack at: " + src); + return -1; + } + await data.WriteModpack(dest); System.Console.Write("Modpack Saved to: " + dest); } catch (Exception ex) { - Trace.WriteLine(ex); + Console.WriteLine(ex); return -1; } return 0; @@ -163,24 +170,24 @@ public static async Task HandleResaveModpack() public static async Task ExtractFile() { - if (_Args.Length < 4) + if (_Args.Length < 3) { + Console.WriteLine("Insufficient argument count for function."); return -1; } var sqpack = GetFlag("/sqpack"); - var src = _Args[2]; - var dest = _Args[3]; + var src = _Args[1]; + var dest = _Args[2]; + + Console.WriteLine("Extracting File: " + src); var rtx = ModTransaction.BeginReadonlyTransaction(); if (Path.GetExtension(src).ToLower() == Path.GetExtension(dest).ToLower()) { var data = await rtx.ReadFile(src, false, sqpack); File.WriteAllBytes(dest, data); - return 0; - } - - if (src.EndsWith(".tex") || src.EndsWith(".atex")) + } else if (src.EndsWith(".tex") || src.EndsWith(".atex")) { var data = await rtx.ReadFile(src); var tex = XivTex.FromUncompressedTex(data); @@ -196,26 +203,28 @@ public static async Task ExtractFile() File.WriteAllBytes(dest, data); } + Console.WriteLine("File saved to:" + dest); return 0; } public static async Task WrapFile() { - if (_Args.Length < 4) + if (_Args.Length < 3) { + Console.WriteLine("Insufficient argument count for function."); return -1; } - var src = _Args[2]; - var dest = _Args[3]; + var src = _Args[1]; + var dest = _Args[2]; // Just dub something in with same extention if we weren't given one. // This will work for anything other than MDL. var ffPath = "chara/file" + Path.GetExtension(dest); - if (_Args.Length > 4) + if (_Args.Length > 3) { - ffPath = _Args[4]; + ffPath = _Args[3]; } - Console.WriteLine("Converting File: " + src); + Console.WriteLine("Wrapping File: " + src); var sqpack = GetFlag("/sqpack"); var parsed = new byte[0]; @@ -228,29 +237,26 @@ public static async Task WrapFile() } File.WriteAllBytes(dest, parsed); + Console.WriteLine("Wrapped File saved to: " + dest); return 0; } public static async Task UnwrapFile() { - if (_Args.Length < 4) - { - return -1; - } - - if (_Args.Length < 4) + if (_Args.Length < 3) { + Console.WriteLine("Insufficient argument count for function."); return -1; } var ffPath = ""; - if(_Args.Length > 4) + if(_Args.Length > 3) { - ffPath = _Args[4]; + ffPath = _Args[3]; } - var src = _Args[2]; - var dest = _Args[3]; + var src = _Args[1]; + var dest = _Args[2]; Console.WriteLine("Unwrapping file: " + src); var data = File.ReadAllBytes(src); @@ -276,10 +282,8 @@ public static async Task UnwrapFile() if (Path.GetExtension(src).ToLower() == Path.GetExtension(dest).ToLower()) { File.WriteAllBytes(dest, data); - return 0; } - - if (src.EndsWith(".tex") || src.EndsWith(".atex")) + else if (src.EndsWith(".tex") || src.EndsWith(".atex")) { var tex = XivTex.FromUncompressedTex(data); await tex.SaveAs(dest); @@ -296,6 +300,7 @@ public static async Task UnwrapFile() File.WriteAllBytes(dest, data); } + Console.WriteLine("Unwrapped File saved to: " + dest); return 0; } diff --git a/lib/xivModdingFramework b/lib/xivModdingFramework index 0f2faeea..71864517 160000 --- a/lib/xivModdingFramework +++ b/lib/xivModdingFramework @@ -1 +1 @@ -Subproject commit 0f2faeeae5958aac6ce542bb679c025c4bd15900 +Subproject commit 71864517d04fac10608966e9a41daf29fcaa46d2 From 13928dba739f1dcf2acd8fc2a20b19a89433ee38 Mon Sep 17 00:00:00 2001 From: Lunaretic Date: Sun, 7 Jul 2024 20:49:55 -0400 Subject: [PATCH 6/7] bump and change a folder name. --- ConsoleTools/App.config | 2 +- ConsoleTools/ConsoleTools.csproj | 4 ++-- ConsoleTools/Program.cs | 14 +++++++------- FFXIV_TexTools/FFXIV_TexTools.csproj | 6 +++--- FFXIV_TexTools/Views/OnboardingWindow.xaml.cs | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ConsoleTools/App.config b/ConsoleTools/App.config index 95cd819c..86880fb0 100644 --- a/ConsoleTools/App.config +++ b/ConsoleTools/App.config @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/ConsoleTools/ConsoleTools.csproj b/ConsoleTools/ConsoleTools.csproj index 9cd0ec34..baf889fe 100644 --- a/ConsoleTools/ConsoleTools.csproj +++ b/ConsoleTools/ConsoleTools.csproj @@ -12,8 +12,8 @@ echo Moving DLL Files - mkdir $(TargetDir)console_lib - xcopy $(TargetDir)*.dll $(TargetDir)console_lib /y + mkdir $(TargetDir)lib_console + xcopy $(TargetDir)*.dll $(TargetDir)lib_console /y del *.dll del *.cso diff --git a/ConsoleTools/Program.cs b/ConsoleTools/Program.cs index c98b12a8..6d0d8e49 100644 --- a/ConsoleTools/Program.cs +++ b/ConsoleTools/Program.cs @@ -27,7 +27,7 @@ public class ConsoleTools public static int Main(string[] args) { // Manual lib loader because the app.config method isn't working for some reason. - var cwd = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "console_lib"); + var cwd = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "lib_console"); var referenceFiles = Directory.GetFiles(cwd, "*.dll", SearchOption.AllDirectories); AppDomain.CurrentDomain.AssemblyResolve += (obj, arg) => @@ -82,15 +82,15 @@ public static async Task HandleConsoleArgs() { code = await ShowHelp(); } - else if (cmd == "/u") + else if (cmd == "/upgrade") { code = await HandleUpgrade(); } - else if(cmd == "/s") + else if(cmd == "/resave") { code = await HandleResaveModpack(); } - else if (cmd == "/e") + else if (cmd == "/extract") { code = await ExtractFile(); } @@ -312,11 +312,11 @@ public static async Task ShowHelp() System.Console.WriteLine("== Commands =="); System.Console.WriteLine("\t/? - Help => You're looking at it."); System.Console.WriteLine(""); - System.Console.WriteLine("\t/u [ModpackFilePath] [DestFilePath] - Updates a given Modpack for Dawntrail."); + System.Console.WriteLine("\t/upgrade [ModpackFilePath] [DestFilePath] - Updates a given Modpack for Dawntrail."); System.Console.WriteLine(""); - System.Console.WriteLine("\t/s [ModpackFilePath] [DestFilePath] - Saves a given modpack file to a new path or type, after performing basic file processing."); + System.Console.WriteLine("\t/resave [ModpackFilePath] [DestFilePath] - Re-Saves a given modpack file to a new path or type, after performing basic file processing."); System.Console.WriteLine(""); - System.Console.WriteLine("\t/e [FfxivInternalPath] [DestFilePath] - Extracts a given file from FFXIV. May be SQPacked with /sqpack"); + System.Console.WriteLine("\t/extract [FfxivInternalPath] [DestFilePath] - Extracts a given file from FFXIV. May be SQPacked with /sqpack"); System.Console.WriteLine(""); System.Console.WriteLine("\t/wrap [SourceFilePath] [DestFilePath] [IntendedFfxivFilePath] - Creates an FFXIV format file from the given source file. May be SQPacked with /sqpack. FF Path only needed for MDLs."); System.Console.WriteLine(""); diff --git a/FFXIV_TexTools/FFXIV_TexTools.csproj b/FFXIV_TexTools/FFXIV_TexTools.csproj index 459dd45f..dab26419 100644 --- a/FFXIV_TexTools/FFXIV_TexTools.csproj +++ b/FFXIV_TexTools/FFXIV_TexTools.csproj @@ -23,9 +23,9 @@ FFXIV_TexTools Copyright © 2024 - 3.0.3.2 - 3.0.3.2 - 3.0.3.2 + 3.0.3.3 + 3.0.3.3 + 3.0.3.3 9.0 true diff --git a/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs b/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs index 2e50f732..0c7beec0 100644 --- a/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs +++ b/FFXIV_TexTools/Views/OnboardingWindow.xaml.cs @@ -166,7 +166,7 @@ private void Done_Click(object sender, RoutedEventArgs e) Settings.Default.Save(); DialogResult = true; - System.Windows.Forms.Application.Restart(); + MainWindow.GetMainWindow().Restart(); System.Windows.Application.Current.Shutdown(); } From fe49ff65e4905a0b378b7332260b51ddc890b797 Mon Sep 17 00:00:00 2001 From: Lunaretic Date: Sun, 7 Jul 2024 20:54:10 -0400 Subject: [PATCH 7/7] Update Framework Reference to Update v3.0.3.3 --- lib/xivModdingFramework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/xivModdingFramework b/lib/xivModdingFramework index 71864517..9b3d171c 160000 --- a/lib/xivModdingFramework +++ b/lib/xivModdingFramework @@ -1 +1 @@ -Subproject commit 71864517d04fac10608966e9a41daf29fcaa46d2 +Subproject commit 9b3d171cf9af54403126255fc903eca174dd4bd1