mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-31 21:03:48 +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
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(),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue