Support for TexTools .rgsp files for meta changes. (Racial Scaling Parameters)

This commit is contained in:
Ottermandias 2021-06-29 18:54:53 +02:00
parent d52086b69c
commit 546f6d4152
13 changed files with 424 additions and 9 deletions

View 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 );
}
}

View file

@ -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(),
};
}

View file

@ -76,5 +76,8 @@ namespace Penumbra.Meta.Files
_ => throw new NotImplementedException(),
};
}
public static GamePath Cmp()
=> GamePath.GenerateUnchecked( "chara/xls/charamake/human.cmp" );
}
}

View file

@ -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}";
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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(),
};
}