mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Support for TexTools .rgsp files for meta changes. (Racial Scaling Parameters)
This commit is contained in:
parent
d52086b69c
commit
546f6d4152
13 changed files with 424 additions and 9 deletions
|
|
@ -27,6 +27,27 @@ namespace Penumbra.Game.Enums
|
|||
Viera,
|
||||
}
|
||||
|
||||
public enum SubRace : byte
|
||||
{
|
||||
Unknown,
|
||||
Midlander,
|
||||
Highlander,
|
||||
Wildwood,
|
||||
Duskwright,
|
||||
Plainsfolk,
|
||||
Dunesfolk,
|
||||
SeekerOfTheSun,
|
||||
KeeperOfTheMoon,
|
||||
Seawolf,
|
||||
Hellsguard,
|
||||
Raen,
|
||||
Xaela,
|
||||
Hellion,
|
||||
Lost,
|
||||
Rava,
|
||||
Veena,
|
||||
}
|
||||
|
||||
// The combined gender-race-npc numerical code as used by the game.
|
||||
public enum GenderRace : ushort
|
||||
{
|
||||
|
|
@ -69,6 +90,58 @@ namespace Penumbra.Game.Enums
|
|||
|
||||
public static class RaceEnumExtensions
|
||||
{
|
||||
public static int ToRspIndex( this SubRace subRace )
|
||||
{
|
||||
return subRace switch
|
||||
{
|
||||
SubRace.Midlander => 0,
|
||||
SubRace.Highlander => 1,
|
||||
SubRace.Wildwood => 10,
|
||||
SubRace.Duskwright => 11,
|
||||
SubRace.Plainsfolk => 20,
|
||||
SubRace.Dunesfolk => 21,
|
||||
SubRace.SeekerOfTheSun => 30,
|
||||
SubRace.KeeperOfTheMoon => 31,
|
||||
SubRace.Seawolf => 40,
|
||||
SubRace.Hellsguard => 41,
|
||||
SubRace.Raen => 50,
|
||||
SubRace.Xaela => 51,
|
||||
SubRace.Hellion => 60,
|
||||
SubRace.Lost => 61,
|
||||
SubRace.Rava => 70,
|
||||
SubRace.Veena => 71,
|
||||
_ => throw new InvalidEnumArgumentException(),
|
||||
};
|
||||
}
|
||||
|
||||
public static Race ToRace( this SubRace subRace )
|
||||
{
|
||||
return subRace switch
|
||||
{
|
||||
SubRace.Unknown => Race.Unknown,
|
||||
SubRace.Midlander => Race.Midlander,
|
||||
SubRace.Highlander => Race.Highlander,
|
||||
SubRace.Wildwood => Race.Elezen,
|
||||
SubRace.Duskwright => Race.Elezen,
|
||||
SubRace.Plainsfolk => Race.Lalafell,
|
||||
SubRace.Dunesfolk => Race.Lalafell,
|
||||
SubRace.SeekerOfTheSun => Race.Miqote,
|
||||
SubRace.KeeperOfTheMoon => Race.Miqote,
|
||||
SubRace.Seawolf => Race.Roegadyn,
|
||||
SubRace.Hellsguard => Race.Roegadyn,
|
||||
SubRace.Raen => Race.AuRa,
|
||||
SubRace.Xaela => Race.AuRa,
|
||||
SubRace.Hellion => Race.Hrothgar,
|
||||
SubRace.Lost => Race.Hrothgar,
|
||||
SubRace.Rava => Race.Viera,
|
||||
SubRace.Veena => Race.Viera,
|
||||
_ => throw new InvalidEnumArgumentException(),
|
||||
};
|
||||
}
|
||||
|
||||
public static bool FitsRace( this SubRace subRace, Race race )
|
||||
=> subRace.ToRace() == race;
|
||||
|
||||
public static byte ToByte( this Gender gender, Race race )
|
||||
=> ( byte )( ( int )gender | ( ( int )race << 3 ) );
|
||||
|
||||
|
|
|
|||
68
Penumbra/Game/Enums/RspAttribute.cs
Normal file
68
Penumbra/Game/Enums/RspAttribute.cs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
namespace Penumbra.Game.Enums
|
||||
{
|
||||
public enum RspAttribute : byte
|
||||
{
|
||||
MaleMinSize,
|
||||
MaleMaxSize,
|
||||
MaleMinTail,
|
||||
MaleMaxTail,
|
||||
FemaleMinSize,
|
||||
FemaleMaxSize,
|
||||
FemaleMinTail,
|
||||
FemaleMaxTail,
|
||||
BustMinX,
|
||||
BustMinY,
|
||||
BustMinZ,
|
||||
BustMaxX,
|
||||
BustMaxY,
|
||||
BustMaxZ,
|
||||
NumAttributes,
|
||||
}
|
||||
|
||||
public static class RspAttributeExtensions
|
||||
{
|
||||
public static Gender ToGender( this RspAttribute attribute )
|
||||
{
|
||||
return attribute switch
|
||||
{
|
||||
RspAttribute.MaleMinSize => Gender.Male,
|
||||
RspAttribute.MaleMaxSize => Gender.Male,
|
||||
RspAttribute.MaleMinTail => Gender.Male,
|
||||
RspAttribute.MaleMaxTail => Gender.Male,
|
||||
RspAttribute.FemaleMinSize => Gender.Female,
|
||||
RspAttribute.FemaleMaxSize => Gender.Female,
|
||||
RspAttribute.FemaleMinTail => Gender.Female,
|
||||
RspAttribute.FemaleMaxTail => Gender.Female,
|
||||
RspAttribute.BustMinX => Gender.Female,
|
||||
RspAttribute.BustMinY => Gender.Female,
|
||||
RspAttribute.BustMinZ => Gender.Female,
|
||||
RspAttribute.BustMaxX => Gender.Female,
|
||||
RspAttribute.BustMaxY => Gender.Female,
|
||||
RspAttribute.BustMaxZ => Gender.Female,
|
||||
_ => Gender.Unknown,
|
||||
};
|
||||
}
|
||||
|
||||
public static string ToUngenderedString( this RspAttribute attribute )
|
||||
{
|
||||
return attribute switch
|
||||
{
|
||||
RspAttribute.MaleMinSize => "MinSize",
|
||||
RspAttribute.MaleMaxSize => "MaxSize",
|
||||
RspAttribute.MaleMinTail => "MinTail",
|
||||
RspAttribute.MaleMaxTail => "MaxTail",
|
||||
RspAttribute.FemaleMinSize => "MinSize",
|
||||
RspAttribute.FemaleMaxSize => "MaxSize",
|
||||
RspAttribute.FemaleMinTail => "MinTail",
|
||||
RspAttribute.FemaleMaxTail => "MaxTail",
|
||||
RspAttribute.BustMinX => "BustMinX",
|
||||
RspAttribute.BustMinY => "BustMinY",
|
||||
RspAttribute.BustMinZ => "BustMinZ",
|
||||
RspAttribute.BustMaxX => "BustMaxX",
|
||||
RspAttribute.BustMaxY => "BustMaxY",
|
||||
RspAttribute.BustMaxZ => "BustMaxZ",
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Penumbra/Game/RspEntry.cs
Normal file
55
Penumbra/Game/RspEntry.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Penumbra.Game.Enums;
|
||||
|
||||
namespace Penumbra.Game
|
||||
{
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
|
||||
public readonly struct RspEntry
|
||||
{
|
||||
public const int ByteSize = ( int )RspAttribute.NumAttributes * 4;
|
||||
|
||||
private readonly float[] Attributes;
|
||||
|
||||
public RspEntry( byte[] bytes, int offset )
|
||||
{
|
||||
if( offset < 0 || offset + ByteSize > bytes.Length )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
Attributes = new float[( int )RspAttribute.NumAttributes];
|
||||
using MemoryStream s = new( bytes ) { Position = offset };
|
||||
using BinaryReader br = new( s );
|
||||
for( var i = 0; i < ( int )RspAttribute.NumAttributes; ++i )
|
||||
{
|
||||
Attributes[ i ] = br.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
private static int ToIndex( RspAttribute attribute )
|
||||
=> attribute < RspAttribute.NumAttributes && attribute >= 0
|
||||
? ( int )attribute
|
||||
: throw new InvalidEnumArgumentException();
|
||||
|
||||
public float this[ RspAttribute attribute ]
|
||||
{
|
||||
get => Attributes[ ToIndex( attribute ) ];
|
||||
set => Attributes[ ToIndex( attribute ) ] = value;
|
||||
}
|
||||
|
||||
public byte[] ToBytes()
|
||||
{
|
||||
using var s = new MemoryStream( ByteSize );
|
||||
using var bw = new BinaryWriter( s );
|
||||
foreach( var attribute in Attributes )
|
||||
{
|
||||
bw.Write( attribute );
|
||||
}
|
||||
|
||||
return s.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -316,5 +316,67 @@ namespace Penumbra.Importer
|
|||
PluginLog.Error( $"Error while parsing .meta file:\n{e}" );
|
||||
}
|
||||
}
|
||||
|
||||
private TexToolsMeta( string filePath, uint version )
|
||||
{
|
||||
FilePath = filePath;
|
||||
Version = version;
|
||||
}
|
||||
|
||||
public static TexToolsMeta Invalid = new( string.Empty, 0 );
|
||||
|
||||
public static TexToolsMeta FromRgspFile( string filePath, byte[] data )
|
||||
{
|
||||
if( data.Length != 45 && data.Length != 42 )
|
||||
{
|
||||
PluginLog.Error( "Error while parsing .rgsp file:\n\tInvalid number of bytes." );
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
using var s = new MemoryStream( data );
|
||||
using var br = new BinaryReader( s );
|
||||
var flag = br.ReadByte();
|
||||
var version = flag != 255 ? ( uint )1 : br.ReadUInt16();
|
||||
|
||||
var ret = new TexToolsMeta( filePath, version );
|
||||
|
||||
var subRace = ( SubRace )( br.ReadByte() + 1 );
|
||||
if( !Enum.IsDefined( typeof( SubRace ), subRace ) || subRace == SubRace.Unknown )
|
||||
{
|
||||
PluginLog.Error( $"Error while parsing .rgsp file:\n\t{subRace} is not a valid SubRace." );
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
var gender = br.ReadByte();
|
||||
if( gender != 1 && gender != 0 )
|
||||
{
|
||||
PluginLog.Error( $"Error while parsing .rgsp file:\n\t{gender} is neither Male nor Female." );
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
if( gender == 1 )
|
||||
{
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.FemaleMinSize, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.FemaleMaxSize, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.FemaleMinTail, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.FemaleMaxTail, br.ReadSingle() ) );
|
||||
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.BustMinX, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.BustMinY, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.BustMinZ, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.BustMaxX, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.BustMaxY, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.BustMaxZ, br.ReadSingle() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.MaleMinSize, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.MaleMaxSize, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.MaleMinTail, br.ReadSingle() ) );
|
||||
ret.AddIfNotDefault( MetaManipulation.Rsp( subRace, RspAttribute.MaleMaxTail, br.ReadSingle() ) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Penumbra/Meta/Files/CmpFile.cs
Normal file
72
Penumbra/Meta/Files/CmpFile.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Penumbra.Game;
|
||||
using Penumbra.Game.Enums;
|
||||
|
||||
namespace Penumbra.Meta.Files
|
||||
{
|
||||
public class CmpFile
|
||||
{
|
||||
private const int RacialScalingStart = 0x2A800;
|
||||
|
||||
private readonly byte[] _byteData = new byte[RacialScalingStart];
|
||||
private readonly List< RspEntry > _rspEntries;
|
||||
|
||||
public CmpFile( byte[] bytes )
|
||||
{
|
||||
if( bytes.Length < RacialScalingStart )
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
Array.Copy( bytes, _byteData, RacialScalingStart );
|
||||
var rspEntryNum = ( bytes.Length - RacialScalingStart ) / RspEntry.ByteSize;
|
||||
_rspEntries = new List< RspEntry >( rspEntryNum );
|
||||
for( var i = 0; i < rspEntryNum; ++i )
|
||||
{
|
||||
_rspEntries.Add( new RspEntry( bytes, RacialScalingStart + i * RspEntry.ByteSize ) );
|
||||
}
|
||||
}
|
||||
|
||||
public RspEntry this[ SubRace subRace ]
|
||||
=> _rspEntries[ subRace.ToRspIndex() ];
|
||||
|
||||
public bool Set( SubRace subRace, RspAttribute attribute, float value )
|
||||
{
|
||||
var entry = _rspEntries[ subRace.ToRspIndex() ];
|
||||
var oldValue = entry[ attribute ];
|
||||
if( oldValue == value )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
entry[ attribute ] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] WriteBytes()
|
||||
{
|
||||
using var s = new MemoryStream( RacialScalingStart + _rspEntries.Count * RspEntry.ByteSize );
|
||||
s.Write( _byteData, 0, _byteData.Length );
|
||||
foreach( var entry in _rspEntries )
|
||||
{
|
||||
var bytes = entry.ToBytes();
|
||||
s.Write( bytes, 0, bytes.Length );
|
||||
}
|
||||
|
||||
return s.ToArray();
|
||||
}
|
||||
|
||||
private CmpFile( byte[] data, List< RspEntry > entries )
|
||||
{
|
||||
_byteData = data.ToArray();
|
||||
_rspEntries = entries.ToList();
|
||||
}
|
||||
|
||||
public CmpFile Clone()
|
||||
=> new( _byteData, _rspEntries );
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,11 @@ namespace Penumbra.Meta.Files
|
|||
return new EstFile( rawFile );
|
||||
}
|
||||
|
||||
if( path.EndsWith( ".cmp" ) )
|
||||
{
|
||||
return new CmpFile( rawFile.Data );
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
|
@ -85,6 +90,9 @@ namespace Penumbra.Meta.Files
|
|||
=> GetDefaultFile< ImcFile >( MetaFileNames.Imc( type, primarySetId, secondarySetId ),
|
||||
$"Could not obtain Imc file for {type}, {primarySetId} {secondarySetId}:\n" );
|
||||
|
||||
private CmpFile? GetDefaultCmpFile()
|
||||
=> GetDefaultFile< CmpFile >( MetaFileNames.Cmp(), "Could not obtain Cmp file:\n" );
|
||||
|
||||
public EqdpFile? GetNewEqdpFile( EquipSlot slot, GenderRace gr )
|
||||
=> GetDefaultEqdpFile( slot, gr )?.Clone();
|
||||
|
||||
|
|
@ -100,6 +108,9 @@ namespace Penumbra.Meta.Files
|
|||
public ImcFile? GetNewImcFile( ObjectType type, ushort primarySetId, ushort secondarySetId = 0 )
|
||||
=> GetDefaultImcFile( type, primarySetId, secondarySetId )?.Clone();
|
||||
|
||||
public CmpFile? GetNewCmpFile()
|
||||
=> GetDefaultCmpFile()?.Clone();
|
||||
|
||||
public MetaDefaults( DalamudPluginInterface pi )
|
||||
=> _pi = pi;
|
||||
|
||||
|
|
@ -128,6 +139,8 @@ namespace Penumbra.Meta.Files
|
|||
MetaType.Est => GetDefaultEstFile( m.EstIdentifier.ObjectType, m.EstIdentifier.EquipSlot, m.EstIdentifier.BodySlot )
|
||||
?.GetEntry( m.EstIdentifier.GenderRace, m.EstIdentifier.PrimaryId )
|
||||
== m.EstValue,
|
||||
MetaType.Rsp => GetDefaultCmpFile()?[ m.RspIdentifier.SubRace ][ m.RspIdentifier.Attribute ]
|
||||
== m.RspValue,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
|
@ -142,6 +155,7 @@ namespace Penumbra.Meta.Files
|
|||
MetaType.Eqp => GetNewEqpFile(),
|
||||
MetaType.Eqdp => GetNewEqdpFile( m.EqdpIdentifier.Slot, m.EqdpIdentifier.GenderRace ),
|
||||
MetaType.Est => GetNewEstFile( m.EstIdentifier.ObjectType, m.EstIdentifier.EquipSlot, m.EstIdentifier.BodySlot ),
|
||||
MetaType.Rsp => GetNewCmpFile(),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,5 +76,8 @@ namespace Penumbra.Meta.Files
|
|||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
public static GamePath Cmp()
|
||||
=> GamePath.GenerateUnchecked( "chara/xls/charamake/human.cmp" );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using Penumbra.Game.Enums;
|
||||
using Penumbra.Meta.Files;
|
||||
|
||||
|
||||
// A struct for each type of meta change that contains all relevant information,
|
||||
|
|
@ -15,6 +16,7 @@ namespace Penumbra.Meta
|
|||
Eqp = 3,
|
||||
Est = 4,
|
||||
Gmp = 5,
|
||||
Rsp = 6,
|
||||
};
|
||||
|
||||
[StructLayout( LayoutKind.Explicit )]
|
||||
|
|
@ -150,4 +152,23 @@ namespace Penumbra.Meta
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout( LayoutKind.Explicit )]
|
||||
public struct RspIdentifier
|
||||
{
|
||||
[FieldOffset( 0 )]
|
||||
public ulong Value;
|
||||
|
||||
[FieldOffset( 0 )]
|
||||
public MetaType Type;
|
||||
|
||||
[FieldOffset( 1 )]
|
||||
public SubRace SubRace;
|
||||
|
||||
[FieldOffset( 2 )]
|
||||
public RspAttribute Attribute;
|
||||
|
||||
public override string ToString()
|
||||
=> $"Rsp - {SubRace} - {Attribute}";
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Dalamud.Plugin;
|
||||
using Newtonsoft.Json;
|
||||
using Penumbra.Importer;
|
||||
|
|
@ -151,9 +152,16 @@ namespace Penumbra.Meta
|
|||
{
|
||||
DefaultData.Clear();
|
||||
GroupData.Clear();
|
||||
foreach( var file in files.Where( f => f.Extension == ".meta" ) )
|
||||
Count = 0;
|
||||
foreach( var file in files )
|
||||
{
|
||||
var metaData = new TexToolsMeta( File.ReadAllBytes( file.FullName ) );
|
||||
TexToolsMeta metaData = file.Extension.ToLowerInvariant() switch
|
||||
{
|
||||
".meta" => new TexToolsMeta( File.ReadAllBytes( file.FullName ) ),
|
||||
".rgsp" => TexToolsMeta.FromRgspFile( file.FullName, File.ReadAllBytes( file.FullName ) ),
|
||||
_ => TexToolsMeta.Invalid,
|
||||
};
|
||||
|
||||
if( metaData.FilePath == string.Empty || metaData.Manipulations.Count == 0 )
|
||||
{
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace Penumbra.Meta
|
|||
GmpFile gmp => gmp.WriteBytes(),
|
||||
EstFile est => est.WriteBytes(),
|
||||
ImcFile imc => imc.WriteBytes(),
|
||||
CmpFile cmp => cmp.WriteBytes(),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
DisposeFile( CurrentFile );
|
||||
|
|
@ -158,6 +159,7 @@ namespace Penumbra.Meta
|
|||
MetaType.Gmp => m.Apply( ( GmpFile )file.Data ),
|
||||
MetaType.Est => m.Apply( ( EstFile )file.Data ),
|
||||
MetaType.Imc => m.Apply( ( ImcFile )file.Data ),
|
||||
MetaType.Rsp => m.Apply( ( CmpFile )file.Data ),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,18 @@ namespace Penumbra.Meta
|
|||
ImcValue = value,
|
||||
};
|
||||
|
||||
public static MetaManipulation Rsp( SubRace subRace, RspAttribute attribute, float value )
|
||||
=> new()
|
||||
{
|
||||
RspIdentifier = new RspIdentifier()
|
||||
{
|
||||
Type = MetaType.Rsp,
|
||||
SubRace = subRace,
|
||||
Attribute = attribute,
|
||||
},
|
||||
RspValue = value,
|
||||
};
|
||||
|
||||
internal MetaManipulation( ulong identifier, ulong value )
|
||||
: this()
|
||||
{
|
||||
|
|
@ -160,6 +172,9 @@ namespace Penumbra.Meta
|
|||
[FieldOffset( 0 )]
|
||||
public ImcIdentifier ImcIdentifier;
|
||||
|
||||
[FieldOffset( 0 )]
|
||||
public RspIdentifier RspIdentifier;
|
||||
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
public EqpEntry EqpValue;
|
||||
|
|
@ -176,6 +191,9 @@ namespace Penumbra.Meta
|
|||
[FieldOffset( 8 )]
|
||||
public ImcFile.ImageChangeData ImcValue; // 6 bytes.
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
public float RspValue;
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Identifier.GetHashCode();
|
||||
|
||||
|
|
@ -191,6 +209,7 @@ namespace Penumbra.Meta
|
|||
MetaType.Est => MetaFileNames.Est( EstIdentifier.ObjectType, EstIdentifier.EquipSlot, EstIdentifier.BodySlot ),
|
||||
MetaType.Gmp => MetaFileNames.Gmp(),
|
||||
MetaType.Imc => MetaFileNames.Imc( ImcIdentifier.ObjectType, ImcIdentifier.PrimaryId, ImcIdentifier.SecondaryId ),
|
||||
MetaType.Rsp => MetaFileNames.Cmp(),
|
||||
_ => throw new InvalidEnumArgumentException(),
|
||||
};
|
||||
}
|
||||
|
|
@ -220,6 +239,9 @@ namespace Penumbra.Meta
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool Apply( CmpFile file )
|
||||
=> file.Set( RspIdentifier.SubRace, RspIdentifier.Attribute, RspValue );
|
||||
|
||||
public string IdentifierString()
|
||||
{
|
||||
return Type switch
|
||||
|
|
@ -229,6 +251,7 @@ namespace Penumbra.Meta
|
|||
MetaType.Est => EstIdentifier.ToString(),
|
||||
MetaType.Gmp => GmpIdentifier.ToString(),
|
||||
MetaType.Imc => ImcIdentifier.ToString(),
|
||||
MetaType.Rsp => RspIdentifier.ToString(),
|
||||
_ => throw new InvalidEnumArgumentException(),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,13 +57,15 @@ namespace Penumbra.Mod
|
|||
.SelectMany( dir => dir.EnumerateFiles( "*.*", SearchOption.AllDirectories ) )
|
||||
.OrderBy( f => f.FullName ) )
|
||||
{
|
||||
if( file.Extension != ".meta" )
|
||||
switch( file.Extension.ToLowerInvariant() )
|
||||
{
|
||||
tmpFiles.Add( file );
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpMetas.Add( file );
|
||||
case ".meta":
|
||||
case ".rgsp":
|
||||
tmpMetas.Add( file );
|
||||
break;
|
||||
default:
|
||||
tmpFiles.Add( file );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface;
|
||||
|
|
@ -774,10 +775,21 @@ namespace Penumbra.UI
|
|||
ImGui.Text( manip.ImcIdentifier.Variant.ToString() );
|
||||
break;
|
||||
}
|
||||
case MetaType.Rsp:
|
||||
{
|
||||
ImGui.Text( manip.RspIdentifier.Attribute.ToUngenderedString() );
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text( manip.RspIdentifier.SubRace.ToString() );
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text( manip.RspIdentifier.Attribute.ToGender().ToString() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TableSetColumnIndex( 9 );
|
||||
ImGui.Text( manip.Value.ToString() );
|
||||
ImGui.Text( manip.Type == MetaType.Rsp ? manip.RspValue.ToString( CultureInfo.InvariantCulture ) : manip.Value.ToString() );
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue