Fix some problems with super early files and meta files.

This commit is contained in:
Ottermandias 2022-09-19 13:19:08 +02:00
parent 257c0d390b
commit 57e66f9b66
8 changed files with 120 additions and 133 deletions

View file

@ -7,6 +7,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Penumbra.Collections; namespace Penumbra.Collections;
@ -215,7 +216,7 @@ public partial class ModCollection
} }
// Load the interface collection. // Load the interface collection.
var interfaceName = jObject[ nameof( Interface ) ]?.ToObject< string >() ?? (configChanged ? Empty.Name : Default.Name); var interfaceName = jObject[ nameof( Interface ) ]?.ToObject< string >() ?? ( configChanged ? Empty.Name : Default.Name );
var interfaceIdx = GetIndexForCollectionName( interfaceName ); var interfaceIdx = GetIndexForCollectionName( interfaceName );
if( interfaceIdx < 0 ) if( interfaceIdx < 0 )
{ {
@ -285,8 +286,6 @@ public partial class ModCollection
{ {
SaveActiveCollections(); SaveActiveCollections();
} }
CreateNecessaryCaches();
} }
@ -363,7 +362,6 @@ public partial class ModCollection
return false; return false;
} }
// Save if any of the active collections is changed. // Save if any of the active collections is changed.
private void SaveOnChange( CollectionType collectionType, ModCollection? _1, ModCollection? _2, string? _3 ) private void SaveOnChange( CollectionType collectionType, ModCollection? _1, ModCollection? _2, string? _3 )
{ {
@ -373,18 +371,20 @@ public partial class ModCollection
} }
} }
// Cache handling. Usually recreate caches on the next framework tick,
// Cache handling. // but at launch create all of them at once.
private void CreateNecessaryCaches() public void CreateNecessaryCaches()
{ {
Default.CreateCache(); var tasks = _specialCollections.OfType< ModCollection >()
Interface.CreateCache(); .Concat( _characters.Values )
Current.CreateCache(); .Prepend( Current )
.Prepend( Default )
.Prepend( Interface )
.Distinct()
.Select( c => Task.Run( c.CalculateEffectiveFileListInternal ) )
.ToArray();
foreach( var collection in _specialCollections.OfType< ModCollection >().Concat( _characters.Values ) ) Task.WaitAll( tasks );
{
collection.CreateCache();
}
} }
private void RemoveCache( int idx ) private void RemoveCache( int idx )

View file

@ -133,67 +133,6 @@ public partial class ModCollection
Penumbra.Log.Debug( $"[{Thread.CurrentThread.ManagedThreadId}] Recalculation of effective file list for {AnonymizedName} finished." ); Penumbra.Log.Debug( $"[{Thread.CurrentThread.ManagedThreadId}] Recalculation of effective file list for {AnonymizedName} finished." );
} }
// Set Metadata files.
public void SetEqpFiles()
{
if( _cache == null )
{
MetaManager.ResetEqpFiles();
}
else
{
_cache.MetaManipulations.SetEqpFiles();
}
}
public void SetEqdpFiles()
{
if( _cache == null )
{
MetaManager.ResetEqdpFiles();
}
else
{
_cache.MetaManipulations.SetEqdpFiles();
}
}
public void SetGmpFiles()
{
if( _cache == null )
{
MetaManager.ResetGmpFiles();
}
else
{
_cache.MetaManipulations.SetGmpFiles();
}
}
public void SetEstFiles()
{
if( _cache == null )
{
MetaManager.ResetEstFiles();
}
else
{
_cache.MetaManipulations.SetEstFiles();
}
}
public void SetCmpFiles()
{
if( _cache == null )
{
MetaManager.ResetCmpFiles();
}
else
{
_cache.MetaManipulations.SetCmpFiles();
}
}
public void SetFiles() public void SetFiles()
{ {
if( _cache == null ) if( _cache == null )
@ -207,6 +146,18 @@ public partial class ModCollection
} }
} }
public void SetMetaFile( Interop.Structs.CharacterUtility.Index idx )
{
if( _cache == null )
{
Penumbra.CharacterUtility.ResetResource( idx );
}
else
{
_cache.MetaManipulations.SetFile( idx );
}
}
// Used for short periods of changed files. // Used for short periods of changed files.
public CharacterUtility.List.MetaReverter? TemporarilySetEqdpFile( GenderRace genderRace, bool accessory ) public CharacterUtility.List.MetaReverter? TemporarilySetEqdpFile( GenderRace genderRace, bool accessory )
=> _cache?.MetaManipulations.TemporarilySetEqdpFile( genderRace, accessory ); => _cache?.MetaManipulations.TemporarilySetEqdpFile( genderRace, accessory );
@ -222,5 +173,4 @@ public partial class ModCollection
public CharacterUtility.List.MetaReverter? TemporarilySetEstFile( EstManipulation.EstType type ) public CharacterUtility.List.MetaReverter? TemporarilySetEstFile( EstManipulation.EstType type )
=> _cache?.MetaManipulations.TemporarilySetEstFile( type ); => _cache?.MetaManipulations.TemporarilySetEstFile( type );
}
}

