Move TexTools around.

This commit is contained in:
Ottermandias 2023-03-23 21:43:40 +01:00
parent f38a252295
commit 174e640c45
19 changed files with 212 additions and 228 deletions

View file

@ -9,7 +9,7 @@ using OtterGui.Classes;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Import; using Penumbra.Import.Structs;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI; using Penumbra.UI;

View file

@ -1,122 +0,0 @@
using Penumbra.GameData.Enums;
using System.Text.RegularExpressions;
using Penumbra.GameData;
namespace Penumbra.Import;
// Obtain information what type of object is manipulated
// by the given .meta file from TexTools, using its name.
public class MetaFileInfo
{
private const string Pt = @"(?'PrimaryType'[a-z]*)"; // language=regex
private const string Pp = @"(?'PrimaryPrefix'[a-z])"; // language=regex
private const string Pi = @"(?'PrimaryId'\d{4})"; // language=regex
private const string Pir = @"\k'PrimaryId'"; // language=regex
private const string St = @"(?'SecondaryType'[a-z]*)"; // language=regex
private const string Sp = @"(?'SecondaryPrefix'[a-z])"; // language=regex
private const string Si = @"(?'SecondaryId'\d{4})"; // language=regex
private const string File = @"\k'PrimaryPrefix'\k'PrimaryId'(\k'SecondaryPrefix'\k'SecondaryId')?"; // language=regex
private const string Slot = @"(_(?'Slot'[a-z]{3}))?"; // language=regex
private const string Ext = @"\.meta";
// These are the valid regexes for .meta files that we are able to support at the moment.
private static readonly Regex HousingMeta = new($"bgcommon/hou/{Pt}/general/{Pi}/{Pir}{Ext}", RegexOptions.Compiled);
private static readonly Regex CharaMeta = new($"chara/{Pt}/{Pp}{Pi}(/obj/{St}/{Sp}{Si})?/{File}{Slot}{Ext}", RegexOptions.Compiled);
public readonly ObjectType PrimaryType;
public readonly BodySlot SecondaryType;
public readonly ushort PrimaryId;
public readonly ushort SecondaryId;
public readonly EquipSlot EquipSlot = EquipSlot.Unknown;
public readonly CustomizationType CustomizationType = CustomizationType.Unknown;
private static bool ValidType( ObjectType type )
{
return type switch
{
ObjectType.Accessory => true,
ObjectType.Character => true,
ObjectType.Equipment => true,
ObjectType.DemiHuman => true,
ObjectType.Housing => true,
ObjectType.Monster => true,
ObjectType.Weapon => true,
ObjectType.Icon => false,
ObjectType.Font => false,
ObjectType.Interface => false,
ObjectType.LoadingScreen => false,
ObjectType.Map => false,
ObjectType.Vfx => false,
ObjectType.Unknown => false,
ObjectType.World => false,
_ => false,
};
}
public MetaFileInfo( IGamePathParser parser, string fileName )
{
// Set the primary type from the gamePath start.
PrimaryType = parser.PathToObjectType( fileName );
PrimaryId = 0;
SecondaryType = BodySlot.Unknown;
SecondaryId = 0;
// Not all types of objects can have valid meta data manipulation.
if( !ValidType( PrimaryType ) )
{
PrimaryType = ObjectType.Unknown;
return;
}
// Housing files have a separate regex that just contains the primary id.
if( PrimaryType == ObjectType.Housing )
{
var housingMatch = HousingMeta.Match( fileName );
if( housingMatch.Success )
{
PrimaryId = ushort.Parse( housingMatch.Groups[ "PrimaryId" ].Value );
}
return;
}
// Non-housing is in chara/.
var match = CharaMeta.Match( fileName );
if( !match.Success )
{
return;
}
// The primary ID has to be available for every object.
PrimaryId = ushort.Parse( match.Groups[ "PrimaryId" ].Value );
// Depending on slot, we can set equip slot or customization type.
if( match.Groups[ "Slot" ].Success )
{
switch( PrimaryType )
{
case ObjectType.Equipment:
case ObjectType.Accessory:
if( Names.SuffixToEquipSlot.TryGetValue( match.Groups[ "Slot" ].Value, out var tmpSlot ) )
{
EquipSlot = tmpSlot;
}
break;
case ObjectType.Character:
if( Names.SuffixToCustomizationType.TryGetValue( match.Groups[ "Slot" ].Value, out var tmpCustom ) )
{
CustomizationType = tmpCustom;
}
break;
}
}
// Secondary type and secondary id are for weapons and demihumans.
if( match.Groups[ "SecondaryType" ].Success
&& Names.StringToBodySlot.TryGetValue( match.Groups[ "SecondaryType" ].Value, out SecondaryType ) )
{
SecondaryId = ushort.Parse( match.Groups[ "SecondaryId" ].Value );
}
}
}

View file

@ -1,4 +1,4 @@
namespace Penumbra.Import; namespace Penumbra.Import.Structs;
public enum ImporterState public enum ImporterState
{ {

View file

@ -0,0 +1,104 @@
using Penumbra.GameData.Enums;
using System.Text.RegularExpressions;
using Penumbra.GameData;
namespace Penumbra.Import.Structs;
/// <summary>
/// Obtain information what type of object is manipulated
/// by the given .meta file from TexTools, using its name.
/// </summary>
public partial struct MetaFileInfo
{
// These are the valid regexes for .meta files that we are able to support at the moment.
[GeneratedRegex(@"bgcommon/hou/(?'Type1'[a-z]*)/general/(?'Id1'\d{4})/\k'Id1'\.meta",
RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.NonBacktracking)]
private static partial Regex HousingMeta();
[GeneratedRegex(
@"chara/(?'Type1'[a-z]*)/(?'Pre1'[a-z])(?'Id1'\d{4})(/obj/(?'Type2'[a-z]*)/(?'Pre2'[a-z])(?'Id2'\d{4}))?/\k'Pre1'\k'Id1'(\k'Pre2'\k'Id2')?(_(?'Slot'[a-z]{3}))?\\.meta",
RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.NonBacktracking)]
private static partial Regex CharaMeta();
public readonly ObjectType PrimaryType;
public readonly BodySlot SecondaryType;
public readonly ushort PrimaryId;
public readonly ushort SecondaryId;
public readonly EquipSlot EquipSlot = EquipSlot.Unknown;
public readonly CustomizationType CustomizationType = CustomizationType.Unknown;
private static bool ValidType(ObjectType type)
=> type switch
{
ObjectType.Accessory => true,
ObjectType.Character => true,
ObjectType.Equipment => true,
ObjectType.DemiHuman => true,
ObjectType.Housing => true,
ObjectType.Monster => true,
ObjectType.Weapon => true,
ObjectType.Icon => false,
ObjectType.Font => false,
ObjectType.Interface => false,
ObjectType.LoadingScreen => false,
ObjectType.Map => false,
ObjectType.Vfx => false,
ObjectType.Unknown => false,
ObjectType.World => false,
_ => false,
};
public MetaFileInfo(IGamePathParser parser, string fileName)
{
// Set the primary type from the gamePath start.
PrimaryType = parser.PathToObjectType(fileName);
PrimaryId = 0;
SecondaryType = BodySlot.Unknown;
SecondaryId = 0;
// Not all types of objects can have valid meta data manipulation.
if (!ValidType(PrimaryType))
{
PrimaryType = ObjectType.Unknown;
return;
}
// Housing files have a separate regex that just contains the primary id.
if (PrimaryType == ObjectType.Housing)
{
var housingMatch = HousingMeta().Match(fileName);
if (housingMatch.Success)
PrimaryId = ushort.Parse(housingMatch.Groups["Id1"].Value);
return;
}
// Non-housing is in chara/.
var match = CharaMeta().Match(fileName);
if (!match.Success)
return;
// The primary ID has to be available for every object.
PrimaryId = ushort.Parse(match.Groups["Id1"].Value);
// Depending on slot, we can set equip slot or customization type.
if (match.Groups["Slot"].Success)
switch (PrimaryType)
{
case ObjectType.Equipment:
case ObjectType.Accessory:
if (Names.SuffixToEquipSlot.TryGetValue(match.Groups["Slot"].Value, out var tmpSlot))
EquipSlot = tmpSlot;
break;
case ObjectType.Character:
if (Names.SuffixToCustomizationType.TryGetValue(match.Groups["Slot"].Value, out var tmpCustom))
CustomizationType = tmpCustom;
break;
}
// Secondary type and secondary id are for weapons and demihumans.
if (match.Groups["Type2"].Success && Names.StringToBodySlot.TryGetValue(match.Groups["Type2"].Value, out SecondaryType))
SecondaryId = ushort.Parse(match.Groups["Id2"].Value);
}
}

View file

@ -2,15 +2,15 @@ using Penumbra.Util;
using System; using System;
using System.IO; using System.IO;
namespace Penumbra.Import; namespace Penumbra.Import.Structs;
// Create an automatically disposing SqPack stream. // Create an automatically disposing SqPack stream.
public class StreamDisposer : PenumbraSqPackStream, IDisposable public class StreamDisposer : PenumbraSqPackStream, IDisposable
{ {
private readonly FileStream _fileStream; private readonly FileStream _fileStream;
public StreamDisposer( FileStream stream ) public StreamDisposer(FileStream stream)
: base( stream ) : base(stream)
=> _fileStream = stream; => _fileStream = stream;
public new void Dispose() public new void Dispose()
@ -20,6 +20,6 @@ public class StreamDisposer : PenumbraSqPackStream, IDisposable
base.Dispose(); base.Dispose();
_fileStream.Dispose(); _fileStream.Dispose();
File.Delete( filePath ); File.Delete(filePath);
} }
} }

View file

@ -1,7 +1,7 @@
using System; using System;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
namespace Penumbra.Import; namespace Penumbra.Import.Structs;
internal static class DefaultTexToolsData internal static class DefaultTexToolsData
{ {
@ -27,7 +27,7 @@ internal class SimpleMod
internal class ModPackPage internal class ModPackPage
{ {
public int PageIndex = 0; public int PageIndex = 0;
public ModGroup[] ModGroups = Array.Empty< ModGroup >(); public ModGroup[] ModGroups = Array.Empty<ModGroup>();
} }
[Serializable] [Serializable]
@ -35,7 +35,7 @@ internal class ModGroup
{ {
public string GroupName = string.Empty; public string GroupName = string.Empty;
public GroupType SelectionType = GroupType.Single; public GroupType SelectionType = GroupType.Single;
public OptionList[] OptionList = Array.Empty< OptionList >(); public OptionList[] OptionList = Array.Empty<OptionList>();
public string Description = string.Empty; public string Description = string.Empty;
} }
@ -45,7 +45,7 @@ internal class OptionList
public string Name = string.Empty; public string Name = string.Empty;
public string Description = string.Empty; public string Description = string.Empty;
public string ImagePath = string.Empty; public string ImagePath = string.Empty;
public SimpleMod[] ModsJsons = Array.Empty< SimpleMod >(); public SimpleMod[] ModsJsons = Array.Empty<SimpleMod>();
public string GroupName = string.Empty; public string GroupName = string.Empty;
public GroupType SelectionType = GroupType.Single; public GroupType SelectionType = GroupType.Single;
public bool IsChecked = false; public bool IsChecked = false;
@ -60,18 +60,18 @@ internal class ExtendedModPack
public string Version = string.Empty; public string Version = string.Empty;
public string Description = DefaultTexToolsData.Description; public string Description = DefaultTexToolsData.Description;
public string Url = string.Empty; public string Url = string.Empty;
public ModPackPage[] ModPackPages = Array.Empty< ModPackPage >(); public ModPackPage[] ModPackPages = Array.Empty<ModPackPage>();
public SimpleMod[] SimpleModsList = Array.Empty< SimpleMod >(); public SimpleMod[] SimpleModsList = Array.Empty<SimpleMod>();
} }
[Serializable] [Serializable]
internal class SimpleModPack internal class SimpleModPack
{ {
public string TtmpVersion = string.Empty; public string TtmpVersion = string.Empty;
public string Name = DefaultTexToolsData.Name; public string Name = DefaultTexToolsData.Name;
public string Author = DefaultTexToolsData.Author; public string Author = DefaultTexToolsData.Author;
public string Version = string.Empty; public string Version = string.Empty;
public string Description = DefaultTexToolsData.Description; public string Description = DefaultTexToolsData.Description;
public string Url = string.Empty; public string Url = string.Empty;
public SimpleMod[] SimpleModsList = Array.Empty< SimpleMod >(); public SimpleMod[] SimpleModsList = Array.Empty<SimpleMod>();
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -6,6 +7,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Penumbra.Import.Structs;
using Penumbra.Mods; using Penumbra.Mods;
using FileMode = System.IO.FileMode; using FileMode = System.IO.FileMode;
using ZipArchive = SharpCompress.Archives.Zip.ZipArchive; using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;

View file

@ -2,6 +2,7 @@ using Dalamud.Utility;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using Penumbra.Import.Structs;
using Penumbra.Mods; using Penumbra.Mods;
using SharpCompress.Archives; using SharpCompress.Archives;
using SharpCompress.Archives.Rar; using SharpCompress.Archives.Rar;

View file

@ -3,6 +3,7 @@ using System.Numerics;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Import.Structs;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
namespace Penumbra.Import; namespace Penumbra.Import;

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Import.Structs;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Util; using Penumbra.Util;
using SharpCompress.Archives.Zip; using SharpCompress.Archives.Zip;

View file

@ -3,6 +3,7 @@ using System.IO;
using Lumina.Extensions; using Lumina.Extensions;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Import.Structs;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Import.Structs;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
namespace Penumbra.Import; namespace Penumbra.Import;

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.ImGuiFileDialog;
using ImGuiNET; using ImGuiNET;
using ImGuiScene; using ImGuiScene;
using Lumina.Data.Files; using Lumina.Data.Files;

View file

@ -1,10 +1,10 @@
using System;
using System.IO;
using Lumina.Data.Files; using Lumina.Data.Files;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using System;
using System.IO;
namespace Penumbra.Import.Dds; namespace Penumbra.Import.Textures;
public static class TextureImporter public static class TextureImporter
{ {

View file

@ -82,7 +82,7 @@ public unsafe partial class CharacterUtility
ResetResourceInternal(); ResetResourceInternal();
} }
// Set the currently stored data of this resource to new values. /// <summary> Set the currently stored data of this resource to new values. </summary>
private void SetResourceInternal(nint data, int length) private void SetResourceInternal(nint data, int length)
{ {
if (!Ready) if (!Ready)
@ -92,7 +92,7 @@ public unsafe partial class CharacterUtility
resource->SetData(data, length); resource->SetData(data, length);
} }
// Reset the currently stored data of this resource to its default values. /// <summary> Reset the currently stored data of this resource to its default values. </summary>
private void ResetResourceInternal() private void ResetResourceInternal()
=> SetResourceInternal(_defaultResourceData, _defaultResourceSize); => SetResourceInternal(_defaultResourceData, _defaultResourceSize);

View file

@ -5,141 +5,136 @@ using System.Threading.Tasks;
namespace Penumbra.Mods; namespace Penumbra.Mods;
// Utility to create and apply a zipped backup of a mod. /// <summary> Utility to create and apply a zipped backup of a mod. </summary>
public class ModBackup public class ModBackup
{ {
public static bool CreatingBackup { get; private set; } public static bool CreatingBackup { get; private set; }
private readonly Mod _mod; private readonly Mod.Manager _modManager;
public readonly string Name; private readonly Mod _mod;
public readonly bool Exists; public readonly string Name;
public readonly bool Exists;
public ModBackup( Mod.Manager modManager, Mod mod ) public ModBackup(Mod.Manager modManager, Mod mod)
{ {
_mod = mod; _modManager = modManager;
Name = Path.Combine( modManager.ExportDirectory.FullName, _mod.ModPath.Name ) + ".pmp"; _mod = mod;
Exists = File.Exists( Name ); Name = Path.Combine(_modManager.ExportDirectory.FullName, _mod.ModPath.Name) + ".pmp";
Exists = File.Exists(Name);
} }
// Migrate file extensions. /// <summary> Migrate file extensions. </summary>
public static void MigrateZipToPmp( Mod.Manager manager ) public static void MigrateZipToPmp(Mod.Manager manager)
{ {
foreach( var mod in manager ) foreach (var mod in manager)
{ {
var pmpName = mod.ModPath + ".pmp"; var pmpName = mod.ModPath + ".pmp";
var zipName = mod.ModPath + ".zip"; var zipName = mod.ModPath + ".zip";
if( File.Exists( zipName ) ) if (!File.Exists(zipName))
{ continue;
try
{
if( !File.Exists( pmpName ) )
{
File.Move( zipName, pmpName );
}
else
{
File.Delete( zipName );
}
Penumbra.Log.Information( $"Migrated mod export from {zipName} to {pmpName}." ); try
} {
catch( Exception e ) if (!File.Exists(pmpName))
{ File.Move(zipName, pmpName);
Penumbra.Log.Warning( $"Could not migrate mod export of {mod.ModPath} from .pmp to .zip:\n{e}" ); else
} File.Delete(zipName);
Penumbra.Log.Information($"Migrated mod export from {zipName} to {pmpName}.");
}
catch (Exception e)
{
Penumbra.Log.Warning($"Could not migrate mod export of {mod.ModPath} from .pmp to .zip:\n{e}");
} }
} }
} }
// Move and/or rename an exported mod. /// <summary>
// This object is unusable afterwards. /// Move and/or rename an exported mod.
public void Move( string? newBasePath = null, string? newName = null ) /// This object is unusable afterwards.
/// </summary>
public void Move(string? newBasePath = null, string? newName = null)
{ {
if( CreatingBackup || !Exists ) if (CreatingBackup || !Exists)
{
return; return;
}
try try
{ {
newBasePath ??= Path.GetDirectoryName( Name ) ?? string.Empty; newBasePath ??= Path.GetDirectoryName(Name) ?? string.Empty;
newName = newName == null ? Path.GetFileName( Name ) : newName + ".pmp"; newName = newName == null ? Path.GetFileName(Name) : newName + ".pmp";
var newPath = Path.Combine( newBasePath, newName ); var newPath = Path.Combine(newBasePath, newName);
File.Move( Name, newPath ); File.Move(Name, newPath);
} }
catch( Exception e ) catch (Exception e)
{ {
Penumbra.Log.Warning( $"Could not move mod export file {Name}:\n{e}" ); Penumbra.Log.Warning($"Could not move mod export file {Name}:\n{e}");
} }
} }
// Create a backup zip without blocking the main thread. /// <summary> Create a backup zip without blocking the main thread. </summary>
public async void CreateAsync() public async void CreateAsync()
{ {
if( CreatingBackup ) if (CreatingBackup)
{
return; return;
}
CreatingBackup = true; CreatingBackup = true;
await Task.Run( Create ); await Task.Run(Create);
CreatingBackup = false; CreatingBackup = false;
} }
/// <summary> Create a backup. Overwrites pre-existing backups. </summary>
// Create a backup. Overwrites pre-existing backups.
private void Create() private void Create()
{ {
try try
{ {
Delete(); Delete();
ZipFile.CreateFromDirectory( _mod.ModPath.FullName, Name, CompressionLevel.Optimal, false ); ZipFile.CreateFromDirectory(_mod.ModPath.FullName, Name, CompressionLevel.Optimal, false);
Penumbra.Log.Debug( $"Created export file {Name} from {_mod.ModPath.FullName}." ); Penumbra.Log.Debug($"Created export file {Name} from {_mod.ModPath.FullName}.");
} }
catch( Exception e ) catch (Exception e)
{ {
Penumbra.Log.Error( $"Could not export mod {_mod.Name} to \"{Name}\":\n{e}" ); Penumbra.Log.Error($"Could not export mod {_mod.Name} to \"{Name}\":\n{e}");
} }
} }
// Delete a pre-existing backup. /// <summary> Delete a pre-existing backup. </summary>
public void Delete() public void Delete()
{ {
if( !Exists ) if (!Exists)
{
return; return;
}
try try
{ {
File.Delete( Name ); File.Delete(Name);
Penumbra.Log.Debug( $"Deleted export file {Name}." ); Penumbra.Log.Debug($"Deleted export file {Name}.");
} }
catch( Exception e ) catch (Exception e)
{ {
Penumbra.Log.Error( $"Could not delete file \"{Name}\":\n{e}" ); Penumbra.Log.Error($"Could not delete file \"{Name}\":\n{e}");
} }
} }
// Restore a mod from a pre-existing backup. Does not check if the mod contained in the backup is even similar. /// <summary>
// Does an automatic reload after extraction. /// Restore a mod from a pre-existing backup. Does not check if the mod contained in the backup is even similar.
/// Does an automatic reload after extraction.
/// </summary>
public void Restore() public void Restore()
{ {
try try
{ {
if( Directory.Exists( _mod.ModPath.FullName ) ) if (Directory.Exists(_mod.ModPath.FullName))
{ {
Directory.Delete( _mod.ModPath.FullName, true ); Directory.Delete(_mod.ModPath.FullName, true);
Penumbra.Log.Debug( $"Deleted mod folder {_mod.ModPath.FullName}." ); Penumbra.Log.Debug($"Deleted mod folder {_mod.ModPath.FullName}.");
} }
ZipFile.ExtractToDirectory( Name, _mod.ModPath.FullName ); ZipFile.ExtractToDirectory(Name, _mod.ModPath.FullName);
Penumbra.Log.Debug( $"Extracted exported file {Name} to {_mod.ModPath.FullName}." ); Penumbra.Log.Debug($"Extracted exported file {Name} to {_mod.ModPath.FullName}.");
Penumbra.ModManager.ReloadMod( _mod.Index ); _modManager.ReloadMod(_mod.Index);
} }
catch( Exception e ) catch (Exception e)
{ {
Penumbra.Log.Error( $"Could not restore {_mod.Name} from export \"{Name}\":\n{e}" ); Penumbra.Log.Error($"Could not restore {_mod.Name} from export \"{Name}\":\n{e}");
} }
} }
} }

View file

@ -24,12 +24,12 @@ public class ModEditor : IDisposable
public ModEditor(ModNormalizer modNormalizer, ModMetaEditor metaEditor, ModFileCollection files, public ModEditor(ModNormalizer modNormalizer, ModMetaEditor metaEditor, ModFileCollection files,
ModFileEditor fileEditor, DuplicateManager duplicates, ModSwapEditor swapEditor, MdlMaterialEditor mdlMaterialEditor) ModFileEditor fileEditor, DuplicateManager duplicates, ModSwapEditor swapEditor, MdlMaterialEditor mdlMaterialEditor)
{ {
ModNormalizer = modNormalizer; ModNormalizer = modNormalizer;
MetaEditor = metaEditor; MetaEditor = metaEditor;
Files = files; Files = files;
FileEditor = fileEditor; FileEditor = fileEditor;
Duplicates = duplicates; Duplicates = duplicates;
SwapEditor = swapEditor; SwapEditor = swapEditor;
MdlMaterialEditor = mdlMaterialEditor; MdlMaterialEditor = mdlMaterialEditor;
} }
@ -88,7 +88,7 @@ public class ModEditor : IDisposable
GroupIdx = -1; GroupIdx = -1;
OptionIdx = 0; OptionIdx = 0;
if (message) if (message)
global::Penumbra.Penumbra.Log.Error($"Loading invalid option {groupIdx} {optionIdx} for Mod {Mod?.Name ?? "Unknown"}."); Penumbra.Log.Error($"Loading invalid option {groupIdx} {optionIdx} for Mod {Mod?.Name ?? "Unknown"}.");
} }
public void Clear() public void Clear()
@ -125,4 +125,4 @@ public class ModEditor : IDisposable
subDir.Delete(); subDir.Delete();
} }
} }
} }

View file

@ -10,7 +10,7 @@ using Newtonsoft.Json.Linq;
using OtterGui.Classes; using OtterGui.Classes;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Import; using Penumbra.Import.Structs;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods;

View file

@ -15,6 +15,7 @@ using OtterGui.Raii;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.Import; using Penumbra.Import;
using Penumbra.Import.Structs;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;