Fix issues with accessories and with gender-locked gear.

This commit is contained in:
Ottermandias 2023-01-01 23:32:54 +01:00
parent 070d73a5a1
commit bc3a55eded
3 changed files with 54 additions and 17 deletions

View file

@ -52,9 +52,19 @@ public static class EquipmentSwap
_ => ( EstManipulation.EstType )0, _ => ( EstManipulation.EstType )0,
}; };
var skipFemale = false;
var skipMale = false;
var mtrlVariantTo = imcFileTo.GetEntry( ImcFile.PartIndex( slotFrom ), variantTo ).MaterialId; var mtrlVariantTo = imcFileTo.GetEntry( ImcFile.PartIndex( slotFrom ), variantTo ).MaterialId;
foreach( var gr in Enum.GetValues< GenderRace >() ) 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 ) if( CharacterUtility.EqdpIdx( gr, isAccessory ) < 0 )
{ {
continue; continue;
@ -66,12 +76,28 @@ public static class EquipmentSwap
swaps.Add( est ); swaps.Add( est );
} }
try
{
var eqdp = CreateEqdp( redirections, manips, slotFrom, gr, idFrom, idTo, mtrlVariantTo ); var eqdp = CreateEqdp( redirections, manips, slotFrom, gr, idFrom, idTo, mtrlVariantTo );
if( eqdp != null ) if( eqdp != null )
{ {
swaps.Add( eqdp ); 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;
}
}
}
foreach( var variant in variants ) foreach( var variant in variants )
{ {
@ -79,7 +105,6 @@ public static class EquipmentSwap
swaps.Add( imc ); swaps.Add( imc );
} }
return affectedItems; 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 ) 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 accessory = slot.IsAccessory();
var mdlPathTo = GamePaths.Equipment.Mdl.Path( idTo, gr, slot ); 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 ); var mdl = FileSwap.CreateSwap( ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo );
foreach( ref var fileName in mdl.AsMdl()!.Materials.AsSpan() ) foreach( ref var fileName in mdl.AsMdl()!.Materials.AsSpan() )
@ -292,7 +318,7 @@ public static class EquipmentSwap
} }
var newPath = ItemSwap.ReplaceAnyId( path, prefix, idFrom ); 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 ) if( newPath != path )
{ {
texture.Path = addedDashes ? newPath.Replace( "--", string.Empty ) : newPath; 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 ) public static FileSwap CreateAtex( Func< Utf8GamePath, FullPath > redirections, ref string filePath, ref bool dataWasChanged )
{ {
var oldPath = filePath; 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; dataWasChanged = true;
return FileSwap.CreateSwap( ResourceType.Atex, redirections, filePath, oldPath, oldPath ); return FileSwap.CreateSwap( ResourceType.Atex, redirections, filePath, oldPath, oldPath );

View file

@ -23,6 +23,15 @@ public static class ItemSwap
public class IdUnavailableException : Exception 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 ) private static bool LoadFile( FullPath path, out byte[] data )
{ {
if( path.FullName.Length > 0 ) if( path.FullName.Length > 0 )

View file

@ -7,6 +7,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using static Penumbra.Mods.ItemSwap.ItemSwap;
namespace Penumbra.Mods.ItemSwap; namespace Penumbra.Mods.ItemSwap;
@ -63,7 +64,7 @@ public sealed class FileSwap : Swap
public ResourceType Type; public ResourceType Type;
/// <summary> The binary or parsed data of the file at SwapToModded. </summary> /// <summary> The binary or parsed data of the file at SwapToModded. </summary>
public IWritable FileData = ItemSwap.GenericFile.Invalid; public IWritable FileData = GenericFile.Invalid;
/// <summary> The path that would be requested without manipulated parent files. </summary> /// <summary> The path that would be requested without manipulated parent files. </summary>
public string SwapFromPreChangePath = string.Empty; public string SwapFromPreChangePath = string.Empty;
@ -114,12 +115,13 @@ public sealed class FileSwap : Swap
/// <param name="swapToRequest">The unmodded path to the file the game is supposed to load instead.</param> /// <param name="swapToRequest">The unmodded path to the file the game is supposed to load instead.</param>
/// <param name="swap">A full swap container with the actual file in memory.</param> /// <param name="swap">A full swap container with the actual file in memory.</param>
/// <returns>True if everything could be read correctly, false otherwise.</returns> /// <returns>True if everything could be read correctly, false otherwise.</returns>
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 var swap = new FileSwap
{ {
Type = type, Type = type,
FileData = ItemSwap.GenericFile.Invalid, FileData = GenericFile.Invalid,
DataWasChanged = false, DataWasChanged = false,
SwapFromPreChangePath = swapFromPreChange ?? swapFromRequest, SwapFromPreChangePath = swapFromPreChange ?? swapFromRequest,
SwapFromChanged = swapFromPreChange != swapFromRequest, SwapFromChanged = swapFromPreChange != swapFromRequest,
@ -142,10 +144,10 @@ public sealed class FileSwap : Swap
swap.FileData = type switch 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.Mdl => LoadMdl( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
ResourceType.Mtrl => ItemSwap.LoadMtrl( swap.SwapToModded, out var f ) ? f : throw new Exception( $"Could not load file data for {swap.SwapToModded}." ), ResourceType.Mtrl => LoadMtrl( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
ResourceType.Avfx => ItemSwap.LoadAvfx( swap.SwapToModded, out var f ) ? f : throw new Exception( $"Could not load file data for {swap.SwapToModded}." ), ResourceType.Avfx => LoadAvfx( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
_ => ItemSwap.LoadFile( swap.SwapToModded, out var f ) ? f : throw new Exception( $"Could not load file data for {swap.SwapToModded}." ), _ => LoadFile( swap.SwapToModded, out var f ) ? f : throw new MissingFileException( type, swap.SwapToModded ),
}; };
return swap; return swap;