View file

@ -50,7 +50,8 @@ public unsafe partial class CharacterUtility
public MetaReverter TemporarilyResetResource() public MetaReverter TemporarilyResetResource()
{ {
Penumbra.Log.Verbose( $"Temporarily reset resource {GlobalIndex} to default at 0x{_defaultResourceData:X} ({_defaultResourceSize} bytes)." ); Penumbra.Log.Verbose(
$"Temporarily reset resource {GlobalIndex} to default at 0x{_defaultResourceData:X} ({_defaultResourceSize} bytes)." );
var reverter = new MetaReverter( this ); var reverter = new MetaReverter( this );
_entries.AddFirst( reverter ); _entries.AddFirst( reverter );
ResetResourceInternal(); ResetResourceInternal();
@ -84,6 +85,9 @@ public unsafe partial class CharacterUtility
private void ResetResourceInternal() private void ResetResourceInternal()
=> SetResourceInternal( _defaultResourceData, _defaultResourceSize ); => SetResourceInternal( _defaultResourceData, _defaultResourceSize );
private void SetResourceToDefaultCollection()
=> Penumbra.CollectionManager.Default.SetMetaFile( GlobalIndex );
public void Dispose() public void Dispose()
{ {
if( _entries.Count > 0 ) if( _entries.Count > 0 )
@ -127,14 +131,14 @@ public unsafe partial class CharacterUtility
if( list.Count == 0 ) if( list.Count == 0 )
{ {
List.ResetResourceInternal(); List.SetResourceToDefaultCollection();
} }
else else
{ {
var next = list.First!.Value; var next = list.First!.Value;
if( next.Resetter ) if( next.Resetter )
{ {
List.ResetResourceInternal(); List.SetResourceToDefaultCollection();
} }
else else
{ {

View file

@ -78,9 +78,9 @@ public unsafe partial class CharacterUtility : IDisposable
if( !anyMissing ) if( !anyMissing )
{ {
Ready = true; Ready = true;
LoadingFinished.Invoke();
Dalamud.Framework.Update -= LoadDefaultResources; Dalamud.Framework.Update -= LoadDefaultResources;
LoadingFinished.Invoke();
} }
} }

View file

@ -56,7 +56,7 @@ public unsafe partial class PathResolver
{ {
if( type == ResourceType.Tex if( type == ResourceType.Tex
&& LastCreatedCollection.Valid && LastCreatedCollection.Valid
&& gamePath.Path.Substring( "chara/common/texture/".Length ).StartsWith( 'd', 'e', 'c', 'a', 'l', '_', 'f', 'a', 'c', 'e' ) ) && gamePath.Path.Substring( "chara/common/texture/".Length ).StartsWith( 'd', 'e', 'c', 'a', 'l' ) )
{ {
resolveData = LastCreatedCollection; resolveData = LastCreatedCollection;
return true; return true;

View file

@ -81,8 +81,8 @@ public unsafe partial class PathResolver
var collection = GetResolveData( drawObject ); var collection = GetResolveData( drawObject );
if( collection.Valid ) if( collection.Valid )
{ {
using var eqp = collection.ModCollection.TemporarilySetEqpFile(); using var eqp = collection.ModCollection.TemporarilySetEqpFile();
using var eqdp = ResolveEqdpData( collection.ModCollection, GetDrawObjectGenderRace( drawObject ), true, true ); using var eqdp = ResolveEqdpData( collection.ModCollection, GetDrawObjectGenderRace( drawObject ), true, true );
_onModelLoadCompleteHook.Original.Invoke( drawObject ); _onModelLoadCompleteHook.Original.Invoke( drawObject );
} }
else else
@ -211,61 +211,60 @@ public unsafe partial class PathResolver
var equipmentEnumerable = var equipmentEnumerable =
equipment equipment
? races.Select( r => collection.TemporarilySetEqdpFile( r, false ) ) ? races.Select( r => collection.TemporarilySetEqdpFile( r, false ) )
: Array.Empty<IDisposable?>().AsEnumerable(); : Array.Empty< IDisposable? >().AsEnumerable();
var accessoryEnumerable = var accessoryEnumerable =
accessory accessory
? races.Select( r => collection.TemporarilySetEqdpFile( r, true ) ) ? races.Select( r => collection.TemporarilySetEqdpFile( r, true ) )
: Array.Empty<IDisposable?>().AsEnumerable(); : Array.Empty< IDisposable? >().AsEnumerable();
return new DisposableContainer( equipmentEnumerable.Concat( accessoryEnumerable ) ); return new DisposableContainer( equipmentEnumerable.Concat( accessoryEnumerable ) );
} }
return race switch return race switch
{ {
MidlanderMale => Convert( MidlanderMale ), MidlanderMale => Convert( MidlanderMale ),
HighlanderMale => Convert( MidlanderMale, HighlanderMale ), HighlanderMale => Convert( MidlanderMale, HighlanderMale ),
ElezenMale => Convert( MidlanderMale, ElezenMale ), ElezenMale => Convert( MidlanderMale, ElezenMale ),
MiqoteMale => Convert( MidlanderMale, MiqoteMale ), MiqoteMale => Convert( MidlanderMale, MiqoteMale ),
RoegadynMale => Convert( MidlanderMale, RoegadynMale ), RoegadynMale => Convert( MidlanderMale, RoegadynMale ),
LalafellMale => Convert( MidlanderMale, LalafellMale ), LalafellMale => Convert( MidlanderMale, LalafellMale ),
AuRaMale => Convert( MidlanderMale, AuRaMale ), AuRaMale => Convert( MidlanderMale, AuRaMale ),
HrothgarMale => Convert( MidlanderMale, RoegadynMale, HrothgarMale ), HrothgarMale => Convert( MidlanderMale, RoegadynMale, HrothgarMale ),
VieraMale => Convert( MidlanderMale, VieraMale ), VieraMale => Convert( MidlanderMale, VieraMale ),
MidlanderFemale => Convert( MidlanderMale, MidlanderFemale ), MidlanderFemale => Convert( MidlanderMale, MidlanderFemale ),
HighlanderFemale => Convert( MidlanderMale, MidlanderFemale, HighlanderFemale ), HighlanderFemale => Convert( MidlanderMale, MidlanderFemale, HighlanderFemale ),
ElezenFemale => Convert( MidlanderMale, MidlanderFemale, ElezenFemale ), ElezenFemale => Convert( MidlanderMale, MidlanderFemale, ElezenFemale ),
MiqoteFemale => Convert( MidlanderMale, MidlanderFemale, MiqoteFemale ), MiqoteFemale => Convert( MidlanderMale, MidlanderFemale, MiqoteFemale ),
RoegadynFemale => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale ), RoegadynFemale => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale ),
LalafellFemale => Convert( MidlanderMale, LalafellMale, LalafellFemale ), LalafellFemale => Convert( MidlanderMale, LalafellMale, LalafellFemale ),
AuRaFemale => Convert( MidlanderMale, MidlanderFemale, AuRaFemale ), AuRaFemale => Convert( MidlanderMale, MidlanderFemale, AuRaFemale ),
HrothgarFemale => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale, HrothgarFemale ), HrothgarFemale => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale, HrothgarFemale ),
VieraFemale => Convert( MidlanderMale, MidlanderFemale, VieraFemale ), VieraFemale => Convert( MidlanderMale, MidlanderFemale, VieraFemale ),
MidlanderMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc ), MidlanderMaleNpc => Convert( MidlanderMale, MidlanderMaleNpc ),
HighlanderMaleNpc => Convert( MidlanderMale, HighlanderMale, HighlanderMaleNpc ), HighlanderMaleNpc => Convert( MidlanderMale, HighlanderMale, HighlanderMaleNpc ),
ElezenMaleNpc => Convert( MidlanderMale, ElezenMale, ElezenMaleNpc ), ElezenMaleNpc => Convert( MidlanderMale, ElezenMale, ElezenMaleNpc ),
MiqoteMaleNpc => Convert( MidlanderMale, MiqoteMale, MiqoteMaleNpc ), MiqoteMaleNpc => Convert( MidlanderMale, MiqoteMale, MiqoteMaleNpc ),
RoegadynMaleNpc => Convert( MidlanderMale, RoegadynMale, RoegadynMaleNpc ), RoegadynMaleNpc => Convert( MidlanderMale, RoegadynMale, RoegadynMaleNpc ),
LalafellMaleNpc => Convert( MidlanderMale, LalafellMale, LalafellMaleNpc ), LalafellMaleNpc => Convert( MidlanderMale, LalafellMale, LalafellMaleNpc ),
AuRaMaleNpc => Convert( MidlanderMale, AuRaMale, AuRaMaleNpc ), AuRaMaleNpc => Convert( MidlanderMale, AuRaMale, AuRaMaleNpc ),
HrothgarMaleNpc => Convert( MidlanderMale, RoegadynMale, HrothgarMale, HrothgarMaleNpc ), HrothgarMaleNpc => Convert( MidlanderMale, RoegadynMale, HrothgarMale, HrothgarMaleNpc ),
VieraMaleNpc => Convert( MidlanderMale, VieraMale, VieraMaleNpc ), VieraMaleNpc => Convert( MidlanderMale, VieraMale, VieraMaleNpc ),
MidlanderFemaleNpc => Convert( MidlanderMale, MidlanderFemale, MidlanderFemaleNpc ), MidlanderFemaleNpc => Convert( MidlanderMale, MidlanderFemale, MidlanderFemaleNpc ),
HighlanderFemaleNpc => Convert( MidlanderMale, MidlanderFemale, HighlanderFemale, HighlanderFemaleNpc ), HighlanderFemaleNpc => Convert( MidlanderMale, MidlanderFemale, HighlanderFemale, HighlanderFemaleNpc ),
ElezenFemaleNpc => Convert( MidlanderMale, MidlanderFemale, ElezenFemale, ElezenFemaleNpc ), ElezenFemaleNpc => Convert( MidlanderMale, MidlanderFemale, ElezenFemale, ElezenFemaleNpc ),
MiqoteFemaleNpc => Convert( MidlanderMale, MidlanderFemale, MiqoteFemale, MiqoteFemaleNpc ), MiqoteFemaleNpc => Convert( MidlanderMale, MidlanderFemale, MiqoteFemale, MiqoteFemaleNpc ),
RoegadynFemaleNpc => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale, RoegadynFemaleNpc ), RoegadynFemaleNpc => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale, RoegadynFemaleNpc ),
LalafellFemaleNpc => Convert( MidlanderMale, LalafellMale, LalafellFemale, LalafellFemaleNpc ), LalafellFemaleNpc => Convert( MidlanderMale, LalafellMale, LalafellFemale, LalafellFemaleNpc ),
AuRaFemaleNpc => Convert( MidlanderMale, MidlanderFemale, AuRaFemale, AuRaFemaleNpc ), AuRaFemaleNpc => Convert( MidlanderMale, MidlanderFemale, AuRaFemale, AuRaFemaleNpc ),
HrothgarFemaleNpc => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale, HrothgarFemale, HrothgarFemaleNpc ), HrothgarFemaleNpc => Convert( MidlanderMale, MidlanderFemale, RoegadynFemale, HrothgarFemale, HrothgarFemaleNpc ),
VieraFemaleNpc => Convert( MidlanderMale, MidlanderFemale, VieraFemale, VieraFemaleNpc ), VieraFemaleNpc => Convert( MidlanderMale, MidlanderFemale, VieraFemale, VieraFemaleNpc ),
UnknownMaleNpc => Convert( MidlanderMale, UnknownMaleNpc ), UnknownMaleNpc => Convert( MidlanderMale, UnknownMaleNpc ),
UnknownFemaleNpc => Convert( MidlanderMale, MidlanderFemale, UnknownFemaleNpc ), UnknownFemaleNpc => Convert( MidlanderMale, MidlanderFemale, UnknownFemaleNpc ),
_ => DisposableContainer.Empty, _ => DisposableContainer.Empty,
}; };
} }
} }
} }

