mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Add support for the DalamudSubstitutionProvider for textures.
This commit is contained in:
parent
cf3810a1b8
commit
04b76ddee1
10 changed files with 285 additions and 66 deletions
|
|
@ -1,7 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
|
using Penumbra.Communication;
|
||||||
|
using Penumbra.Mods;
|
||||||
|
using Penumbra.Services;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
|
using static Penumbra.Api.Ipc;
|
||||||
|
|
||||||
namespace Penumbra.Api;
|
namespace Penumbra.Api;
|
||||||
|
|
||||||
|
|
@ -9,19 +16,109 @@ public class DalamudSubstitutionProvider : IDisposable
|
||||||
{
|
{
|
||||||
private readonly ITextureSubstitutionProvider _substitution;
|
private readonly ITextureSubstitutionProvider _substitution;
|
||||||
private readonly ActiveCollectionData _activeCollectionData;
|
private readonly ActiveCollectionData _activeCollectionData;
|
||||||
|
private readonly Configuration _config;
|
||||||
|
private readonly CommunicatorService _communicator;
|
||||||
|
|
||||||
public DalamudSubstitutionProvider(ITextureSubstitutionProvider substitution, ActiveCollectionData activeCollectionData)
|
public bool Enabled
|
||||||
|
=> _config.UseDalamudUiTextureRedirection;
|
||||||
|
|
||||||
|
public DalamudSubstitutionProvider(ITextureSubstitutionProvider substitution, ActiveCollectionData activeCollectionData,
|
||||||
|
Configuration config, CommunicatorService communicator)
|
||||||
{
|
{
|
||||||
_substitution = substitution;
|
_substitution = substitution;
|
||||||
_activeCollectionData = activeCollectionData;
|
_activeCollectionData = activeCollectionData;
|
||||||
_substitution.InterceptTexDataLoad += Substitute;
|
_config = config;
|
||||||
|
_communicator = communicator;
|
||||||
|
if (Enabled)
|
||||||
|
Subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(bool value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
Enable();
|
||||||
|
else
|
||||||
|
Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetSubstitutions(IEnumerable<Utf8GamePath> paths)
|
||||||
|
{
|
||||||
|
var transformed = paths
|
||||||
|
.Where(p => (p.Path.StartsWith("ui/"u8) || p.Path.StartsWith("common/font/"u8)) && p.Path.EndsWith(".tex"u8))
|
||||||
|
.Select(p => p.ToString());
|
||||||
|
_substitution.InvalidatePaths(transformed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enable()
|
||||||
|
{
|
||||||
|
if (Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_config.UseDalamudUiTextureRedirection = true;
|
||||||
|
_config.Save();
|
||||||
|
Subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disable()
|
||||||
|
{
|
||||||
|
if (!Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Unsubscribe();
|
||||||
|
_config.UseDalamudUiTextureRedirection = false;
|
||||||
|
_config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
=> _substitution.InterceptTexDataLoad -= Substitute;
|
=> Unsubscribe();
|
||||||
|
|
||||||
|
private void OnCollectionChange(CollectionType type, ModCollection? oldCollection, ModCollection? newCollection, string _)
|
||||||
|
{
|
||||||
|
if (type is not CollectionType.Interface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var enumerable = oldCollection?.ResolvedFiles.Keys ?? Array.Empty<Utf8GamePath>().AsEnumerable();
|
||||||
|
enumerable = enumerable.Concat(newCollection?.ResolvedFiles.Keys ?? Array.Empty<Utf8GamePath>().AsEnumerable());
|
||||||
|
ResetSubstitutions(enumerable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnResolvedFileChange(ModCollection collection, ResolvedFileChanged.Type type, Utf8GamePath key, FullPath _1, FullPath _2,
|
||||||
|
IMod? _3)
|
||||||
|
{
|
||||||
|
if (_activeCollectionData.Interface != collection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ResolvedFileChanged.Type.Added:
|
||||||
|
case ResolvedFileChanged.Type.Removed:
|
||||||
|
case ResolvedFileChanged.Type.Replaced:
|
||||||
|
ResetSubstitutions(new[]
|
||||||
|
{
|
||||||
|
key,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case ResolvedFileChanged.Type.FullRecomputeStart:
|
||||||
|
case ResolvedFileChanged.Type.FullRecomputeFinished:
|
||||||
|
ResetSubstitutions(collection.ResolvedFiles.Keys);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnabledChange(bool state)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
OnCollectionChange(CollectionType.Interface, null, _activeCollectionData.Interface, string.Empty);
|
||||||
|
else
|
||||||
|
OnCollectionChange(CollectionType.Interface, _activeCollectionData.Interface, null, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
private void Substitute(string path, ref string? replacementPath)
|
private void Substitute(string path, ref string? replacementPath)
|
||||||
{
|
{
|
||||||
|
// Do not replace when not enabled.
|
||||||
|
if (!_config.EnableMods)
|
||||||
|
return;
|
||||||
|
|
||||||
// Let other plugins prioritize replacement paths.
|
// Let other plugins prioritize replacement paths.
|
||||||
if (replacementPath != null)
|
if (replacementPath != null)
|
||||||
return;
|
return;
|
||||||
|
|
@ -43,4 +140,22 @@ public class DalamudSubstitutionProvider : IDisposable
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void Subscribe()
|
||||||
|
{
|
||||||
|
_substitution.InterceptTexDataLoad += Substitute;
|
||||||
|
_communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.DalamudSubstitutionProvider);
|
||||||
|
_communicator.ResolvedFileChanged.Subscribe(OnResolvedFileChange, ResolvedFileChanged.Priority.DalamudSubstitutionProvider);
|
||||||
|
_communicator.EnabledChanged.Subscribe(OnEnabledChange, EnabledChanged.Priority.DalamudSubstitutionProvider);
|
||||||
|
OnCollectionChange(CollectionType.Interface, null, _activeCollectionData.Interface, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Unsubscribe()
|
||||||
|
{
|
||||||
|
_substitution.InterceptTexDataLoad -= Substitute;
|
||||||
|
_communicator.CollectionChange.Unsubscribe(OnCollectionChange);
|
||||||
|
_communicator.ResolvedFileChanged.Unsubscribe(OnResolvedFileChange);
|
||||||
|
_communicator.EnabledChanged.Unsubscribe(OnEnabledChange);
|
||||||
|
OnCollectionChange(CollectionType.Interface, _activeCollectionData.Interface, null, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
|
using Penumbra.Communication;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
|
|
||||||
|
|
@ -34,7 +35,7 @@ public class CollectionCache : IDisposable
|
||||||
public int Calculating = -1;
|
public int Calculating = -1;
|
||||||
|
|
||||||
public string AnonymizedName
|
public string AnonymizedName
|
||||||
=> _collection.AnonymizedName;
|
=> _collection.AnonymizedName;
|
||||||
|
|
||||||
public IEnumerable<SingleArray<ModConflicts>> AllConflicts
|
public IEnumerable<SingleArray<ModConflicts>> AllConflicts
|
||||||
=> _conflicts.Values;
|
=> _conflicts.Values;
|
||||||
|
|
@ -63,9 +64,7 @@ public class CollectionCache : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
=> Meta.Dispose();
|
||||||
Meta.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
~CollectionCache()
|
~CollectionCache()
|
||||||
=> Meta.Dispose();
|
=> Meta.Dispose();
|
||||||
|
|
@ -130,8 +129,8 @@ public class CollectionCache : IDisposable
|
||||||
=> _manager.AddChange(ChangeData.ForcedFile(this, path, fullPath));
|
=> _manager.AddChange(ChangeData.ForcedFile(this, path, fullPath));
|
||||||
|
|
||||||
public void RemovePath(Utf8GamePath path)
|
public void RemovePath(Utf8GamePath path)
|
||||||
=> _manager.AddChange(ChangeData.ForcedFile(this, path, FullPath.Empty));
|
=> _manager.AddChange(ChangeData.ForcedFile(this, path, FullPath.Empty));
|
||||||
|
|
||||||
public void ReloadMod(IMod mod, bool addMetaChanges)
|
public void ReloadMod(IMod mod, bool addMetaChanges)
|
||||||
=> _manager.AddChange(ChangeData.ModReload(this, mod, addMetaChanges));
|
=> _manager.AddChange(ChangeData.ModReload(this, mod, addMetaChanges));
|
||||||
|
|
||||||
|
|
@ -139,8 +138,8 @@ public class CollectionCache : IDisposable
|
||||||
=> _manager.AddChange(ChangeData.ModAddition(this, mod, addMetaChanges));
|
=> _manager.AddChange(ChangeData.ModAddition(this, mod, addMetaChanges));
|
||||||
|
|
||||||
public void RemoveMod(IMod mod, bool addMetaChanges)
|
public void RemoveMod(IMod mod, bool addMetaChanges)
|
||||||
=> _manager.AddChange(ChangeData.ModRemoval(this, mod, addMetaChanges));
|
=> _manager.AddChange(ChangeData.ModRemoval(this, mod, addMetaChanges));
|
||||||
|
|
||||||
/// <summary> Force a file to be resolved to a specific path regardless of conflicts. </summary>
|
/// <summary> Force a file to be resolved to a specific path regardless of conflicts. </summary>
|
||||||
internal void ForceFileSync(Utf8GamePath path, FullPath fullPath)
|
internal void ForceFileSync(Utf8GamePath path, FullPath fullPath)
|
||||||
{
|
{
|
||||||
|
|
@ -148,9 +147,24 @@ public class CollectionCache : IDisposable
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ResolvedFiles.Remove(path, out var modPath))
|
if (ResolvedFiles.Remove(path, out var modPath))
|
||||||
|
{
|
||||||
ModData.RemovePath(modPath.Mod, path);
|
ModData.RemovePath(modPath.Mod, path);
|
||||||
if (fullPath.FullName.Length > 0)
|
if (fullPath.FullName.Length > 0)
|
||||||
|
{
|
||||||
|
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
|
||||||
|
InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Replaced, path, fullPath, modPath.Path,
|
||||||
|
Mod.ForcedFiles);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Removed, path, FullPath.Empty, modPath.Path, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fullPath.FullName.Length > 0)
|
||||||
|
{
|
||||||
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
|
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
|
||||||
|
InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Added, path, fullPath, FullPath.Empty, Mod.ForcedFiles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReloadModSync(IMod mod, bool addMetaChanges)
|
private void ReloadModSync(IMod mod, bool addMetaChanges)
|
||||||
|
|
@ -169,9 +183,14 @@ public class CollectionCache : IDisposable
|
||||||
|
|
||||||
foreach (var path in paths)
|
foreach (var path in paths)
|
||||||
{
|
{
|
||||||
if (ResolvedFiles.Remove(path, out var mp) && mp.Mod != mod)
|
if (ResolvedFiles.Remove(path, out var mp))
|
||||||
Penumbra.Log.Warning(
|
{
|
||||||
$"Invalid mod state, removing {mod.Name} and associated file {path} returned current mod {mp.Mod.Name}.");
|
if (mp.Mod != mod)
|
||||||
|
Penumbra.Log.Warning(
|
||||||
|
$"Invalid mod state, removing {mod.Name} and associated file {path} returned current mod {mp.Mod.Name}.");
|
||||||
|
else
|
||||||
|
_manager.ResolvedFileChanged.Invoke(_collection, ResolvedFileChanged.Type.Removed, path, FullPath.Empty, mp.Path, mp.Mod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var manipulation in manipulations)
|
foreach (var manipulation in manipulations)
|
||||||
|
|
@ -203,7 +222,7 @@ public class CollectionCache : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Add all files and possibly manipulations of a given mod according to its settings in this collection. </summary>
|
/// <summary> Add all files and possibly manipulations of a given mod according to its settings in this collection. </summary>
|
||||||
internal void AddModSync(IMod mod, bool addMetaChanges)
|
internal void AddModSync(IMod mod, bool addMetaChanges)
|
||||||
{
|
{
|
||||||
if (mod.Index >= 0)
|
if (mod.Index >= 0)
|
||||||
|
|
@ -257,6 +276,14 @@ public class CollectionCache : IDisposable
|
||||||
foreach (var manip in subMod.Manipulations)
|
foreach (var manip in subMod.Manipulations)
|
||||||
AddManipulation(manip, parentMod);
|
AddManipulation(manip, parentMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Invoke only if not in a full recalculation. </summary>
|
||||||
|
private void InvokeResolvedFileChange(ModCollection collection, ResolvedFileChanged.Type type, Utf8GamePath key, FullPath value,
|
||||||
|
FullPath old, IMod? mod)
|
||||||
|
{
|
||||||
|
if (Calculating == -1)
|
||||||
|
_manager.ResolvedFileChanged.Invoke(collection, type, key, value, old, mod);
|
||||||
|
}
|
||||||
|
|
||||||
// Add a specific file redirection, handling potential conflicts.
|
// Add a specific file redirection, handling potential conflicts.
|
||||||
// For different mods, higher mod priority takes precedence before option group priority,
|
// For different mods, higher mod priority takes precedence before option group priority,
|
||||||
|
|
@ -271,7 +298,8 @@ public class CollectionCache : IDisposable
|
||||||
{
|
{
|
||||||
if (ResolvedFiles.TryAdd(path, new ModPath(mod, file)))
|
if (ResolvedFiles.TryAdd(path, new ModPath(mod, file)))
|
||||||
{
|
{
|
||||||
ModData.AddPath(mod, path);
|
ModData.AddPath(mod, path);
|
||||||
|
InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Added, path, file, FullPath.Empty, mod);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,11 +313,13 @@ public class CollectionCache : IDisposable
|
||||||
ModData.RemovePath(modPath.Mod, path);
|
ModData.RemovePath(modPath.Mod, path);
|
||||||
ResolvedFiles[path] = new ModPath(mod, file);
|
ResolvedFiles[path] = new ModPath(mod, file);
|
||||||
ModData.AddPath(mod, path);
|
ModData.AddPath(mod, path);
|
||||||
|
InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Replaced, path, file, modPath.Path, mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Penumbra.Log.Error($"[{Thread.CurrentThread.ManagedThreadId}] Error adding redirection {file} -> {path} for mod {mod.Name} to collection cache {AnonymizedName}:\n{ex}");
|
Penumbra.Log.Error(
|
||||||
|
$"[{Thread.CurrentThread.ManagedThreadId}] Error adding redirection {file} -> {path} for mod {mod.Name} to collection cache {AnonymizedName}:\n{ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -491,7 +521,7 @@ public class CollectionCache : IDisposable
|
||||||
case 2:
|
case 2:
|
||||||
Cache.ReloadModSync(Mod, AddMetaChanges);
|
Cache.ReloadModSync(Mod, AddMetaChanges);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
Cache.ForceFileSync(Path, FullPath);
|
Cache.ForceFileSync(Path, FullPath);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,19 @@ using Penumbra.Meta;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
|
using Penumbra.String.Classes;
|
||||||
|
|
||||||
namespace Penumbra.Collections.Cache;
|
namespace Penumbra.Collections.Cache;
|
||||||
|
|
||||||
public class CollectionCacheManager : IDisposable
|
public class CollectionCacheManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly FrameworkManager _framework;
|
private readonly FrameworkManager _framework;
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly TempModManager _tempMods;
|
private readonly TempModManager _tempMods;
|
||||||
private readonly ModStorage _modStorage;
|
private readonly ModStorage _modStorage;
|
||||||
private readonly CollectionStorage _storage;
|
private readonly CollectionStorage _storage;
|
||||||
private readonly ActiveCollections _active;
|
private readonly ActiveCollections _active;
|
||||||
|
internal readonly ResolvedFileChanged ResolvedFileChanged;
|
||||||
|
|
||||||
internal readonly MetaFileManager MetaFileManager;
|
internal readonly MetaFileManager MetaFileManager;
|
||||||
|
|
||||||
|
|
@ -39,16 +41,17 @@ public class CollectionCacheManager : IDisposable
|
||||||
public IEnumerable<ModCollection> Active
|
public IEnumerable<ModCollection> Active
|
||||||
=> _storage.Where(c => c.HasCache);
|
=> _storage.Where(c => c.HasCache);
|
||||||
|
|
||||||
public CollectionCacheManager(FrameworkManager framework, CommunicatorService communicator,
|
public CollectionCacheManager(FrameworkManager framework, CommunicatorService communicator, TempModManager tempMods, ModStorage modStorage,
|
||||||
TempModManager tempMods, ModStorage modStorage, MetaFileManager metaFileManager, ActiveCollections active, CollectionStorage storage)
|
MetaFileManager metaFileManager, ActiveCollections active, CollectionStorage storage)
|
||||||
{
|
{
|
||||||
_framework = framework;
|
_framework = framework;
|
||||||
_communicator = communicator;
|
_communicator = communicator;
|
||||||
_tempMods = tempMods;
|
_tempMods = tempMods;
|
||||||
_modStorage = modStorage;
|
_modStorage = modStorage;
|
||||||
MetaFileManager = metaFileManager;
|
MetaFileManager = metaFileManager;
|
||||||
_active = active;
|
_active = active;
|
||||||
_storage = storage;
|
_storage = storage;
|
||||||
|
ResolvedFileChanged = _communicator.ResolvedFileChanged;
|
||||||
|
|
||||||
if (!_active.Individuals.IsLoaded)
|
if (!_active.Individuals.IsLoaded)
|
||||||
_active.Individuals.Loaded += CreateNecessaryCaches;
|
_active.Individuals.Loaded += CreateNecessaryCaches;
|
||||||
|
|
@ -158,6 +161,9 @@ public class CollectionCacheManager : IDisposable
|
||||||
cache.Calculating = Environment.CurrentManagedThreadId;
|
cache.Calculating = Environment.CurrentManagedThreadId;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
ResolvedFileChanged.Invoke(collection, ResolvedFileChanged.Type.FullRecomputeStart, Utf8GamePath.Empty, FullPath.Empty,
|
||||||
|
FullPath.Empty,
|
||||||
|
null);
|
||||||
cache.ResolvedFiles.Clear();
|
cache.ResolvedFiles.Clear();
|
||||||
cache.Meta.Reset();
|
cache.Meta.Reset();
|
||||||
cache._conflicts.Clear();
|
cache._conflicts.Clear();
|
||||||
|
|
@ -177,6 +183,9 @@ public class CollectionCacheManager : IDisposable
|
||||||
collection.IncrementCounter();
|
collection.IncrementCounter();
|
||||||
|
|
||||||
MetaFileManager.ApplyDefaultFiles(collection);
|
MetaFileManager.ApplyDefaultFiles(collection);
|
||||||
|
ResolvedFileChanged.Invoke(collection, ResolvedFileChanged.Type.FullRecomputeFinished, Utf8GamePath.Empty, FullPath.Empty,
|
||||||
|
FullPath.Empty,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ public sealed class CollectionChange : EventWrapper<Action<CollectionType, ModCo
|
||||||
{
|
{
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
|
/// <seealso cref="Api.DalamudSubstitutionProvider.OnCollectionChange"/>
|
||||||
|
DalamudSubstitutionProvider = -3,
|
||||||
|
|
||||||
/// <seealso cref="Collections.Cache.CollectionCacheManager.OnCollectionChange"/>
|
/// <seealso cref="Collections.Cache.CollectionCacheManager.OnCollectionChange"/>
|
||||||
CollectionCacheManager = -2,
|
CollectionCacheManager = -2,
|
||||||
|
|
||||||
|
|
@ -43,6 +46,7 @@ public sealed class CollectionChange : EventWrapper<Action<CollectionType, ModCo
|
||||||
|
|
||||||
/// <seealso cref="UI.ModsTab.ModFileSystemSelector.OnCollectionChange"/>
|
/// <seealso cref="UI.ModsTab.ModFileSystemSelector.OnCollectionChange"/>
|
||||||
ModFileSystemSelector = 0,
|
ModFileSystemSelector = 0,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CollectionChange()
|
public CollectionChange()
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ public sealed class EnabledChanged : EventWrapper<Action<bool>, EnabledChanged.P
|
||||||
{
|
{
|
||||||
/// <seealso cref="Ipc.EnabledChange"/>
|
/// <seealso cref="Ipc.EnabledChange"/>
|
||||||
Api = int.MinValue,
|
Api = int.MinValue,
|
||||||
|
|
||||||
|
/// <seealso cref="Api.DalamudSubstitutionProvider.OnEnabledChange"/>
|
||||||
|
DalamudSubstitutionProvider = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnabledChanged()
|
public EnabledChanged()
|
||||||
|
|
|
||||||
43
Penumbra/Communication/ResolvedFileChanged.cs
Normal file
43
Penumbra/Communication/ResolvedFileChanged.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using Penumbra.Collections;
|
||||||
|
using Penumbra.Mods;
|
||||||
|
using Penumbra.String.Classes;
|
||||||
|
|
||||||
|
namespace Penumbra.Communication;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered whenever a redirection in a mod collection cache is manipulated.
|
||||||
|
/// <list type="number">
|
||||||
|
/// <item>Parameter is collection with a changed cache. </item>
|
||||||
|
/// <item>Parameter is the type of change. </item>
|
||||||
|
/// <item>Parameter is the game path to be redirected or empty for FullRecompute. </item>
|
||||||
|
/// <item>Parameter is the new redirection path or empty for Removed or FullRecompute </item>
|
||||||
|
/// <item>Parameter is the old redirection path for Replaced, or empty. </item>
|
||||||
|
/// <item>Parameter is the mod responsible for the new redirection if any. </item>
|
||||||
|
/// </list> </summary>
|
||||||
|
public sealed class ResolvedFileChanged : EventWrapper<Action<ModCollection, ResolvedFileChanged.Type, Utf8GamePath, FullPath, FullPath, IMod?>,
|
||||||
|
ResolvedFileChanged.Priority>
|
||||||
|
{
|
||||||
|
public enum Type
|
||||||
|
{
|
||||||
|
Added,
|
||||||
|
Removed,
|
||||||
|
Replaced,
|
||||||
|
FullRecomputeStart,
|
||||||
|
FullRecomputeFinished,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
/// <seealso cref="Api.DalamudSubstitutionProvider.OnResolvedFileChanged"/>
|
||||||
|
DalamudSubstitutionProvider = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResolvedFileChanged()
|
||||||
|
: base(nameof(ResolvedFileChanged))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public void Invoke(ModCollection collection, Type type, Utf8GamePath key, FullPath value, FullPath old, IMod? mod)
|
||||||
|
=> Invoke(this, collection, type, key, value, old, mod);
|
||||||
|
}
|
||||||
|
|
@ -38,9 +38,10 @@ public class Configuration : IPluginConfiguration, ISavable
|
||||||
public string ModDirectory { get; set; } = string.Empty;
|
public string ModDirectory { get; set; } = string.Empty;
|
||||||
public string ExportDirectory { get; set; } = string.Empty;
|
public string ExportDirectory { get; set; } = string.Empty;
|
||||||
|
|
||||||
public bool HideUiInGPose { get; set; } = false;
|
public bool HideUiInGPose { get; set; } = false;
|
||||||
public bool HideUiInCutscenes { get; set; } = true;
|
public bool HideUiInCutscenes { get; set; } = true;
|
||||||
public bool HideUiWhenUiHidden { get; set; } = false;
|
public bool HideUiWhenUiHidden { get; set; } = false;
|
||||||
|
public bool UseDalamudUiTextureRedirection { get; set; } = true;
|
||||||
|
|
||||||
public bool UseCharacterCollectionInMainWindow { get; set; } = true;
|
public bool UseCharacterCollectionInMainWindow { get; set; } = true;
|
||||||
public bool UseCharacterCollectionsInCards { get; set; } = true;
|
public bool UseCharacterCollectionsInCards { get; set; } = true;
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ public class CommunicatorService : IDisposable
|
||||||
/// <inheritdoc cref="Communication.SelectTab"/>
|
/// <inheritdoc cref="Communication.SelectTab"/>
|
||||||
public readonly SelectTab SelectTab = new();
|
public readonly SelectTab SelectTab = new();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Communication.ResolvedFileChanged"/>
|
||||||
|
public readonly ResolvedFileChanged ResolvedFileChanged = new();
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
CollectionChange.Dispose();
|
CollectionChange.Dispose();
|
||||||
|
|
@ -86,5 +89,6 @@ public class CommunicatorService : IDisposable
|
||||||
ChangedItemHover.Dispose();
|
ChangedItemHover.Dispose();
|
||||||
ChangedItemClick.Dispose();
|
ChangedItemClick.Dispose();
|
||||||
SelectTab.Dispose();
|
SelectTab.Dispose();
|
||||||
|
ResolvedFileChanged.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,5 +181,6 @@ public static class ServiceManager
|
||||||
=> services.AddSingleton<PenumbraApi>()
|
=> services.AddSingleton<PenumbraApi>()
|
||||||
.AddSingleton<IPenumbraApi>(x => x.GetRequiredService<PenumbraApi>())
|
.AddSingleton<IPenumbraApi>(x => x.GetRequiredService<PenumbraApi>())
|
||||||
.AddSingleton<PenumbraIpcProviders>()
|
.AddSingleton<PenumbraIpcProviders>()
|
||||||
.AddSingleton<HttpApi>();
|
.AddSingleton<HttpApi>()
|
||||||
|
.AddSingleton<DalamudSubstitutionProvider>();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,38 +26,41 @@ public class SettingsTab : ITab
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Settings"u8;
|
=> "Settings"u8;
|
||||||
|
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly FontReloader _fontReloader;
|
private readonly FontReloader _fontReloader;
|
||||||
private readonly TutorialService _tutorial;
|
private readonly TutorialService _tutorial;
|
||||||
private readonly Penumbra _penumbra;
|
private readonly Penumbra _penumbra;
|
||||||
private readonly FileDialogService _fileDialog;
|
private readonly FileDialogService _fileDialog;
|
||||||
private readonly ModManager _modManager;
|
private readonly ModManager _modManager;
|
||||||
private readonly ModExportManager _modExportManager;
|
private readonly ModExportManager _modExportManager;
|
||||||
private readonly ModFileSystemSelector _selector;
|
private readonly ModFileSystemSelector _selector;
|
||||||
private readonly CharacterUtility _characterUtility;
|
private readonly CharacterUtility _characterUtility;
|
||||||
private readonly ResidentResourceManager _residentResources;
|
private readonly ResidentResourceManager _residentResources;
|
||||||
private readonly DalamudServices _dalamud;
|
private readonly DalamudServices _dalamud;
|
||||||
private readonly HttpApi _httpApi;
|
private readonly HttpApi _httpApi;
|
||||||
|
private readonly DalamudSubstitutionProvider _dalamudSubstitutionProvider;
|
||||||
|
|
||||||
private int _minimumX = int.MaxValue;
|
private int _minimumX = int.MaxValue;
|
||||||
private int _minimumY = int.MaxValue;
|
private int _minimumY = int.MaxValue;
|
||||||
|
|
||||||
public SettingsTab(Configuration config, FontReloader fontReloader, TutorialService tutorial, Penumbra penumbra,
|
public SettingsTab(Configuration config, FontReloader fontReloader, TutorialService tutorial, Penumbra penumbra,
|
||||||
FileDialogService fileDialog, ModManager modManager, ModFileSystemSelector selector, CharacterUtility characterUtility,
|
FileDialogService fileDialog, ModManager modManager, ModFileSystemSelector selector, CharacterUtility characterUtility,
|
||||||
ResidentResourceManager residentResources, DalamudServices dalamud, ModExportManager modExportManager, HttpApi httpApi)
|
ResidentResourceManager residentResources, DalamudServices dalamud, ModExportManager modExportManager, HttpApi httpApi,
|
||||||
|
DalamudSubstitutionProvider dalamudSubstitutionProvider)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_fontReloader = fontReloader;
|
_fontReloader = fontReloader;
|
||||||
_tutorial = tutorial;
|
_tutorial = tutorial;
|
||||||
_penumbra = penumbra;
|
_penumbra = penumbra;
|
||||||
_fileDialog = fileDialog;
|
_fileDialog = fileDialog;
|
||||||
_modManager = modManager;
|
_modManager = modManager;
|
||||||
_selector = selector;
|
_selector = selector;
|
||||||
_characterUtility = characterUtility;
|
_characterUtility = characterUtility;
|
||||||
_residentResources = residentResources;
|
_residentResources = residentResources;
|
||||||
_dalamud = dalamud;
|
_dalamud = dalamud;
|
||||||
_modExportManager = modExportManager;
|
_modExportManager = modExportManager;
|
||||||
_httpApi = httpApi;
|
_httpApi = httpApi;
|
||||||
|
_dalamudSubstitutionProvider = dalamudSubstitutionProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawHeader()
|
public void DrawHeader()
|
||||||
|
|
@ -389,6 +392,12 @@ public class SettingsTab : ITab
|
||||||
/// <summary> Draw all settings pertaining to actor identification for collections. </summary>
|
/// <summary> Draw all settings pertaining to actor identification for collections. </summary>
|
||||||
private void DrawIdentificationSettings()
|
private void DrawIdentificationSettings()
|
||||||
{
|
{
|
||||||
|
Checkbox("Use Interface Collection for other Plugin UIs",
|
||||||
|
"Use the collection assigned to your interface for other plugins requesting UI-textures and icons through Dalamud.",
|
||||||
|
_dalamudSubstitutionProvider.Enabled, _dalamudSubstitutionProvider.Set);
|
||||||
|
var icon = _dalamud.TextureProvider.GetIcon(60026);
|
||||||
|
if (icon != null)
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
|
||||||
Checkbox($"Use {TutorialService.AssignedCollections} in Character Window",
|
Checkbox($"Use {TutorialService.AssignedCollections} in Character Window",
|
||||||
"Use the individual collection for your characters name or the Your Character collection in your main character window, if it is set.",
|
"Use the individual collection for your characters name or the Your Character collection in your main character window, if it is set.",
|
||||||
_config.UseCharacterCollectionInMainWindow, v => _config.UseCharacterCollectionInMainWindow = v);
|
_config.UseCharacterCollectionInMainWindow, v => _config.UseCharacterCollectionInMainWindow = v);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue