diff --git a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs
index 3bdc99a9..49e8ae66 100644
--- a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs
+++ b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs
@@ -34,7 +34,7 @@ public static class EquipmentSwap
swaps.Add( eqp );
}
- var gmp = CreateGmp( manips, slotFrom, idFrom, idTo);
+ var gmp = CreateGmp( manips, slotFrom, idFrom, idTo );
if( gmp != null )
{
swaps.Add( gmp );
@@ -52,9 +52,19 @@ public static class EquipmentSwap
_ => ( EstManipulation.EstType )0,
};
+ var skipFemale = false;
+ var skipMale = false;
var mtrlVariantTo = imcFileTo.GetEntry( ImcFile.PartIndex( slotFrom ), variantTo ).MaterialId;
foreach( var gr in Enum.GetValues< GenderRace >() )
{
+ switch( gr.Split().Item1 )
+ {
+ case Gender.Male when skipMale: continue;
+ case Gender.Female when skipFemale: continue;
+ case Gender.MaleNpc when skipMale: continue;
+ case Gender.FemaleNpc when skipFemale: continue;
+ }
+
if( CharacterUtility.EqdpIdx( gr, isAccessory ) < 0 )
{
continue;
@@ -66,10 +76,26 @@ public static class EquipmentSwap
swaps.Add( est );
}
- var eqdp = CreateEqdp( redirections, manips, slotFrom, gr, idFrom, idTo, mtrlVariantTo );
- if( eqdp != null )
+ try
{
- swaps.Add( eqdp );
+ var eqdp = CreateEqdp( redirections, manips, slotFrom, gr, idFrom, idTo, mtrlVariantTo );
+ if( eqdp != null )
+ {
+ swaps.Add( eqdp );
+ }
+ }
+ catch( ItemSwap.MissingFileException e )
+ {
+ switch( gr )
+ {
+ case GenderRace.MidlanderMale when e.Type == ResourceType.Mdl:
+ skipMale = true;
+ continue;
+ case GenderRace.MidlanderFemale when e.Type == ResourceType.Mdl:
+ skipFemale = true;
+ continue;
+ default: throw;
+ }
}
}
@@ -79,7 +105,6 @@ public static class EquipmentSwap
swaps.Add( imc );
}
-
return affectedItems;
}
@@ -106,8 +131,9 @@ public static class EquipmentSwap
public static FileSwap CreateMdl( Func< Utf8GamePath, FullPath > redirections, EquipSlot slot, GenderRace gr, SetId idFrom, SetId idTo, byte mtrlTo )
{
- var mdlPathFrom = GamePaths.Equipment.Mdl.Path( idFrom, gr, slot );
- var mdlPathTo = GamePaths.Equipment.Mdl.Path( idTo, gr, slot );
+ var accessory = slot.IsAccessory();
+ var mdlPathFrom = accessory ? GamePaths.Accessory.Mdl.Path( idFrom, gr, slot ) : GamePaths.Equipment.Mdl.Path( idFrom, gr, slot );
+ var mdlPathTo = accessory ? GamePaths.Accessory.Mdl.Path( idTo, gr, slot ) : GamePaths.Equipment.Mdl.Path( idTo, gr, slot );
var mdl = FileSwap.CreateSwap( ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo );
foreach( ref var fileName in mdl.AsMdl()!.Materials.AsSpan() )
@@ -292,7 +318,7 @@ public static class EquipmentSwap
}
var newPath = ItemSwap.ReplaceAnyId( path, prefix, idFrom );
- newPath = ItemSwap.AddSuffix( newPath, ".tex", $"_{Path.GetFileName( texture.Path ).GetStableHashCode():x8}", true );
+ newPath = ItemSwap.AddSuffix( newPath, ".tex", $"_{Path.GetFileName( texture.Path ).GetStableHashCode():x8}" );
if( newPath != path )
{
texture.Path = addedDashes ? newPath.Replace( "--", string.Empty ) : newPath;
@@ -311,7 +337,7 @@ public static class EquipmentSwap
public static FileSwap CreateAtex( Func< Utf8GamePath, FullPath > redirections, ref string filePath, ref bool dataWasChanged )
{
var oldPath = filePath;
- filePath = ItemSwap.AddSuffix( filePath, ".atex", $"_{Path.GetFileName( filePath ).GetStableHashCode():x8}", true );
+ filePath = ItemSwap.AddSuffix( filePath, ".atex", $"_{Path.GetFileName( filePath ).GetStableHashCode():x8}" );
dataWasChanged = true;
return FileSwap.CreateSwap( ResourceType.Atex, redirections, filePath, oldPath, oldPath );
diff --git a/Penumbra/Mods/ItemSwap/ItemSwap.cs b/Penumbra/Mods/ItemSwap/ItemSwap.cs
index d8e8809a..68812674 100644
--- a/Penumbra/Mods/ItemSwap/ItemSwap.cs
+++ b/Penumbra/Mods/ItemSwap/ItemSwap.cs
@@ -23,6 +23,15 @@ public static class ItemSwap
public class IdUnavailableException : Exception
{ }
+ public class MissingFileException : Exception
+ {
+ public readonly ResourceType Type;
+
+ public MissingFileException( ResourceType type, object path )
+ : base($"Could not load {type} File Data for \"{path}\".")
+ => Type = type;
+ }
+
private static bool LoadFile( FullPath path, out byte[] data )
{
if( path.FullName.Length > 0 )
diff --git a/Penumbra/Mods/ItemSwap/Swaps.cs b/Penumbra/Mods/ItemSwap/Swaps.cs
index 5e40f9ac..332aa6ac 100644
--- a/Penumbra/Mods/ItemSwap/Swaps.cs
+++ b/Penumbra/Mods/ItemSwap/Swaps.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Security.Cryptography;
using Penumbra.GameData.Enums;
+using static Penumbra.Mods.ItemSwap.ItemSwap;
namespace Penumbra.Mods.ItemSwap;
@@ -63,7 +64,7 @@ public sealed class FileSwap : Swap
public ResourceType Type;
/// The binary or parsed data of the file at SwapToModded.
- public IWritable FileData = ItemSwap.GenericFile.Invalid;
+ public IWritable FileData = GenericFile.Invalid;
/// The path that would be requested without manipulated parent files.
public string SwapFromPreChangePath = string.Empty;
@@ -114,12 +115,13 @@ public sealed class FileSwap : Swap
/// The unmodded path to the file the game is supposed to load instead.
/// A full swap container with the actual file in memory.
/// True if everything could be read correctly, false otherwise.
- public static FileSwap CreateSwap( ResourceType type, Func< Utf8GamePath, FullPath > redirections, string swapFromRequest, string swapToRequest, string? swapFromPreChange = null )
+ public static FileSwap CreateSwap( ResourceType type, Func< Utf8GamePath, FullPath > redirections, string swapFromRequest, string swapToRequest,
+ string? swapFromPreChange = null )
{
var swap = new FileSwap
{
Type = type,
- FileData = ItemSwap.GenericFile.Invalid,
+ FileData = GenericFile.Invalid,
DataWasChanged = false,
SwapFromPreChangePath = swapFromPreChange ?? swapFromRequest,
SwapFromChanged = swapFromPreChange != swapFromRequest,
@@ -142,10 +144,10 @@ public sealed class FileSwap : Swap
swap.FileData = type switch
{
- ResourceType.Mdl => ItemSwap.LoadMdl( swap.SwapToModded, out var f ) ? f : throw new Exception( $"Could not load file data for {swap.SwapToModded}." ),
- ResourceType.Mtrl => ItemSwap.LoadMtrl( swap.SwapToModded, out var f ) ? f : throw new Exception( $"Could not load file data for {swap.SwapToModded}." ),
- ResourceType.Avfx => ItemSwap.LoadAvfx( swap.SwapToModded, out var f ) ? f : throw new Exception( $"Could not load file data for {swap.SwapToModded}." ),
- _ => ItemSwap.LoadFile( swap.SwapToModded, out var f ) ? f : throw new Exception( $"Could not load file data for {swap.SwapToModded}." ),
+ ResourceType.Mdl => LoadMdl( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
+ ResourceType.Mtrl => LoadMtrl( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
+ ResourceType.Avfx => LoadAvfx( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
+ _ => LoadFile( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
};
return swap;
@@ -166,7 +168,7 @@ public sealed class FileSwap : Swap
var name =
$"{( oldFilename.StartsWith( "--" ) ? "--" : string.Empty )}{string.Join( null, hash.Select( c => c.ToString( "x2" ) ) )}.{swap.Type.ToString().ToLowerInvariant()}";
var newPath = path.Replace( oldFilename, name );
- var newSwap = CreateSwap( swap.Type, redirections, newPath, swap.SwapToRequestPath.ToString());
+ var newSwap = CreateSwap( swap.Type, redirections, newPath, swap.SwapToRequestPath.ToString() );
path = newPath;
dataWasChanged = true;