mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-14 04:34:19 +01:00
Change EST files to be sorted and thus work.
This commit is contained in:
parent
19b295bbc3
commit
aa7d71530d
1 changed files with 122 additions and 117 deletions
|
|
@ -4,154 +4,159 @@ using System.Linq;
|
||||||
using Lumina.Data;
|
using Lumina.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Penumbra.Meta.Files
|
namespace Penumbra.Meta.Files;
|
||||||
|
|
||||||
|
// EST Structure:
|
||||||
|
// 1x [NumEntries : UInt32]
|
||||||
|
// Apparently entries need to be sorted.
|
||||||
|
// #NumEntries x [SetId : UInt16] [RaceId : UInt16]
|
||||||
|
// #NumEntries x [SkeletonId : UInt16]
|
||||||
|
public class EstFile
|
||||||
{
|
{
|
||||||
// EST Structure:
|
private const ushort EntryDescSize = 4;
|
||||||
// 1x [NumEntries : UInt32]
|
private const ushort EntrySize = 2;
|
||||||
// #NumEntries x [SetId : UInt16] [RaceId : UInt16]
|
|
||||||
// #NumEntries x [SkeletonId : UInt16]
|
private readonly SortedList< GenderRace, SortedList< ushort, ushort > > _entries = new();
|
||||||
public class EstFile
|
private uint NumEntries { get; set; }
|
||||||
|
|
||||||
|
private EstFile( EstFile clone )
|
||||||
{
|
{
|
||||||
private const ushort EntryDescSize = 4;
|
NumEntries = clone.NumEntries;
|
||||||
private const ushort EntrySize = 2;
|
_entries = new SortedList< GenderRace, SortedList< ushort, ushort > >( clone._entries.Count );
|
||||||
|
foreach( var (genderRace, data) in clone._entries )
|
||||||
private readonly Dictionary< GenderRace, Dictionary< ushort, ushort > > _entries = new();
|
|
||||||
private uint NumEntries { get; set; }
|
|
||||||
|
|
||||||
private EstFile( EstFile clone )
|
|
||||||
{
|
{
|
||||||
NumEntries = clone.NumEntries;
|
var dict = new SortedList< ushort, ushort >( data.Count );
|
||||||
_entries = new Dictionary< GenderRace, Dictionary< ushort, ushort > >( clone._entries.Count );
|
foreach( var (setId, value) in data )
|
||||||
foreach( var kvp in clone._entries )
|
|
||||||
{
|
{
|
||||||
var dict = kvp.Value.ToDictionary( k => k.Key, k => k.Value );
|
dict.Add( setId, value );
|
||||||
_entries.Add( kvp.Key, dict );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_entries.Add( genderRace, dict );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EstFile Clone()
|
||||||
|
=> new(this);
|
||||||
|
|
||||||
|
private bool DeleteEntry( GenderRace gr, ushort setId )
|
||||||
|
{
|
||||||
|
if( !_entries.TryGetValue( gr, out var setDict ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EstFile Clone()
|
if( !setDict.ContainsKey( setId ) )
|
||||||
=> new( this );
|
|
||||||
|
|
||||||
private bool DeleteEntry( GenderRace gr, ushort setId )
|
|
||||||
{
|
{
|
||||||
if( !_entries.TryGetValue( gr, out var setDict ) )
|
return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !setDict.ContainsKey( setId ) )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setDict.Remove( setId );
|
|
||||||
if( setDict.Count == 0 )
|
|
||||||
{
|
|
||||||
_entries.Remove( gr );
|
|
||||||
}
|
|
||||||
|
|
||||||
--NumEntries;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private (bool, bool) AddEntry( GenderRace gr, ushort setId, ushort entry )
|
setDict.Remove( setId );
|
||||||
|
if( setDict.Count == 0 )
|
||||||
{
|
{
|
||||||
if( !_entries.TryGetValue( gr, out var setDict ) )
|
_entries.Remove( gr );
|
||||||
{
|
}
|
||||||
_entries[ gr ] = new Dictionary< ushort, ushort >();
|
|
||||||
setDict = _entries[ gr ];
|
|
||||||
}
|
|
||||||
|
|
||||||
if( setDict.TryGetValue( setId, out var oldEntry ) )
|
--NumEntries;
|
||||||
{
|
return true;
|
||||||
if( oldEntry == entry )
|
}
|
||||||
{
|
|
||||||
return ( false, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
setDict[ setId ] = entry;
|
private (bool, bool) AddEntry( GenderRace gr, ushort setId, ushort entry )
|
||||||
return ( false, true );
|
{
|
||||||
|
if( !_entries.TryGetValue( gr, out var setDict ) )
|
||||||
|
{
|
||||||
|
_entries[ gr ] = new SortedList< ushort, ushort >();
|
||||||
|
setDict = _entries[ gr ];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( setDict.TryGetValue( setId, out var oldEntry ) )
|
||||||
|
{
|
||||||
|
if( oldEntry == entry )
|
||||||
|
{
|
||||||
|
return ( false, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
setDict[ setId ] = entry;
|
setDict[ setId ] = entry;
|
||||||
return ( true, true );
|
return ( false, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetEntry( GenderRace gr, ushort setId, ushort entry )
|
setDict[ setId ] = entry;
|
||||||
|
return ( true, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetEntry( GenderRace gr, ushort setId, ushort entry )
|
||||||
|
{
|
||||||
|
if( entry == 0 )
|
||||||
{
|
{
|
||||||
if( entry == 0 )
|
return DeleteEntry( gr, setId );
|
||||||
{
|
|
||||||
return DeleteEntry( gr, setId );
|
|
||||||
}
|
|
||||||
|
|
||||||
var (addedNew, changed) = AddEntry( gr, setId, entry );
|
|
||||||
if( !addedNew )
|
|
||||||
{
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
++NumEntries;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ushort GetEntry( GenderRace gr, ushort setId )
|
var (addedNew, changed) = AddEntry( gr, setId, entry );
|
||||||
|
if( !addedNew )
|
||||||
{
|
{
|
||||||
if( !_entries.TryGetValue( gr, out var setDict ) )
|
return changed;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !setDict.TryGetValue( setId, out var entry ) ? ( ushort )0 : entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] WriteBytes()
|
++NumEntries;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort GetEntry( GenderRace gr, ushort setId )
|
||||||
|
{
|
||||||
|
if( !_entries.TryGetValue( gr, out var setDict ) )
|
||||||
{
|
{
|
||||||
using MemoryStream mem = new( ( int )( 4 + ( EntryDescSize + EntrySize ) * NumEntries ) );
|
return 0;
|
||||||
using BinaryWriter bw = new( mem );
|
|
||||||
|
|
||||||
bw.Write( NumEntries );
|
|
||||||
foreach( var kvp1 in _entries )
|
|
||||||
{
|
|
||||||
foreach( var kvp2 in kvp1.Value )
|
|
||||||
{
|
|
||||||
bw.Write( kvp2.Key );
|
|
||||||
bw.Write( ( ushort )kvp1.Key );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach( var kvp2 in _entries.SelectMany( kvp1 => kvp1.Value ) )
|
|
||||||
{
|
|
||||||
bw.Write( kvp2.Value );
|
|
||||||
}
|
|
||||||
|
|
||||||
return mem.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return !setDict.TryGetValue( setId, out var entry ) ? ( ushort )0 : entry;
|
||||||
|
}
|
||||||
|
|
||||||
public EstFile( FileResource file )
|
public byte[] WriteBytes()
|
||||||
|
{
|
||||||
|
using MemoryStream mem = new(( int )( 4 + ( EntryDescSize + EntrySize ) * NumEntries ));
|
||||||
|
using BinaryWriter bw = new(mem);
|
||||||
|
|
||||||
|
bw.Write( NumEntries );
|
||||||
|
foreach( var kvp1 in _entries )
|
||||||
{
|
{
|
||||||
file.Reader.BaseStream.Seek( 0, SeekOrigin.Begin );
|
foreach( var kvp2 in kvp1.Value )
|
||||||
NumEntries = file.Reader.ReadUInt32();
|
|
||||||
|
|
||||||
var currentEntryDescOffset = 4;
|
|
||||||
var currentEntryOffset = 4 + EntryDescSize * NumEntries;
|
|
||||||
for( var i = 0; i < NumEntries; ++i )
|
|
||||||
{
|
{
|
||||||
file.Reader.BaseStream.Seek( currentEntryDescOffset, SeekOrigin.Begin );
|
bw.Write( kvp2.Key );
|
||||||
currentEntryDescOffset += EntryDescSize;
|
bw.Write( ( ushort )kvp1.Key );
|
||||||
var setId = file.Reader.ReadUInt16();
|
|
||||||
var raceId = ( GenderRace )file.Reader.ReadUInt16();
|
|
||||||
if( !raceId.IsValid() )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.Reader.BaseStream.Seek( currentEntryOffset, SeekOrigin.Begin );
|
|
||||||
currentEntryOffset += EntrySize;
|
|
||||||
var entry = file.Reader.ReadUInt16();
|
|
||||||
|
|
||||||
AddEntry( raceId, setId, entry );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach( var kvp2 in _entries.SelectMany( kvp1 => kvp1.Value ) )
|
||||||
|
{
|
||||||
|
bw.Write( kvp2.Value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public EstFile( FileResource file )
|
||||||
|
{
|
||||||
|
file.Reader.BaseStream.Seek( 0, SeekOrigin.Begin );
|
||||||
|
NumEntries = file.Reader.ReadUInt32();
|
||||||
|
|
||||||
|
var currentEntryDescOffset = 4;
|
||||||
|
var currentEntryOffset = 4 + EntryDescSize * NumEntries;
|
||||||
|
for( var i = 0; i < NumEntries; ++i )
|
||||||
|
{
|
||||||
|
file.Reader.BaseStream.Seek( currentEntryDescOffset, SeekOrigin.Begin );
|
||||||
|
currentEntryDescOffset += EntryDescSize;
|
||||||
|
var setId = file.Reader.ReadUInt16();
|
||||||
|
var raceId = ( GenderRace )file.Reader.ReadUInt16();
|
||||||
|
if( !raceId.IsValid() )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.Reader.BaseStream.Seek( currentEntryOffset, SeekOrigin.Begin );
|
||||||
|
currentEntryOffset += EntrySize;
|
||||||
|
var entry = file.Reader.ReadUInt16();
|
||||||
|
|
||||||
|
AddEntry( raceId, setId, entry );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue