Fix crash on load of meta files with secondary type / no slot info.

This commit is contained in:
Ottermandias 2021-04-20 15:41:05 +02:00
parent c3a8b4cb0b
commit 234712ca99
4 changed files with 47 additions and 34 deletions

View file

@ -55,7 +55,7 @@ namespace Penumbra.Importer
ObjectType.Unknown => false, ObjectType.Unknown => false,
ObjectType.Weapon => false, ObjectType.Weapon => false,
ObjectType.World => false, ObjectType.World => false,
_ => false _ => false,
}; };
} }
@ -93,32 +93,30 @@ namespace Penumbra.Importer
} }
PrimaryId = ushort.Parse( match.Groups[ "PrimaryId" ].Value ); PrimaryId = ushort.Parse( match.Groups[ "PrimaryId" ].Value );
if( !match.Groups[ "Slot" ].Success ) if( match.Groups[ "Slot" ].Success )
{ {
return; switch( PrimaryType )
} {
case ObjectType.Equipment:
case ObjectType.Accessory:
if( GameData.SuffixToEquipSlot.TryGetValue( match.Groups[ "Slot" ].Value, out var tmpSlot ) )
{
EquipSlot = tmpSlot;
}
switch( PrimaryType ) break;
{ case ObjectType.Character:
case ObjectType.Equipment: if( GameData.SuffixToCustomizationType.TryGetValue( match.Groups[ "Slot" ].Value, out var tmpCustom ) )
case ObjectType.Accessory: {
if( GameData.SuffixToEquipSlot.TryGetValue( match.Groups[ "Slot" ].Value, out var tmpSlot ) ) CustomizationType = tmpCustom;
{ }
EquipSlot = tmpSlot;
}
break; break;
case ObjectType.Character: }
if( GameData.SuffixToCustomizationType.TryGetValue( match.Groups[ "Slot" ].Value, out var tmpCustom ) )
{
CustomizationType = tmpCustom;
}
break;
} }
if( match.Groups[ "SecondaryType" ].Success if( match.Groups[ "SecondaryType" ].Success
&& GameData.StringToBodySlot.TryGetValue( match.Groups[ "SecondaryType" ].Value, out SecondaryType ) ) && GameData.StringToBodySlot.TryGetValue( match.Groups[ "SecondaryType" ].Value, out SecondaryType ) )
{ {
SecondaryId = ushort.Parse( match.Groups[ "SecondaryId" ].Value ); SecondaryId = ushort.Parse( match.Groups[ "SecondaryId" ].Value );
} }
@ -217,8 +215,8 @@ namespace Penumbra.Importer
var id = reader.ReadUInt16(); var id = reader.ReadUInt16();
var value = reader.ReadUInt16(); var value = reader.ReadUInt16();
if( !gr.IsValid() if( !gr.IsValid()
|| info.PrimaryType == ObjectType.Character && info.SecondaryType != BodySlot.Face && info.SecondaryType != BodySlot.Hair || info.PrimaryType == ObjectType.Character && info.SecondaryType != BodySlot.Face && info.SecondaryType != BodySlot.Hair
|| info.PrimaryType == ObjectType.Equipment && info.EquipSlot != EquipSlot.Head && info.EquipSlot != EquipSlot.Body ) || info.PrimaryType == ObjectType.Equipment && info.EquipSlot != EquipSlot.Head && info.EquipSlot != EquipSlot.Body )
{ {
continue; continue;
} }

View file