View file

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using OtterGui;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
@ -83,17 +84,14 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
} }
_manipulations[ manip ] = mod; _manipulations[ manip ] = mod;
// Imc manipulations do not require character utility.
if( manip.ManipulationType == MetaManipulation.Type.Imc )
{
return ApplyMod( manip.Imc );
}
if( !Penumbra.CharacterUtility.Ready ) if( !Penumbra.CharacterUtility.Ready )
{ {
return true; return true;
} }
// Imc manipulations do not require character utility,
// but they do require the file space to be ready.
return manip.ManipulationType switch return manip.ManipulationType switch
{ {
MetaManipulation.Type.Eqp => ApplyMod( manip.Eqp ), MetaManipulation.Type.Eqp => ApplyMod( manip.Eqp ),
@ -101,6 +99,7 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ), MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ),
MetaManipulation.Type.Est => ApplyMod( manip.Est ), MetaManipulation.Type.Est => ApplyMod( manip.Est ),
MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ), MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ),
MetaManipulation.Type.Imc => ApplyMod( manip.Imc ),
MetaManipulation.Type.Unknown => false, MetaManipulation.Type.Unknown => false,
_ => false, _ => false,
}; };
@ -109,17 +108,13 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
public bool RevertMod( MetaManipulation manip ) public bool RevertMod( MetaManipulation manip )
{ {
var ret = _manipulations.Remove( manip ); var ret = _manipulations.Remove( manip );
// Imc manipulations do not require character utility.
if( manip.ManipulationType == MetaManipulation.Type.Imc )
{
return RevertMod( manip.Imc );
}
if( !Penumbra.CharacterUtility.Ready ) if( !Penumbra.CharacterUtility.Ready )
{ {
return ret; return ret;
} }
// Imc manipulations do not require character utility,
// but they do require the file space to be ready.
return manip.ManipulationType switch return manip.ManipulationType switch
{ {
MetaManipulation.Type.Eqp => RevertMod( manip.Eqp ), MetaManipulation.Type.Eqp => RevertMod( manip.Eqp ),
@ -127,6 +122,7 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
MetaManipulation.Type.Eqdp => RevertMod( manip.Eqdp ), MetaManipulation.Type.Eqdp => RevertMod( manip.Eqdp ),
MetaManipulation.Type.Est => RevertMod( manip.Est ), MetaManipulation.Type.Est => RevertMod( manip.Est ),
MetaManipulation.Type.Rsp => RevertMod( manip.Rsp ), MetaManipulation.Type.Rsp => RevertMod( manip.Rsp ),
MetaManipulation.Type.Imc => RevertMod( manip.Imc ),
MetaManipulation.Type.Unknown => false, MetaManipulation.Type.Unknown => false,
_ => false, _ => false,
}; };
@ -150,6 +146,7 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ), MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ),
MetaManipulation.Type.Est => ApplyMod( manip.Est ), MetaManipulation.Type.Est => ApplyMod( manip.Est ),
MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ), MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ),
MetaManipulation.Type.Imc => ApplyMod( manip.Imc ),
MetaManipulation.Type.Unknown => false, MetaManipulation.Type.Unknown => false,
_ => false, _ => false,
} }
@ -167,6 +164,42 @@ public partial class MetaManager : IDisposable, IEnumerable< KeyValuePair< MetaM
Penumbra.Log.Debug( $"{_collection.AnonymizedName}: Loaded {loaded} delayed meta manipulations." ); Penumbra.Log.Debug( $"{_collection.AnonymizedName}: Loaded {loaded} delayed meta manipulations." );
} }
public void SetFile( CharacterUtility.Index index )
{
switch( index )
{
case CharacterUtility.Index.Eqp:
SetFile( _eqpFile, index );
break;
case CharacterUtility.Index.Gmp:
SetFile( _gmpFile, index );
break;
case CharacterUtility.Index.HumanCmp:
SetFile( _cmpFile, index );
break;
case CharacterUtility.Index.FaceEst:
SetFile( _estFaceFile, index );
break;
case CharacterUtility.Index.HairEst:
SetFile( _estHairFile, index );
break;
case CharacterUtility.Index.HeadEst:
SetFile( _estHeadFile, index );
break;
case CharacterUtility.Index.BodyEst:
SetFile( _estBodyFile, index );
break;
default:
var i = CharacterUtility.EqdpIndices.IndexOf( index );
if( i != -1 )
{
SetFile( _eqdpFiles[ i ], index );
}
break;
}
}
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )] [MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
private static unsafe void SetFile( MetaBaseFile? file, CharacterUtility.Index index ) private static unsafe void SetFile( MetaBaseFile? file, CharacterUtility.Index index )
{ {

View file

@ -94,6 +94,7 @@ public class Penumbra : IDalamudPlugin
ModManager = new Mod.Manager( Config.ModDirectory ); ModManager = new Mod.Manager( Config.ModDirectory );
ModManager.DiscoverMods(); ModManager.DiscoverMods();
CollectionManager = new ModCollection.Manager( ModManager ); CollectionManager = new ModCollection.Manager( ModManager );
CollectionManager.CreateNecessaryCaches();
ModFileSystem = ModFileSystem.Load(); ModFileSystem = ModFileSystem.Load();
ObjectReloader = new ObjectReloader(); ObjectReloader = new ObjectReloader();
PathResolver = new PathResolver( ResourceLoader ); PathResolver = new PathResolver( ResourceLoader );