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

View file

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

View file

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

View file

@ -1,6 +1,8 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using Dalamud.Plugin;
using Lumina.Data.Files;
using Penumbra.Game;
using Penumbra.Mods;
@ -9,9 +11,13 @@ namespace Penumbra.MetaData
{
public static class ImcExtensions
{
public static bool Equal( this ImcFile.ImageChangeData lhs, ImcFile.ImageChangeData rhs ) =>
lhs.MaterialId == rhs.MaterialId && lhs.DecalId == rhs.DecalId && lhs.AttributeMask == rhs.AttributeMask
&& lhs.SoundId == rhs.SoundId && lhs.VfxId == rhs.VfxId && lhs.MaterialAnimationId == rhs.MaterialAnimationId;
public static bool Equal( this ImcFile.ImageChangeData lhs, ImcFile.ImageChangeData rhs )
=> lhs.MaterialId == rhs.MaterialId
&& 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 )
{
@ -67,7 +73,7 @@ namespace Penumbra.MetaData
EquipSlot.RingR => 3,
EquipSlot.Feet => 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 ].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 )
@ -84,12 +99,12 @@ namespace Penumbra.MetaData
var ret = new ImcFile
{
Count = file.Count,
PartMask = file.PartMask
PartMask = file.PartMask,
};
var parts = file.GetParts().Select( P => new ImcFile.ImageChangeParts()
{
DefaultVariant = P.DefaultVariant,
Variants = ( ImcFile.ImageChangeData[] )P.Variants.Clone()
Variants = ( ImcFile.ImageChangeData[] )P.Variants.Clone(),
} ).ToArray();
var prop = ret.GetType().GetField( "Parts", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
prop!.SetValue( ret, parts );