@ -108,7 +108,7 @@ namespace Penumbra.MetaData
protected T GetEntry< T >( T[]?[] blocks, ushort idx, T defaultEntry ) protected T GetEntry< T >( T[]?[] blocks, ushort idx, T defaultEntry )
{ {
// Skip the zeroth item. // Skip the zeroth item.
idx = idx == 0 ? 1 : idx; idx = idx == 0 ? ( ushort )1 : idx;
var block = BlockIdx( idx ); var block = BlockIdx( idx );
var array = block < blocks.Length ? blocks[ block ] : null; var array = block < blocks.Length ? blocks[ block ] : null;
if( array == null ) if( array == null )
@ -122,7 +122,7 @@ namespace Penumbra.MetaData
protected ref T GetTrueEntry< T >( T[]?[] blocks, ushort idx ) protected ref T GetTrueEntry< T >( T[]?[] blocks, ushort idx )
{ {
// Skip the zeroth item. // Skip the zeroth item.
idx = idx == 0 ? 1 : idx; idx = idx == 0 ? ( ushort )1 : idx;
var block = BlockIdx( idx ); var block = BlockIdx( idx );
if( block >= TotalBlockCount ) if( block >= TotalBlockCount )
{ {
@ -141,7 +141,7 @@ namespace Penumbra.MetaData
using var bw = new BinaryWriter( mem ); using var bw = new BinaryWriter( mem );
foreach( var parameter in blocks.Where( array => array != null ) foreach( var parameter in blocks.Where( array => array != null )
.SelectMany( array => array ) ) .SelectMany( array => array ) )
{ {
bw.Write( transform( parameter ) ); bw.Write( transform( parameter ) );
} }

View file

@ -101,7 +101,7 @@ namespace Penumbra.MetaData
return 0; return 0;
} }
return !setDict.TryGetValue( setId, out var entry ) ? 0 : entry; return !setDict.TryGetValue( setId, out var entry ) ? (ushort) 0 : entry;
} }
public byte[] WriteBytes() public byte[] WriteBytes()

View file

@ -1,6 +1,8 @@
using System;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Dalamud.Plugin;
using Lumina.Data.Files; using Lumina.Data.Files;
using Penumbra.Game; using Penumbra.Game;
using Penumbra.Mods; using Penumbra.Mods;
@ -9,9 +11,13 @@ namespace Penumbra.MetaData
{ {
public static class ImcExtensions public static class ImcExtensions
{ {
public static bool Equal( this ImcFile.ImageChangeData lhs, ImcFile.ImageChangeData rhs ) => public static bool Equal( this ImcFile.ImageChangeData lhs, ImcFile.ImageChangeData rhs )
lhs.MaterialId == rhs.MaterialId && lhs.DecalId == rhs.DecalId && lhs.AttributeMask == rhs.AttributeMask => lhs.MaterialId == rhs.MaterialId
&& lhs.SoundId == rhs.SoundId && lhs.VfxId == rhs.VfxId && lhs.MaterialAnimationId == rhs.MaterialAnimationId; && lhs.DecalId == rhs.DecalId
&& lhs.AttributeMask == rhs.AttributeMask
&& lhs.SoundId == rhs.SoundId
&& lhs.VfxId == rhs.VfxId
&& lhs.MaterialAnimationId == rhs.MaterialAnimationId;
private static void WriteBytes( this ImcFile.ImageChangeData variant, BinaryWriter bw ) private static void WriteBytes( this ImcFile.ImageChangeData variant, BinaryWriter bw )
{ {
@ -67,7 +73,7 @@ namespace Penumbra.MetaData
EquipSlot.RingR => 3, EquipSlot.RingR => 3,
EquipSlot.Feet => 4, EquipSlot.Feet => 4,
EquipSlot.RingL => 4, EquipSlot.RingL => 4,
_ => throw new InvalidEnumArgumentException() _ => throw new InvalidEnumArgumentException(),
}; };
} }
@ -76,7 +82,16 @@ namespace Penumbra.MetaData
return ref parts[ idx ].DefaultVariant; return ref parts[ idx ].DefaultVariant;
} }
return ref parts[ idx ].Variants[ imc.Variant - 1 ]; if( imc.Variant > parts[ idx ].Variants.Length )
{
PluginLog.Debug( "Trying to manipulate invalid variant {Variant} of {NumVariants} in file {FileName}.", imc.Variant,
parts[ idx ].Variants.Length, file.FilePath.Path );
return ref parts[ idx ].Variants[ parts[ idx ].Variants.Length - 1 ];
}
else
{
return ref parts[ idx ].Variants[ imc.Variant - 1 ];
}
} }
public static ImcFile Clone( this ImcFile file ) public static ImcFile Clone( this ImcFile file )
@ -84,12 +99,12 @@ namespace Penumbra.MetaData
var ret = new ImcFile var ret = new ImcFile
{ {
Count = file.Count, Count = file.Count,
PartMask = file.PartMask PartMask = file.PartMask,
}; };
var parts = file.GetParts().Select( P => new ImcFile.ImageChangeParts() var parts = file.GetParts().Select( P => new ImcFile.ImageChangeParts()
{ {
DefaultVariant = P.DefaultVariant, DefaultVariant = P.DefaultVariant,
Variants = ( ImcFile.ImageChangeData[] )P.Variants.Clone() Variants = ( ImcFile.ImageChangeData[] )P.Variants.Clone(),
} ).ToArray(); } ).ToArray();
var prop = ret.GetType().GetField( "Parts", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance ); var prop = ret.GetType().GetField( "Parts", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
prop!.SetValue( ret, parts ); prop!.SetValue( ret, parts );