mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-30 20:33:43 +01:00
Change most things to new byte strings, introduce new ResourceLoader and Logger fully.
This commit is contained in:
parent
5d77cd5514
commit
f5fccb0235
55 changed files with 2681 additions and 2730 deletions
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Logging;
|
||||
using Penumbra.Interop;
|
||||
using Penumbra.Mod;
|
||||
using Penumbra.Util;
|
||||
|
||||
|
|
@ -250,16 +249,16 @@ public class CollectionManager
|
|||
|
||||
public bool CreateCharacterCollection( string characterName )
|
||||
{
|
||||
if( !CharacterCollection.ContainsKey( characterName ) )
|
||||
if( CharacterCollection.ContainsKey( characterName ) )
|
||||
{
|
||||
CharacterCollection[ characterName ] = ModCollection.Empty;
|
||||
Penumbra.Config.CharacterCollections[ characterName ] = string.Empty;
|
||||
Penumbra.Config.Save();
|
||||
Penumbra.PlayerWatcher.AddPlayerToWatch( characterName );
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
CharacterCollection[ characterName ] = ModCollection.Empty;
|
||||
Penumbra.Config.CharacterCollections[ characterName ] = string.Empty;
|
||||
Penumbra.Config.Save();
|
||||
Penumbra.PlayerWatcher.AddPlayerToWatch( characterName );
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveCharacterCollection( string characterName )
|
||||
|
|
@ -299,7 +298,7 @@ public class CollectionManager
|
|||
|
||||
private bool LoadForcedCollection( Configuration config )
|
||||
{
|
||||
if( config.ForcedCollection == string.Empty )
|
||||
if( config.ForcedCollection.Length == 0 )
|
||||
{
|
||||
ForcedCollection = ModCollection.Empty;
|
||||
return false;
|
||||
|
|
@ -320,7 +319,7 @@ public class CollectionManager
|
|||
|
||||
private bool LoadDefaultCollection( Configuration config )
|
||||
{
|
||||
if( config.DefaultCollection == string.Empty )
|
||||
if( config.DefaultCollection.Length == 0 )
|
||||
{
|
||||
DefaultCollection = ModCollection.Empty;
|
||||
return false;
|
||||
|
|
@ -345,7 +344,7 @@ public class CollectionManager
|
|||
foreach( var (player, collectionName) in config.CharacterCollections.ToArray() )
|
||||
{
|
||||
Penumbra.PlayerWatcher.AddPlayerToWatch( player );
|
||||
if( collectionName == string.Empty )
|
||||
if( collectionName.Length == 0 )
|
||||
{
|
||||
CharacterCollection.Add( player, ModCollection.Empty );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,255 +1,256 @@
|
|||
using Dalamud.Plugin;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Logging;
|
||||
using Penumbra.GameData.ByteString;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Interop;
|
||||
using Penumbra.Mod;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Mods
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
// A ModCollection is a named set of ModSettings to all of the users' installed mods.
|
||||
// It is meant to be local only, and thus should always contain settings for every mod, not just the enabled ones.
|
||||
// Settings to mods that are not installed anymore are kept as long as no call to CleanUnavailableSettings is made.
|
||||
// Active ModCollections build a cache of currently relevant data.
|
||||
public class ModCollection
|
||||
{
|
||||
// A ModCollection is a named set of ModSettings to all of the users' installed mods.
|
||||
// It is meant to be local only, and thus should always contain settings for every mod, not just the enabled ones.
|
||||
// Settings to mods that are not installed anymore are kept as long as no call to CleanUnavailableSettings is made.
|
||||
// Active ModCollections build a cache of currently relevant data.
|
||||
public class ModCollection
|
||||
public const string DefaultCollection = "Default";
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public Dictionary< string, ModSettings > Settings { get; }
|
||||
|
||||
public ModCollection()
|
||||
{
|
||||
public const string DefaultCollection = "Default";
|
||||
Name = DefaultCollection;
|
||||
Settings = new Dictionary< string, ModSettings >();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public ModCollection( string name, Dictionary< string, ModSettings > settings )
|
||||
{
|
||||
Name = name;
|
||||
Settings = settings.ToDictionary( kvp => kvp.Key, kvp => kvp.Value.DeepCopy() );
|
||||
}
|
||||
|
||||
public Dictionary< string, ModSettings > Settings { get; }
|
||||
|
||||
public ModCollection()
|
||||
public Mod.Mod GetMod( ModData mod )
|
||||
{
|
||||
if( Cache != null && Cache.AvailableMods.TryGetValue( mod.BasePath.Name, out var ret ) )
|
||||
{
|
||||
Name = DefaultCollection;
|
||||
Settings = new Dictionary< string, ModSettings >();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ModCollection( string name, Dictionary< string, ModSettings > settings )
|
||||
if( Settings.TryGetValue( mod.BasePath.Name, out var settings ) )
|
||||
{
|
||||
Name = name;
|
||||
Settings = settings.ToDictionary( kvp => kvp.Key, kvp => kvp.Value.DeepCopy() );
|
||||
return new Mod.Mod( settings, mod );
|
||||
}
|
||||
|
||||
public Mod.Mod GetMod( ModData mod )
|
||||
{
|
||||
if( Cache != null && Cache.AvailableMods.TryGetValue( mod.BasePath.Name, out var ret ) )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
var newSettings = ModSettings.DefaultSettings( mod.Meta );
|
||||
Settings.Add( mod.BasePath.Name, newSettings );
|
||||
Save();
|
||||
return new Mod.Mod( newSettings, mod );
|
||||
}
|
||||
|
||||
private bool CleanUnavailableSettings( Dictionary< string, ModData > data )
|
||||
{
|
||||
var removeList = Settings.Where( settingKvp => !data.ContainsKey( settingKvp.Key ) ).ToArray();
|
||||
|
||||
foreach( var s in removeList )
|
||||
{
|
||||
Settings.Remove( s.Key );
|
||||
}
|
||||
|
||||
return removeList.Length > 0;
|
||||
}
|
||||
|
||||
public void CreateCache( DirectoryInfo modDirectory, IEnumerable< ModData > data )
|
||||
{
|
||||
Cache = new ModCollectionCache( Name, modDirectory );
|
||||
var changedSettings = false;
|
||||
foreach( var mod in data )
|
||||
{
|
||||
if( Settings.TryGetValue( mod.BasePath.Name, out var settings ) )
|
||||
{
|
||||
return new Mod.Mod( settings, mod );
|
||||
Cache.AddMod( settings, mod, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
changedSettings = true;
|
||||
var newSettings = ModSettings.DefaultSettings( mod.Meta );
|
||||
Settings.Add( mod.BasePath.Name, newSettings );
|
||||
Cache.AddMod( newSettings, mod, false );
|
||||
}
|
||||
}
|
||||
|
||||
var newSettings = ModSettings.DefaultSettings( mod.Meta );
|
||||
Settings.Add( mod.BasePath.Name, newSettings );
|
||||
if( changedSettings )
|
||||
{
|
||||
Save();
|
||||
return new Mod.Mod( newSettings, mod );
|
||||
}
|
||||
|
||||
private bool CleanUnavailableSettings( Dictionary< string, ModData > data )
|
||||
CalculateEffectiveFileList( modDirectory, true, false );
|
||||
}
|
||||
|
||||
public void ClearCache()
|
||||
=> Cache = null;
|
||||
|
||||
public void UpdateSetting( DirectoryInfo modPath, ModMeta meta, bool clear )
|
||||
{
|
||||
if( !Settings.TryGetValue( modPath.Name, out var settings ) )
|
||||
{
|
||||
var removeList = Settings.Where( settingKvp => !data.ContainsKey( settingKvp.Key ) ).ToArray();
|
||||
|
||||
foreach( var s in removeList )
|
||||
{
|
||||
Settings.Remove( s.Key );
|
||||
}
|
||||
|
||||
return removeList.Length > 0;
|
||||
return;
|
||||
}
|
||||
|
||||
public void CreateCache( DirectoryInfo modDirectory, IEnumerable< ModData > data )
|
||||
if( clear )
|
||||
{
|
||||
Cache = new ModCollectionCache( Name, modDirectory );
|
||||
var changedSettings = false;
|
||||
foreach( var mod in data )
|
||||
{
|
||||
if( Settings.TryGetValue( mod.BasePath.Name, out var settings ) )
|
||||
{
|
||||
Cache.AddMod( settings, mod, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
changedSettings = true;
|
||||
var newSettings = ModSettings.DefaultSettings( mod.Meta );
|
||||
Settings.Add( mod.BasePath.Name, newSettings );
|
||||
Cache.AddMod( newSettings, mod, false );
|
||||
}
|
||||
}
|
||||
|
||||
if( changedSettings )
|
||||
{
|
||||
Save();
|
||||
}
|
||||
|
||||
CalculateEffectiveFileList( modDirectory, true, false );
|
||||
settings.Settings.Clear();
|
||||
}
|
||||
|
||||
public void ClearCache()
|
||||
=> Cache = null;
|
||||
|
||||
public void UpdateSetting( DirectoryInfo modPath, ModMeta meta, bool clear )
|
||||
if( settings.FixInvalidSettings( meta ) )
|
||||
{
|
||||
if( !Settings.TryGetValue( modPath.Name, out var settings ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
if (clear)
|
||||
settings.Settings.Clear();
|
||||
if( settings.FixInvalidSettings( meta ) )
|
||||
{
|
||||
Save();
|
||||
}
|
||||
public void UpdateSetting( ModData mod )
|
||||
=> UpdateSetting( mod.BasePath, mod.Meta, false );
|
||||
|
||||
public void UpdateSettings( bool forceSave )
|
||||
{
|
||||
if( Cache == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void UpdateSetting( ModData mod )
|
||||
=> UpdateSetting( mod.BasePath, mod.Meta, false );
|
||||
|
||||
public void UpdateSettings( bool forceSave )
|
||||
var changes = false;
|
||||
foreach( var mod in Cache.AvailableMods.Values )
|
||||
{
|
||||
if( Cache == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var changes = false;
|
||||
foreach( var mod in Cache.AvailableMods.Values )
|
||||
{
|
||||
changes |= mod.FixSettings();
|
||||
}
|
||||
|
||||
if( forceSave || changes )
|
||||
{
|
||||
Save();
|
||||
}
|
||||
changes |= mod.FixSettings();
|
||||
}
|
||||
|
||||
public void CalculateEffectiveFileList( DirectoryInfo modDir, bool withMetaManipulations, bool activeCollection )
|
||||
if( forceSave || changes )
|
||||
{
|
||||
PluginLog.Debug( "Recalculating effective file list for {CollectionName} [{WithMetaManipulations}] [{IsActiveCollection}]", Name,
|
||||
withMetaManipulations, activeCollection );
|
||||
Cache ??= new ModCollectionCache( Name, modDir );
|
||||
UpdateSettings( false );
|
||||
Cache.CalculateEffectiveFileList();
|
||||
if( withMetaManipulations )
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public void CalculateEffectiveFileList( DirectoryInfo modDir, bool withMetaManipulations, bool activeCollection )
|
||||
{
|
||||
PluginLog.Debug( "Recalculating effective file list for {CollectionName} [{WithMetaManipulations}] [{IsActiveCollection}]", Name,
|
||||
withMetaManipulations, activeCollection );
|
||||
Cache ??= new ModCollectionCache( Name, modDir );
|
||||
UpdateSettings( false );
|
||||
Cache.CalculateEffectiveFileList();
|
||||
if( withMetaManipulations )
|
||||
{
|
||||
Cache.UpdateMetaManipulations();
|
||||
if( activeCollection )
|
||||
{
|
||||
Cache.UpdateMetaManipulations();
|
||||
if( activeCollection )
|
||||
{
|
||||
Penumbra.ResidentResources.Reload();
|
||||
}
|
||||
Penumbra.ResidentResources.Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public ModCollectionCache? Cache { get; private set; }
|
||||
[JsonIgnore]
|
||||
public ModCollectionCache? Cache { get; private set; }
|
||||
|
||||
public static ModCollection? LoadFromFile( FileInfo file )
|
||||
public static ModCollection? LoadFromFile( FileInfo file )
|
||||
{
|
||||
if( !file.Exists )
|
||||
{
|
||||
if( !file.Exists )
|
||||
{
|
||||
PluginLog.Error( $"Could not read collection because {file.FullName} does not exist." );
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var collection = JsonConvert.DeserializeObject< ModCollection >( File.ReadAllText( file.FullName ) );
|
||||
return collection;
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not read collection information from {file.FullName}:\n{e}" );
|
||||
}
|
||||
|
||||
PluginLog.Error( $"Could not read collection because {file.FullName} does not exist." );
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SaveToFile( FileInfo file )
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText( file.FullName, JsonConvert.SerializeObject( this, Formatting.Indented ) );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not write collection {Name} to {file.FullName}:\n{e}" );
|
||||
}
|
||||
var collection = JsonConvert.DeserializeObject< ModCollection >( File.ReadAllText( file.FullName ) );
|
||||
return collection;
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not read collection information from {file.FullName}:\n{e}" );
|
||||
}
|
||||
|
||||
public static DirectoryInfo CollectionDir()
|
||||
=> new( Path.Combine( Dalamud.PluginInterface.GetPluginConfigDirectory(), "collections" ) );
|
||||
|
||||
private static FileInfo FileName( DirectoryInfo collectionDir, string name )
|
||||
=> new( Path.Combine( collectionDir.FullName, $"{name.RemoveInvalidPathSymbols()}.json" ) );
|
||||
|
||||
public FileInfo FileName()
|
||||
=> new( Path.Combine( Dalamud.PluginInterface.GetPluginConfigDirectory(),
|
||||
$"{Name.RemoveInvalidPathSymbols()}.json" ) );
|
||||
|
||||
public void Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
var dir = CollectionDir();
|
||||
dir.Create();
|
||||
var file = FileName( dir, Name );
|
||||
SaveToFile( file );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not save collection {Name}:\n{e}" );
|
||||
}
|
||||
}
|
||||
|
||||
public static ModCollection? Load( string name )
|
||||
{
|
||||
var file = FileName( CollectionDir(), name );
|
||||
return file.Exists ? LoadFromFile( file ) : null;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
var file = FileName( CollectionDir(), Name );
|
||||
if( file.Exists )
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not delete collection file {file} for {Name}:\n{e}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMod( ModData data )
|
||||
{
|
||||
if( Cache == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Cache.AddMod( Settings.TryGetValue( data.BasePath.Name, out var settings )
|
||||
? settings
|
||||
: ModSettings.DefaultSettings( data.Meta ),
|
||||
data );
|
||||
}
|
||||
|
||||
public string? ResolveSwappedOrReplacementPath( GamePath gameResourcePath )
|
||||
=> Cache?.ResolveSwappedOrReplacementPath( gameResourcePath );
|
||||
|
||||
public static readonly ModCollection Empty = new() { Name = "" };
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SaveToFile( FileInfo file )
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText( file.FullName, JsonConvert.SerializeObject( this, Formatting.Indented ) );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not write collection {Name} to {file.FullName}:\n{e}" );
|
||||
}
|
||||
}
|
||||
|
||||
public static DirectoryInfo CollectionDir()
|
||||
=> new(Path.Combine( Dalamud.PluginInterface.GetPluginConfigDirectory(), "collections" ));
|
||||
|
||||
private static FileInfo FileName( DirectoryInfo collectionDir, string name )
|
||||
=> new(Path.Combine( collectionDir.FullName, $"{name.RemoveInvalidPathSymbols()}.json" ));
|
||||
|
||||
public FileInfo FileName()
|
||||
=> new(Path.Combine( Dalamud.PluginInterface.GetPluginConfigDirectory(),
|
||||
$"{Name.RemoveInvalidPathSymbols()}.json" ));
|
||||
|
||||
public void Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
var dir = CollectionDir();
|
||||
dir.Create();
|
||||
var file = FileName( dir, Name );
|
||||
SaveToFile( file );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not save collection {Name}:\n{e}" );
|
||||
}
|
||||
}
|
||||
|
||||
public static ModCollection? Load( string name )
|
||||
{
|
||||
var file = FileName( CollectionDir(), name );
|
||||
return file.Exists ? LoadFromFile( file ) : null;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
var file = FileName( CollectionDir(), Name );
|
||||
if( file.Exists )
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"Could not delete collection file {file} for {Name}:\n{e}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMod( ModData data )
|
||||
{
|
||||
if( Cache == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Cache.AddMod( Settings.TryGetValue( data.BasePath.Name, out var settings )
|
||||
? settings
|
||||
: ModSettings.DefaultSettings( data.Meta ),
|
||||
data );
|
||||
}
|
||||
|
||||
public FullPath? ResolveSwappedOrReplacementPath( Utf8GamePath gameResourcePath )
|
||||
=> Cache?.ResolveSwappedOrReplacementPath( gameResourcePath );
|
||||
|
||||
public static readonly ModCollection Empty = new() { Name = "" };
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ using Penumbra.GameData.ByteString;
|
|||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Meta;
|
||||
using Penumbra.Mod;
|
||||
using Penumbra.Structs;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Mods;
|
||||
|
|
@ -20,17 +19,16 @@ namespace Penumbra.Mods;
|
|||
public class ModCollectionCache
|
||||
{
|
||||
// Shared caches to avoid allocations.
|
||||
private static readonly BitArray FileSeen = new(256);
|
||||
private static readonly Dictionary< GamePath, Mod.Mod > RegisteredFiles = new(256);
|
||||
private static readonly BitArray FileSeen = new(256);
|
||||
private static readonly Dictionary< Utf8GamePath, Mod.Mod > RegisteredFiles = new(256);
|
||||
|
||||
public readonly Dictionary< string, Mod.Mod > AvailableMods = new();
|
||||
|
||||
private readonly SortedList< string, object? > _changedItems = new();
|
||||
public readonly Dictionary< GamePath, FullPath > ResolvedFiles = new();
|
||||
public readonly Dictionary< GamePath, GamePath > SwappedFiles = new();
|
||||
public readonly HashSet< FullPath > MissingFiles = new();
|
||||
public readonly HashSet< ulong > Checksums = new();
|
||||
public readonly MetaManager MetaManipulations;
|
||||
private readonly SortedList< string, object? > _changedItems = new();
|
||||
public readonly Dictionary< Utf8GamePath, FullPath > ResolvedFiles = new();
|
||||
public readonly HashSet< FullPath > MissingFiles = new();
|
||||
public readonly HashSet< ulong > Checksums = new();
|
||||
public readonly MetaManager MetaManipulations;
|
||||
|
||||
public IReadOnlyDictionary< string, object? > ChangedItems
|
||||
{
|
||||
|
|
@ -61,7 +59,6 @@ public class ModCollectionCache
|
|||
public void CalculateEffectiveFileList()
|
||||
{
|
||||
ResolvedFiles.Clear();
|
||||
SwappedFiles.Clear();
|
||||
MissingFiles.Clear();
|
||||
RegisteredFiles.Clear();
|
||||
_changedItems.Clear();
|
||||
|
|
@ -85,7 +82,7 @@ public class ModCollectionCache
|
|||
|
||||
private void SetChangedItems()
|
||||
{
|
||||
if( _changedItems.Count > 0 || ResolvedFiles.Count + SwappedFiles.Count + MetaManipulations.Count == 0 )
|
||||
if( _changedItems.Count > 0 || ResolvedFiles.Count + MetaManipulations.Count == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -98,12 +95,7 @@ public class ModCollectionCache
|
|||
var identifier = GameData.GameData.GetIdentifier();
|
||||
foreach( var resolved in ResolvedFiles.Keys.Where( file => !metaFiles.Contains( file ) ) )
|
||||
{
|
||||
identifier.Identify( _changedItems, resolved );
|
||||
}
|
||||
|
||||
foreach( var swapped in SwappedFiles.Keys )
|
||||
{
|
||||
identifier.Identify( _changedItems, swapped );
|
||||
identifier.Identify( _changedItems, resolved.ToGamePath() );
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
|
|
@ -134,12 +126,12 @@ public class ModCollectionCache
|
|||
AddRemainingFiles( mod );
|
||||
}
|
||||
|
||||
private bool FilterFile( GamePath gamePath )
|
||||
private static bool FilterFile( Utf8GamePath gamePath )
|
||||
{
|
||||
// If audio streaming is not disabled, replacing .scd files crashes the game,
|
||||
// so only add those files if it is disabled.
|
||||
if( !Penumbra.Config.DisableSoundStreaming
|
||||
&& gamePath.ToString().EndsWith( ".scd", StringComparison.InvariantCultureIgnoreCase ) )
|
||||
&& gamePath.Path.EndsWith( '.', 's', 'c', 'd' ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -148,7 +140,7 @@ public class ModCollectionCache
|
|||
}
|
||||
|
||||
|
||||
private void AddFile( Mod.Mod mod, GamePath gamePath, FullPath file )
|
||||
private void AddFile( Mod.Mod mod, Utf8GamePath gamePath, FullPath file )
|
||||
{
|
||||
if( FilterFile( gamePath ) )
|
||||
{
|
||||
|
|
@ -187,9 +179,8 @@ public class ModCollectionCache
|
|||
{
|
||||
foreach( var (file, paths) in option.OptionFiles )
|
||||
{
|
||||
var fullPath = new FullPath( mod.Data.BasePath,
|
||||
NewRelPath.FromString( file.ToString(), out var p ) ? p : NewRelPath.Empty ); // TODO
|
||||
var idx = mod.Data.Resources.ModFiles.IndexOf( f => f.Equals( fullPath ) );
|
||||
var fullPath = new FullPath( mod.Data.BasePath, file );
|
||||
var idx = mod.Data.Resources.ModFiles.IndexOf( f => f.Equals( fullPath ) );
|
||||
if( idx < 0 )
|
||||
{
|
||||
AddMissingFile( fullPath );
|
||||
|
|
@ -259,7 +250,7 @@ public class ModCollectionCache
|
|||
{
|
||||
if( file.ToGamePath( mod.Data.BasePath, out var gamePath ) )
|
||||
{
|
||||
AddFile( mod, new GamePath( gamePath.ToString() ), file ); // TODO
|
||||
AddFile( mod, gamePath, file );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -294,7 +285,7 @@ public class ModCollectionCache
|
|||
if( !RegisteredFiles.TryGetValue( key, out var oldMod ) )
|
||||
{
|
||||
RegisteredFiles.Add( key, mod );
|
||||
SwappedFiles.Add( key, value );
|
||||
ResolvedFiles.Add( key, value );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -341,54 +332,54 @@ public class ModCollectionCache
|
|||
|
||||
public void RemoveMod( DirectoryInfo basePath )
|
||||
{
|
||||
if( AvailableMods.TryGetValue( basePath.Name, out var mod ) )
|
||||
if( !AvailableMods.TryGetValue( basePath.Name, out var mod ) )
|
||||
{
|
||||
AvailableMods.Remove( basePath.Name );
|
||||
if( mod.Settings.Enabled )
|
||||
{
|
||||
CalculateEffectiveFileList();
|
||||
if( mod.Data.Resources.MetaManipulations.Count > 0 )
|
||||
{
|
||||
UpdateMetaManipulations();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
AvailableMods.Remove( basePath.Name );
|
||||
if( !mod.Settings.Enabled )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateEffectiveFileList();
|
||||
if( mod.Data.Resources.MetaManipulations.Count > 0 )
|
||||
{
|
||||
UpdateMetaManipulations();
|
||||
}
|
||||
}
|
||||
|
||||
private class PriorityComparer : IComparer< Mod.Mod >
|
||||
{
|
||||
public int Compare( Mod.Mod? x, Mod.Mod? y )
|
||||
=> ( x?.Settings.Priority ?? 0 ).CompareTo( y?.Settings.Priority ?? 0 );
|
||||
}
|
||||
|
||||
private static readonly PriorityComparer Comparer = new();
|
||||
|
||||
public void AddMod( ModSettings settings, ModData data, bool updateFileList = true )
|
||||
{
|
||||
if( !AvailableMods.TryGetValue( data.BasePath.Name, out var existingMod ) )
|
||||
if( AvailableMods.ContainsKey( data.BasePath.Name ) )
|
||||
{
|
||||
var newMod = new Mod.Mod( settings, data );
|
||||
AvailableMods[ data.BasePath.Name ] = newMod;
|
||||
return;
|
||||
}
|
||||
|
||||
if( updateFileList && settings.Enabled )
|
||||
{
|
||||
CalculateEffectiveFileList();
|
||||
if( data.Resources.MetaManipulations.Count > 0 )
|
||||
{
|
||||
UpdateMetaManipulations();
|
||||
}
|
||||
}
|
||||
AvailableMods[ data.BasePath.Name ] = new Mod.Mod( settings, data );
|
||||
|
||||
if( !updateFileList || !settings.Enabled )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateEffectiveFileList();
|
||||
if( data.Resources.MetaManipulations.Count > 0 )
|
||||
{
|
||||
UpdateMetaManipulations();
|
||||
}
|
||||
}
|
||||
|
||||
public FullPath? GetCandidateForGameFile( GamePath gameResourcePath )
|
||||
public FullPath? GetCandidateForGameFile( Utf8GamePath gameResourcePath )
|
||||
{
|
||||
if( !ResolvedFiles.TryGetValue( gameResourcePath, out var candidate ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if( candidate.FullName.Length >= 260 || !candidate.Exists )
|
||||
if( candidate.InternalName.Length > Utf8GamePath.MaxGamePathLength
|
||||
|| candidate.IsRooted && !candidate.Exists )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
@ -396,9 +387,6 @@ public class ModCollectionCache
|
|||
return candidate;
|
||||
}
|
||||
|
||||
public GamePath? GetSwappedFilePath( GamePath gameResourcePath )
|
||||
=> SwappedFiles.TryGetValue( gameResourcePath, out var swappedPath ) ? swappedPath : null;
|
||||
|
||||
public string? ResolveSwappedOrReplacementPath( GamePath gameResourcePath )
|
||||
=> GetCandidateForGameFile( gameResourcePath )?.FullName.Replace( '\\', '/' ) ?? GetSwappedFilePath( gameResourcePath ) ?? null;
|
||||
public FullPath? ResolveSwappedOrReplacementPath( Utf8GamePath gameResourcePath )
|
||||
=> GetCandidateForGameFile( gameResourcePath );
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Logging;
|
||||
using Penumbra.GameData.ByteString;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Meta;
|
||||
using Penumbra.Mod;
|
||||
|
|
@ -347,15 +348,7 @@ namespace Penumbra.Mods
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool CheckCrc64( ulong crc )
|
||||
{
|
||||
if( Collections.ActiveCollection.Cache?.Checksums.Contains( crc ) ?? false )
|
||||
return true;
|
||||
|
||||
return Collections.ForcedCollection.Cache?.Checksums.Contains( crc ) ?? false;
|
||||
}
|
||||
|
||||
public string? ResolveSwappedOrReplacementPath( GamePath gameResourcePath )
|
||||
public FullPath? ResolveSwappedOrReplacementPath( Utf8GamePath gameResourcePath )
|
||||
{
|
||||
var ret = Collections.ActiveCollection.ResolveSwappedOrReplacementPath( gameResourcePath );
|
||||
ret ??= Collections.ForcedCollection.ResolveSwappedOrReplacementPath( gameResourcePath );
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.ComponentModel;
|
|||
using System.IO;
|
||||
using Dalamud.Logging;
|
||||
using Penumbra.Mod;
|
||||
using Penumbra.Structs;
|
||||
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue