Add some improvements to game path stuff, move the race inheritance tree to game data, etc.

This commit is contained in:
Ottermandias 2022-12-02 17:18:23 +01:00
parent b50ed4b99a
commit f1b495dff4
8 changed files with 607 additions and 320 deletions

View file

@ -78,9 +78,9 @@ public unsafe partial class PathResolver
private void OnModelLoadCompleteDetour( IntPtr drawObject )
{
var collection = GetResolveData( drawObject );
using var eqp = collection.ModCollection.TemporarilySetEqpFile();
using var eqdp = ResolveEqdpData( collection.ModCollection, GetDrawObjectGenderRace( drawObject ), true, true );
var collection = GetResolveData( drawObject );
using var eqp = collection.ModCollection.TemporarilySetEqpFile();
using var eqdp = ResolveEqdpData( collection.ModCollection, GetDrawObjectGenderRace( drawObject ), true, true );
_onModelLoadCompleteHook.Original.Invoke( drawObject );
}
@ -98,9 +98,9 @@ public unsafe partial class PathResolver
return;
}
var collection = GetResolveData( drawObject );
using var eqp = collection.ModCollection.TemporarilySetEqpFile();
using var eqdp = ResolveEqdpData( collection.ModCollection, GetDrawObjectGenderRace( drawObject ), true, true );
var collection = GetResolveData( drawObject );
using var eqp = collection.ModCollection.TemporarilySetEqpFile();
using var eqdp = ResolveEqdpData( collection.ModCollection, GetDrawObjectGenderRace( drawObject ), true, true );
_updateModelsHook.Original.Invoke( drawObject );
}
@ -187,75 +187,27 @@ public unsafe partial class PathResolver
_inChangeCustomize = true;
var resolveData = GetResolveData( human );
using var cmp = resolveData.ModCollection.TemporarilySetCmpFile();
using var decals = new CharacterUtility.DecalReverter( resolveData.ModCollection, DrawObjectState.UsesDecal( 0, data ) );
var ret = _changeCustomize.Original( human, data, skipEquipment );
using var decals = new CharacterUtility.DecalReverter( resolveData.ModCollection, DrawObjectState.UsesDecal( 0, data ) );
var ret = _changeCustomize.Original( human, data, skipEquipment );
_inChangeCustomize = false;
return ret;
}
public static DisposableContainer ResolveEqdpData( ModCollection collection, GenderRace race, bool equipment, bool accessory )
{
DisposableContainer Convert( params GenderRace[] races )
var races = race.Dependencies();
if( races.Length == 0 )
{
var equipmentEnumerable =
equipment
? races.Select( r => collection.TemporarilySetEqdpFile( r, false ) )
: Array.Empty< IDisposable? >().AsEnumerable();
var accessoryEnumerable =
accessory
? races.Select( r => collection.TemporarilySetEqdpFile( r, true ) )
: Array.Empty< IDisposable? >().AsEnumerable();
return new DisposableContainer( equipmentEnumerable.Concat( accessoryEnumerable ) );
return DisposableContainer.Empty;
}
return race switch
{
// @formatter:off
MidlanderMale => Convert( MidlanderMale ),
HighlanderMale => Convert( MidlanderMale, HighlanderMale ),
ElezenMale => Convert( MidlanderMale, ElezenMale ),
MiqoteMale => Convert( MidlanderMale, MiqoteMale ),
RoegadynMale => Convert( MidlanderMale, RoegadynMale ),
LalafellMale => Convert( MidlanderMale, LalafellMale ),
AuRaMale => Convert( MidlanderMale, AuRaMale ),
HrothgarMale => Convert( MidlanderMale, RoegadynMale, HrothgarMale ),
VieraMale => Convert( MidlanderMale, VieraMale ),
MidlanderFemale => Convert( MidlanderMale, MidlanderFemale ),
HighlanderFemale => Convert( MidlanderMale, MidlanderFemale, HighlanderFemale ),
ElezenFemale => Convert( MidlanderMale, MidlanderFemale, ElezenFemale ),
MiqoteFemale => Convert( MidlanderMale, MidlanderFemale, MiqoteFemale ),
RoegadynFemale => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale ),
LalafellFemale => Convert( MidlanderMale, LalafellMale, LalafellFemale ),
AuRaFemale => Convert( MidlanderMale, MidlanderFemale, AuRaFemale ),
HrothgarFemale => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale, HrothgarFemale ),
VieraFemale => Convert( MidlanderMale, MidlanderFemale, VieraFemale ),
MidlanderMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc ),
HighlanderMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, HighlanderMale, HighlanderMaleNpc ),
ElezenMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, ElezenMale, ElezenMaleNpc ),
MiqoteMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MiqoteMale, MiqoteMaleNpc ),
RoegadynMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, RoegadynMale, RoegadynMaleNpc ),
LalafellMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, LalafellMale, LalafellMaleNpc ),
AuRaMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, AuRaMale, AuRaMaleNpc ),
HrothgarMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, RoegadynMaleNpc, RoegadynMale, HrothgarMale, HrothgarMaleNpc ),
VieraMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, VieraMale, VieraMaleNpc ),
MidlanderFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc ),
HighlanderFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, HighlanderFemale, HighlanderFemaleNpc ),
ElezenFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, ElezenFemale, ElezenFemaleNpc ),
MiqoteFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, MiqoteFemale, MiqoteFemaleNpc ),
RoegadynFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, RoegadynFemale, RoegadynFemaleNpc ),
LalafellFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, LalafellMale, LalafellMaleNpc, LalafellFemale, LalafellFemaleNpc ),
AuRaFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, AuRaFemale, AuRaFemaleNpc ),
HrothgarFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, RoegadynFemale, RoegadynFemaleNpc, HrothgarFemale, HrothgarFemaleNpc ),
VieraFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, VieraFemale, VieraFemaleNpc ),
UnknownMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, UnknownMaleNpc ),
UnknownFemaleNpc => Convert( MidlanderMale, MidlanderMaleNpc, MidlanderFemale, MidlanderFemaleNpc, UnknownFemaleNpc ),
_ => DisposableContainer.Empty,
// @formatter:on
};
var equipmentEnumerable = equipment
? races.Select( r => collection.TemporarilySetEqdpFile( r, false ) )
: Array.Empty< IDisposable? >().AsEnumerable();
var accessoryEnumerable = accessory
? races.Select( r => collection.TemporarilySetEqdpFile( r, true ) )
: Array.Empty< IDisposable? >().AsEnumerable();
return new DisposableContainer( equipmentEnumerable.Concat( accessoryEnumerable ) );
}
}
}

View file

@ -2,6 +2,7 @@ using System;
using System.Numerics;
using Newtonsoft.Json;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.Structs;
using Penumbra.Meta.Manipulations;
using Penumbra.String.Classes;
@ -9,52 +10,6 @@ using Penumbra.String.Functions;
namespace Penumbra.Meta.Files;
public readonly struct ImcEntry : IEquatable< ImcEntry >
{
public byte MaterialId { get; init; }
public byte DecalId { get; init; }
public readonly ushort AttributeAndSound;
public byte VfxId { get; init; }
public byte MaterialAnimationId { get; init; }
public ushort AttributeMask
{
get => ( ushort )( AttributeAndSound & 0x3FF );
init => AttributeAndSound = ( ushort )( ( AttributeAndSound & ~0x3FF ) | ( value & 0x3FF ) );
}
public byte SoundId
{
get => ( byte )( AttributeAndSound >> 10 );
init => AttributeAndSound = ( ushort )( AttributeMask | ( value << 10 ) );
}
public bool Equals( ImcEntry other )
=> MaterialId == other.MaterialId
&& DecalId == other.DecalId
&& AttributeAndSound == other.AttributeAndSound
&& VfxId == other.VfxId
&& MaterialAnimationId == other.MaterialAnimationId;
public override bool Equals( object? obj )
=> obj is ImcEntry other && Equals( other );
public override int GetHashCode()
=> HashCode.Combine( MaterialId, DecalId, AttributeAndSound, VfxId, MaterialAnimationId );
[JsonConstructor]
public ImcEntry( byte materialId, byte decalId, ushort attributeMask, byte soundId, byte vfxId, byte materialAnimationId )
{
MaterialId = materialId;
DecalId = decalId;
AttributeAndSound = 0;
VfxId = vfxId;
MaterialAnimationId = materialAnimationId;
AttributeMask = attributeMask;
SoundId = soundId;
}
}
public class ImcException : Exception
{
public readonly ImcManipulation Manipulation;
@ -212,8 +167,11 @@ public unsafe class ImcFile : MetaBaseFile
}
public static ImcEntry GetDefault( Utf8GamePath path, EquipSlot slot, int variantIdx, out bool exists )
=> GetDefault( path.ToString(), slot, variantIdx, out exists );
public static ImcEntry GetDefault( string path, EquipSlot slot, int variantIdx, out bool exists )
{
var file = Dalamud.GameData.GetFile( path.ToString() );
var file = Dalamud.GameData.GetFile( path );
exists = false;
if( file == null )
{

View file

@ -2,7 +2,9 @@ using System;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.Structs;
using Penumbra.Meta.Files;
using Penumbra.String.Classes;
@ -130,25 +132,12 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation >
{
return ObjectType switch
{
ObjectType.Accessory => Utf8GamePath.FromString( $"chara/accessory/a{PrimaryId:D4}/a{PrimaryId:D4}.imc", out var p )
? p
: Utf8GamePath.Empty,
ObjectType.Equipment => Utf8GamePath.FromString( $"chara/equipment/e{PrimaryId:D4}/e{PrimaryId:D4}.imc", out var p )
? p
: Utf8GamePath.Empty,
ObjectType.DemiHuman => Utf8GamePath.FromString(
$"chara/demihuman/d{PrimaryId:D4}/obj/equipment/e{SecondaryId:D4}/e{SecondaryId:D4}.imc", out var p )
? p
: Utf8GamePath.Empty,
ObjectType.Monster => Utf8GamePath.FromString( $"chara/monster/m{PrimaryId:D4}/obj/body/b{SecondaryId:D4}/b{SecondaryId:D4}.imc",
out var p )
? p
: Utf8GamePath.Empty,
ObjectType.Weapon => Utf8GamePath.FromString( $"chara/weapon/w{PrimaryId:D4}/obj/body/b{SecondaryId:D4}/b{SecondaryId:D4}.imc",
out var p )
? p
: Utf8GamePath.Empty,
_ => throw new NotImplementedException(),
ObjectType.Accessory => Utf8GamePath.FromString( GamePaths.Accessory.Imc.Path( PrimaryId ), out var p ) ? p : Utf8GamePath.Empty,
ObjectType.Equipment => Utf8GamePath.FromString( GamePaths.Equipment.Imc.Path( PrimaryId ), out var p ) ? p : Utf8GamePath.Empty,
ObjectType.DemiHuman => Utf8GamePath.FromString( GamePaths.DemiHuman.Imc.Path( PrimaryId, SecondaryId ), out var p ) ? p : Utf8GamePath.Empty,
ObjectType.Monster => Utf8GamePath.FromString( GamePaths.Monster.Imc.Path( PrimaryId, SecondaryId ), out var p ) ? p : Utf8GamePath.Empty,
ObjectType.Weapon => Utf8GamePath.FromString( GamePaths.Weapon.Imc.Path( PrimaryId, SecondaryId ), out var p ) ? p : Utf8GamePath.Empty,
_ => throw new NotImplementedException(),
};
}