diff --git a/FFXIV_TexTools/FFXIV_TexTools.csproj b/FFXIV_TexTools/FFXIV_TexTools.csproj
index 8a9fe959..61719d34 100644
--- a/FFXIV_TexTools/FFXIV_TexTools.csproj
+++ b/FFXIV_TexTools/FFXIV_TexTools.csproj
@@ -23,8 +23,8 @@
FFXIV_TexTools
FFXIV_TexTools
Copyright © 2024
- 3.0.1.5
- 3.0.1.5
+ 3.0.1.6
+ 3.0.1.6
9.0
bin\$(Configuration)\
true
diff --git a/FFXIV_TexTools/ViewModels/ModListViewModel.cs b/FFXIV_TexTools/ViewModels/ModListViewModel.cs
index d57cf1f8..68b284fa 100644
--- a/FFXIV_TexTools/ViewModels/ModListViewModel.cs
+++ b/FFXIV_TexTools/ViewModels/ModListViewModel.cs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+using FFXIV_TexTools.Annotations;
using FFXIV_TexTools.Helpers;
using FFXIV_TexTools.Models;
using FFXIV_TexTools.Resources;
@@ -37,6 +38,7 @@
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
+using System.Windows.Threading;
using xivModdingFramework.Cache;
using xivModdingFramework.General.Enums;
using xivModdingFramework.Helpers;
@@ -49,6 +51,8 @@
using xivModdingFramework.Textures.DataContainers;
using xivModdingFramework.Textures.Enums;
using xivModdingFramework.Textures.FileTypes;
+using static FFXIV_TexTools.ViewModels.ModListViewModel;
+using static System.Windows.Forms.AxHost;
using Application = System.Windows.Application;
namespace FFXIV_TexTools.ViewModels
@@ -427,266 +431,289 @@ public async Task UpdateList(Category category, CancellationTokenSource cts)
ProgressValue = 0;
ProgressText = string.Empty;
- await Task.Run(async () =>
- {
- var tx = MainWindow.DefaultTransaction;
- var selectedItem = category.Item as IItem;
- if (selectedItem == null) return;
+ var tx = MainWindow.DefaultTransaction;
+ var selectedItem = category.Item as IItem;
+ if (selectedItem == null) return;
- var modList = await tx.GetModList();
+ var modList = await tx.GetModList();
- var modItems = new List();
+ var modItems = new List();
- var allMods = modList.GetMods(x => !x.IsInternal());
- if (ModPackFilter)
+ var allMods = modList.GetMods(x => !x.IsInternal());
+ if (ModPackFilter)
+ {
+ var modPackCategory = category;
+
+ while (!modPackCategory.ParentCategory.Name.Equals("ModPacks"))
+ {
+ modPackCategory = modPackCategory.ParentCategory;
+ }
+
+ foreach (var mod in allMods)
{
- var modPackCategory = category;
+ if (!mod.ItemName.Equals(category.Name)) continue;
- while (!modPackCategory.ParentCategory.Name.Equals("ModPacks"))
+ if (mod.ModPack == modPackCategory.Name)
{
- modPackCategory = modPackCategory.ParentCategory;
+ modItems.Add(mod);
}
-
- foreach (var mod in allMods)
+ else
{
- if (!mod.ItemName.Equals(category.Name)) continue;
-
- if (mod.ModPack == modPackCategory.Name)
- {
- modItems.Add(mod);
- }
- else
- {
- modItems.Add(mod);
- }
+ modItems.Add(mod);
}
}
- else
+ }
+ else
+ {
+ var itemNames = allMods.Select(x => x.ItemName).ToArray();
+ modItems =
+ (from mod in allMods
+ where mod.ItemName.Equals(category.Name)
+ select mod).ToList();
+ }
+
+ var modNum = 0;
+
+ foreach (var modItem in modItems)
+ {
+
+ var itemPath = modItem.FilePath;
+
+ var modListModel = new ModListModel
{
- var itemNames = allMods.Select(x => x.ItemName).ToArray();
- modItems =
- (from mod in allMods
- where mod.ItemName.Equals(category.Name)
- select mod).ToList();
+ ModItem = modItem
+ };
+
+ string parent = null;
+ if(_modListParents.ContainsKey(modItem.FilePath) && _modListParents[modItem.FilePath] != null && _modListParents[modItem.FilePath].Count > 0)
+ {
+ parent = _modListParents[modItem.FilePath][0];
}
- var modNum = 0;
+ var suffix = "";
+ try
+ {
+ suffix = Path.GetExtension(modItem.FilePath).Substring(1);
+ }
+ catch
+ {
+ // No-op.
+ }
- await Task.Run(async () =>
+ // Race
+ modListModel.ItemName = ModViewHelpers.GetFancyName(modItem.ItemName, modItem.FilePath);
+
+ // File Name
+ modListModel.FileName = Path.GetFileName(modItem.FilePath);
+ modListModel.FilePath = modItem.FilePath;
+
+ // Type
+ modListModel.Type = ModViewHelpers.GetType(modItem.FilePath);
+
+ // Material
+ if (suffix == "tex" && parent != null)
{
- foreach (var modItem in modItems)
- {
+ modListModel.Material = ModViewHelpers.GetMaterialId(parent);
+ }
+ else
+ {
+ modListModel.Material = ModViewHelpers.GetMaterialId(modItem.FilePath);
+ }
- var itemPath = modItem.FilePath;
+ // Race
+ if (suffix == "tex" && parent != null)
+ {
+ modListModel.Race = ModViewHelpers.GetRace(parent).GetDisplayName();
+ }
+ else
+ {
+ modListModel.Race = ModViewHelpers.GetRace(modItem.FilePath).GetDisplayName();
+ }
- var modListModel = new ModListModel
- {
- ModItem = modItem
- };
+ ModListPreviewList.Add(modListModel);
+ var mod = modItem;
- string parent = null;
- if(_modListParents.ContainsKey(modItem.FilePath) && _modListParents[modItem.FilePath] != null && _modListParents[modItem.FilePath].Count > 0)
- {
- parent = _modListParents[modItem.FilePath][0];
- }
+ // Preload this so we don't potentially cause multi-load collisions.
+ await tx.GetIndexFile(mod.DataFile);
- var suffix = "";
- try
- {
- suffix = Path.GetExtension(modItem.FilePath).Substring(1);
- }
- catch
- {
- // No-op.
- }
+ _ = Task.Run(async () =>
+ {
+ List tasks = new List();
+ tasks.Add(UpdateModState(modListModel, mod, tx));
+ tasks.Add(UpdateModImage(modListModel, mod, tx));
- // Race
- modListModel.ItemName = ModViewHelpers.GetFancyName(modItem.ItemName, modItem.FilePath);
+ await Task.WhenAll(tasks);
+ });
+ }
+ }
- // File Name
- modListModel.FileName = Path.GetFileName(modItem.FilePath);
- modListModel.FilePath = modItem.FilePath;
+ private async Task UpdateModState(ModListModel mlm, Mod m, ModTransaction tx)
+ {
+ var state = await m.GetState(tx);
+ await Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ if (state == EModState.Enabled)
+ {
+ mlm.ActiveBorder = Brushes.Green;
+ mlm.Active = Brushes.Transparent;
+ mlm.ActiveOpacity = 1;
+ }
+ else
+ {
+ mlm.ActiveBorder = Brushes.Red;
+ mlm.Active = Brushes.Gray;
+ mlm.ActiveOpacity = 0.5f;
+ }
+ });
+ }
- // Type
- modListModel.Type = ModViewHelpers.GetType(modItem.FilePath);
+ private async Task UpdateModImage(ModListModel mlm, Mod m, ModTransaction tx)
+ {
+ var img = await GetModImage(m, tx);
+ await Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ mlm.Image = img;
+ });
+ }
- // Material
- if (suffix == "tex" && parent != null)
- {
- modListModel.Material = ModViewHelpers.GetMaterialId(parent);
- }
- else
- {
- modListModel.Material = ModViewHelpers.GetMaterialId(modItem.FilePath);
- }
+ private async Task GetModImage(Mod m, ModTransaction tx)
+ {
- // Race
- if (suffix == "tex" && parent != null)
- {
- modListModel.Race = ModViewHelpers.GetRace(parent).GetDisplayName();
- }
- else
+ // Added files which are currently disabled cannot be previewed, as their index file entries don't exist.
+ // (???) The above comment is wrong. The data still exists in the Dats, and we have the offset in the modlist file...
+ var state = await m.GetState(tx);
+ var itemPath = m.FilePath;
+ if (!(m.OriginalOffset8x == m.ModOffset8x && state != EModState.Enabled))
+ {
+ // Image
+ if (itemPath.Contains(".mtrl"))
+ {
+ try
+ {
+ var mtrlData = await Mtrl.GetXivMtrl(m.FilePath, false, tx);
+ if (mtrlData != null)
{
- modListModel.Race = ModViewHelpers.GetRace(modItem.FilePath).GetDisplayName();
- }
+ var floats = Half.ConvertToFloat(mtrlData.ColorSetData.ToArray());
- // Added files which are currently disabled cannot be previewed, as their index file entries don't exist.
- // (???) The above comment is wrong. The data still exists in the Dats, and we have the offset in the modlist file...
- var state = await modItem.GetState(tx);
- if (!(modItem.OriginalOffset8x == modItem.ModOffset8x && state != EModState.Enabled))
- {
- // Image
- if (itemPath.Contains(".mtrl"))
+ var floatArray = Utilities.ToByteArray(floats);
+
+ if (floatArray.Length > 0)
{
- try
+ var w = 4;
+ var h = 16;
+
+ if (floatArray.Length >= 1024)
{
- var mtrlData = await Mtrl.GetXivMtrl(modItem.FilePath, false, tx);
- if (mtrlData != null)
- {
+ w = 8;
+ h = 32;
+ }
- var floats = Half.ConvertToFloat(mtrlData.ColorSetData.ToArray());
+ using (var img = Image.LoadPixelData(floatArray, w, h))
+ {
+ img.Mutate(x => x.Opacity(1));
- var floatArray = Utilities.ToByteArray(floats);
- if (floatArray.Length > 0)
+ using (var ms = new MemoryStream())
+ {
+ img.Save(ms, new BmpEncoder());
+
+ // Have to create the BMP on the main thread, for reasons.
+ return await Application.Current.Dispatcher.InvokeAsync(() =>
{
- var w = 4;
- var h = 16;
-
- if(floatArray.Length >= 1024)
- {
- w = 8;
- h = 32;
- }
-
- using (var img = Image.LoadPixelData(floatArray, w, h))
- {
- img.Mutate(x => x.Opacity(1));
-
- BitmapImage bmp;
-
- using (var ms = new MemoryStream())
- {
- img.Save(ms, new BmpEncoder());
-
- bmp = new BitmapImage();
- bmp.BeginInit();
- bmp.StreamSource = ms;
- bmp.CacheOption = BitmapCacheOption.OnLoad;
- bmp.EndInit();
- bmp.Freeze();
- }
-
- modListModel.Image =
- Application.Current.Dispatcher.Invoke(() => bmp);
- }
- }
+ BitmapImage bmp = null;
+ bmp = new BitmapImage();
+ bmp.BeginInit();
+ bmp.StreamSource = ms;
+ bmp.CacheOption = BitmapCacheOption.OnLoad;
+ bmp.EndInit();
+ bmp.Freeze();
+ return bmp;
+ });
}
}
- catch (Exception ex)
- {
- // User doesn't need to be bombarded with error messages if something is broken here.
- /*FlexibleMessageBox.Show(
- string.Format(UIMessages.MaterialFileReadErrorMessage, modItem.FilePath,
- ex.Message),
- UIMessages.MaterialDataReadErrorTitle,
- MessageBoxButtons.OK, MessageBoxIcon.Error);*/
- }
-
- }
- else if (itemPath.Contains(".mdl"))
- {
- modListModel.Image = Application.Current.Dispatcher.Invoke(() => new BitmapImage(
- new Uri("pack://application:,,,/FFXIV_TexTools;component/Resources/3DModel.png")));
}
- else if (itemPath.Contains(".imc") || itemPath.Contains(".eqp") || itemPath.Contains(".eqdp") || itemPath.Contains(".meta"))
- {
- modListModel.Image = Application.Current.Dispatcher.Invoke(() => new BitmapImage(
- new Uri("pack://application:,,,/FFXIV_TexTools;component/Resources/Metadata.png")));
- }
- else if(itemPath.Contains(".tex"))
- {
- var ttp = new TexTypePath
- {
- Type = XivTexType.Diffuse,
- DataFile = modItem.DataFile,
- Path = modItem.FilePath
- };
+ }
+ }
+ catch (Exception ex)
+ {
+ // User doesn't need to be bombarded with error messages if something is broken here.
+ /*FlexibleMessageBox.Show(
+ string.Format(UIMessages.MaterialFileReadErrorMessage, modItem.FilePath,
+ ex.Message),
+ UIMessages.MaterialDataReadErrorTitle,
+ MessageBoxButtons.OK, MessageBoxIcon.Error);*/
+ }
- XivTex texData;
- try
- {
- if(await tx.FileExists(modItem.FilePath))
- {
+ }
+ else if (itemPath.Contains(".mdl"))
+ {
- texData = await Tex.GetXivTex(modItem.FilePath, false, tx);
+ // Have to create the BMP on the main thread, for reasons.
+ return await Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ return new BitmapImage(new Uri("pack://application:,,,/FFXIV_TexTools;component/Resources/3DModel.png"));
+ });
+ }
+ else if (itemPath.Contains(".imc") || itemPath.Contains(".eqp") || itemPath.Contains(".eqdp") || itemPath.Contains(".meta"))
+ {
+ // Have to create the BMP on the main thread, for reasons.
+ return await Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ return new BitmapImage(new Uri("pack://application:,,,/FFXIV_TexTools;component/Resources/Metadata.png"));
+ });
+ }
+ else if (itemPath.Contains(".tex"))
+ {
- var mapBytes = await texData.GetRawPixels();
+ XivTex texData;
+ try
+ {
+ if (await tx.FileExists(m.FilePath))
+ {
- using (var img = Image.LoadPixelData(mapBytes, texData.Width, texData.Height))
- {
- img.Mutate(x => x.Opacity(1));
+ texData = await Tex.GetXivTex(m.FilePath, false, tx);
- BitmapImage bmp;
+ var mapBytes = await texData.GetRawPixels();
- using (var ms = new MemoryStream())
- {
- img.Save(ms, new BmpEncoder());
+ using (var img = Image.LoadPixelData(mapBytes, texData.Width, texData.Height))
+ {
+ img.Mutate(x => x.Opacity(1));
- bmp = new BitmapImage();
- bmp.BeginInit();
- bmp.StreamSource = ms;
- bmp.CacheOption = BitmapCacheOption.OnLoad;
- bmp.EndInit();
- bmp.Freeze();
- }
- modListModel.Image =
- Application.Current.Dispatcher.Invoke(() => bmp);
- }
- }
- }
- catch (Exception ex)
+ using (var ms = new MemoryStream())
{
- /*
- FlexibleMessageBox.Show(
- string.Format(UIMessages.TextureFileReadErrorMessage, ttp.Path, ex.Message),
- UIMessages.TextureDataReadErrorTitle,
- MessageBoxButtons.OK, MessageBoxIcon.Error);*/
+ img.Save(ms, new BmpEncoder());
+
+ // Have to create the BMP on the main thread, for reasons.
+ return await Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ BitmapImage bmp = null;
+ bmp = new BitmapImage();
+ bmp.BeginInit();
+ bmp.StreamSource = ms;
+ bmp.CacheOption = BitmapCacheOption.OnLoad;
+ bmp.EndInit();
+ bmp.Freeze();
+
+ return bmp;
+ });
}
}
-
- }
-
- // Status
- if (state == EModState.Enabled)
- {
- modListModel.ActiveBorder = Brushes.Green;
- modListModel.Active = Brushes.Transparent;
- modListModel.ActiveOpacity = 1;
- }
- else
- {
- modListModel.ActiveBorder = Brushes.Red;
- modListModel.Active = Brushes.Gray;
- modListModel.ActiveOpacity = 0.5f;
- }
-
- cts.Token.ThrowIfCancellationRequested();
-
- lock (updateLock)
- {
- progress.Report((++modNum, modItems.Count));
- }
-
- if (!cts.IsCancellationRequested)
- {
- Application.Current.Dispatcher.Invoke(() => ModListPreviewList.Add(modListModel));
}
}
- }, cts.Token);
- }, cts.Token);
+ catch (Exception ex)
+ {
+ /*
+ FlexibleMessageBox.Show(
+ string.Format(UIMessages.TextureFileReadErrorMessage, ttp.Path, ex.Message),
+ UIMessages.TextureDataReadErrorTitle,
+ MessageBoxButtons.OK, MessageBoxIcon.Error);*/
+ }
+ }
+ }
+ return null;
+
}
///
@@ -1170,10 +1197,22 @@ public SolidColorBrush ActiveBorder
///
public Mod ModItem { get; set; }
+
+ private ImageSource _Image;
+
///
/// The image of the modded item
///
- public BitmapSource Image { get; set; }
+ public ImageSource Image
+ {
+ get => _Image;
+
+ set
+ {
+ _Image = value;
+ OnPropertyChanged(nameof(Image));
+ }
+ }
public event PropertyChangedEventHandler PropertyChanged;
@@ -1183,14 +1222,5 @@ protected virtual void OnPropertyChanged(string propertyName)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
-
- ///
- /// Gets the language for the application
- ///
- /// The application language as XivLanguage
- private static XivLanguage GetLanguage()
- {
- return XivLanguages.GetXivLanguage(Properties.Settings.Default.Application_Language);
- }
}
}
\ No newline at end of file
diff --git a/FFXIV_TexTools/Views/ModListView.xaml b/FFXIV_TexTools/Views/ModListView.xaml
index b3b7dff5..94af72e5 100644
--- a/FFXIV_TexTools/Views/ModListView.xaml
+++ b/FFXIV_TexTools/Views/ModListView.xaml
@@ -63,14 +63,14 @@
-
-
-
-
-
+
+
+
-
+
@@ -86,66 +86,54 @@
-
+
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditors/ImcManipulationEditor.xaml.cs b/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditors/ImcManipulationEditor.xaml.cs
index e50d4721..6bfdadf8 100644
--- a/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditors/ImcManipulationEditor.xaml.cs
+++ b/FFXIV_TexTools/Views/ModPack/Wizard/ManipulationEditors/ImcManipulationEditor.xaml.cs
@@ -59,7 +59,8 @@ public XivDependencyRoot Root
{
if (value == null) return;
var id = PmpIdentifierJson.FromRoot(value.Info);
-
+
+ Manipulation.ObjectType = PMPExtensions.XivItemTypeToPenumbraObject[value.Info.PrimaryType];
Manipulation.EquipSlot = id.EquipSlot;
Manipulation.BodySlot = id.BodySlot;
Manipulation.PrimaryId = id.PrimaryId;
diff --git a/lib/xivModdingFramework b/lib/xivModdingFramework
index cf094e32..832314a3 160000
--- a/lib/xivModdingFramework
+++ b/lib/xivModdingFramework
@@ -1 +1 @@
-Subproject commit cf094e32668aa5a570280dc22fa3181d1d0b92cc
+Subproject commit 832314a3a63f3b1269f3c523ee77389b2fa8ae70