mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Get rid of OtterGui event wrappers.
This commit is contained in:
parent
3ce02b506e
commit
c423ce1d47
103 changed files with 1050 additions and 1024 deletions
2
Luna
2
Luna
|
|
@ -1 +1 @@
|
|||
Subproject commit ece206edc96bc39844e4c6c314dd562fe1b1db55
|
||||
Subproject commit f39b514304d8f30030310f75d83f99385105c271
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Interop.Hooks.ResourceLoading;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
|
@ -28,36 +29,24 @@ public class GameStateApi : IPenumbraApiGameState, Luna.IApiService, IDisposable
|
|||
_resourceLoader.ResourceLoaded += OnResourceLoaded;
|
||||
_resourceLoader.PapRequested += OnPapRequested;
|
||||
_communicator.CreatedCharacterBase.Subscribe(OnCreatedCharacterBase, Communication.CreatedCharacterBase.Priority.Api);
|
||||
_communicator.CreatingCharacterBase.Subscribe(OnCreatingCharacterBase, Communication.CreatingCharacterBase.Priority.Api);
|
||||
}
|
||||
|
||||
private void OnCreatingCharacterBase(in CreatingCharacterBase.Arguments arguments)
|
||||
=> CreatingCharacterBase?.Invoke(arguments.GameObject.Address, arguments.Collection.Identity.Id, arguments.ModelCharaId, arguments.Customize,
|
||||
arguments.EquipData);
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
_resourceLoader.ResourceLoaded -= OnResourceLoaded;
|
||||
_resourceLoader.PapRequested -= OnPapRequested;
|
||||
_communicator.CreatedCharacterBase.Unsubscribe(OnCreatedCharacterBase);
|
||||
_communicator.CreatingCharacterBase.Unsubscribe(OnCreatingCharacterBase);
|
||||
}
|
||||
|
||||
public event CreatedCharacterBaseDelegate? CreatedCharacterBase;
|
||||
public event GameObjectResourceResolvedDelegate? GameObjectResourceResolved;
|
||||
|
||||
public event CreatingCharacterBaseDelegate? CreatingCharacterBase
|
||||
{
|
||||
add
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
_communicator.CreatingCharacterBase.Subscribe(new Action<nint, Guid, nint, nint, nint>(value),
|
||||
Communication.CreatingCharacterBase.Priority.Api);
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
_communicator.CreatingCharacterBase.Unsubscribe(new Action<nint, Guid, nint, nint, nint>(value));
|
||||
}
|
||||
}
|
||||
public event CreatingCharacterBaseDelegate? CreatingCharacterBase;
|
||||
|
||||
public unsafe (nint GameObject, (Guid Id, string Name) Collection) GetDrawObjectInfo(nint drawObject)
|
||||
{
|
||||
|
|
@ -117,6 +106,6 @@ public class GameStateApi : IPenumbraApiGameState, Luna.IApiService, IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private void OnCreatedCharacterBase(nint gameObject, ModCollection collection, nint drawObject)
|
||||
=> CreatedCharacterBase?.Invoke(gameObject, collection.Identity.Id, drawObject);
|
||||
private void OnCreatedCharacterBase(in CreatedCharacterBase.Arguments arguments)
|
||||
=> CreatedCharacterBase?.Invoke(arguments.GameObject, arguments.Collection.Identity.Id, arguments.DrawObject);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@ using Penumbra.Collections.Manager;
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.Interop.PathResolving;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Mods.Settings;
|
||||
using Penumbra.Mods.SubMods;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.Api.Api;
|
||||
|
|
@ -264,19 +262,18 @@ public class ModSettingsApi : IPenumbraApiModSettings, IApiService, IDisposable
|
|||
ModSettingChanged?.Invoke(ModSettingChange.Edited, collection.Identity.Id, mod.Identifier, parent != collection);
|
||||
}
|
||||
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? _1, DirectoryInfo? _2)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
if (type == ModPathChangeType.Reloaded)
|
||||
TriggerSettingEdited(mod);
|
||||
if (arguments.Type is ModPathChangeType.Reloaded)
|
||||
TriggerSettingEdited(arguments.Mod);
|
||||
}
|
||||
|
||||
private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, Setting _1, int _2, bool inherited)
|
||||
=> ModSettingChanged?.Invoke(type, collection.Identity.Id, mod?.ModPath.Name ?? string.Empty, inherited);
|
||||
private void OnModSettingChange(in ModSettingChanged.Arguments arguments)
|
||||
=> ModSettingChanged?.Invoke(arguments.Type, arguments.Collection.Identity.Id, arguments.Mod?.Identifier ?? string.Empty, arguments.Inherited);
|
||||
|
||||
private void OnModOptionEdited(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
|
||||
int moveIndex)
|
||||
private void OnModOptionEdited(in ModOptionChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModOptionChangeType.GroupDeleted:
|
||||
case ModOptionChangeType.GroupMoved:
|
||||
|
|
@ -288,17 +285,17 @@ public class ModSettingsApi : IPenumbraApiModSettings, IApiService, IDisposable
|
|||
case ModOptionChangeType.OptionFilesAdded:
|
||||
case ModOptionChangeType.OptionSwapsChanged:
|
||||
case ModOptionChangeType.OptionMetaChanged:
|
||||
TriggerSettingEdited(mod);
|
||||
TriggerSettingEdited(arguments.Mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModFileChanged(Mod mod, FileRegistry file)
|
||||
private void OnModFileChanged(in ModFileChanged.Arguments arguments)
|
||||
{
|
||||
if (file.CurrentUsage == 0)
|
||||
if (arguments.File.CurrentUsage == 0)
|
||||
return;
|
||||
|
||||
TriggerSettingEdited(mod);
|
||||
TriggerSettingEdited(arguments.Mod);
|
||||
}
|
||||
|
||||
public static PenumbraApiEc ConvertModSetting(Mod mod, string groupName, IReadOnlyList<string> optionNames, out int groupIndex,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using Luna;
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Services;
|
||||
|
||||
|
|
@ -29,16 +28,24 @@ public class ModsApi : IPenumbraApiMods, IApiService, IDisposable
|
|||
_migrationManager = migrationManager;
|
||||
_log = log;
|
||||
_communicator.ModPathChanged.Subscribe(OnModPathChanged, ModPathChanged.Priority.ApiMods);
|
||||
_communicator.PcpCreation.Subscribe(OnPcpCreation, PcpCreation.Priority.ApiMods);
|
||||
_communicator.PcpParsing.Subscribe(OnPcpParsing, PcpParsing.Priority.ApiMods);
|
||||
}
|
||||
|
||||
private void OnModPathChanged(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, DirectoryInfo? newDirectory)
|
||||
private void OnPcpParsing(in PcpParsing.Arguments arguments)
|
||||
=> ParsingPcp?.Invoke(arguments.JObject, arguments.Mod.Identifier, arguments.Collection?.Identity.Id ?? Guid.Empty);
|
||||
|
||||
private void OnPcpCreation(in PcpCreation.Arguments arguments)
|
||||
=> CreatingPcp?.Invoke(arguments.JObject, arguments.ObjectIndex, arguments.DirectoryPath);
|
||||
|
||||
private void OnModPathChanged(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Deleted when oldDirectory != null: ModDeleted?.Invoke(oldDirectory.Name); break;
|
||||
case ModPathChangeType.Added when newDirectory != null: ModAdded?.Invoke(newDirectory.Name); break;
|
||||
case ModPathChangeType.Moved when newDirectory != null && oldDirectory != null:
|
||||
ModMoved?.Invoke(oldDirectory.Name, newDirectory.Name);
|
||||
case ModPathChangeType.Deleted when arguments.OldDirectory is not null: ModDeleted?.Invoke(arguments.OldDirectory.Name); break;
|
||||
case ModPathChangeType.Added when arguments.NewDirectory is not null: ModAdded?.Invoke(arguments.NewDirectory.Name); break;
|
||||
case ModPathChangeType.Moved when arguments is { NewDirectory: not null, OldDirectory: not null }:
|
||||
ModMoved?.Invoke(arguments.OldDirectory.Name, arguments.NewDirectory.Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +53,8 @@ public class ModsApi : IPenumbraApiMods, IApiService, IDisposable
|
|||
public void Dispose()
|
||||
{
|
||||
_communicator.ModPathChanged.Unsubscribe(OnModPathChanged);
|
||||
_communicator.PcpCreation.Unsubscribe(OnPcpCreation);
|
||||
_communicator.PcpParsing.Unsubscribe(OnPcpParsing);
|
||||
}
|
||||
|
||||
public Dictionary<string, string> GetModList()
|
||||
|
|
@ -105,21 +114,11 @@ public class ModsApi : IPenumbraApiMods, IApiService, IDisposable
|
|||
return ApiHelpers.Return(PenumbraApiEc.Success, ApiHelpers.Args("ModDirectory", modDirectory, "ModName", modName));
|
||||
}
|
||||
|
||||
public event Action<string>? ModDeleted;
|
||||
public event Action<string>? ModAdded;
|
||||
public event Action<string, string>? ModMoved;
|
||||
|
||||
public event Action<JObject, ushort, string>? CreatingPcp
|
||||
{
|
||||
add => _communicator.PcpCreation.Subscribe(value!, PcpCreation.Priority.ModsApi);
|
||||
remove => _communicator.PcpCreation.Unsubscribe(value!);
|
||||
}
|
||||
|
||||
public event Action<JObject, string, Guid>? ParsingPcp
|
||||
{
|
||||
add => _communicator.PcpParsing.Subscribe(value!, PcpParsing.Priority.ModsApi);
|
||||
remove => _communicator.PcpParsing.Unsubscribe(value!);
|
||||
}
|
||||
public event Action<string>? ModDeleted;
|
||||
public event Action<string>? ModAdded;
|
||||
public event Action<string, string>? ModMoved;
|
||||
public event Action<JObject, ushort, string>? CreatingPcp;
|
||||
public event Action<JObject, string, Guid>? ParsingPcp;
|
||||
|
||||
public (PenumbraApiEc, string, bool, bool) GetModPath(string modDirectory, string modName)
|
||||
{
|
||||
|
|
@ -155,7 +154,7 @@ public class ModsApi : IPenumbraApiMods, IApiService, IDisposable
|
|||
|
||||
public Dictionary<string, object?> GetChangedItems(string modDirectory, string modName)
|
||||
=> _modManager.TryGetMod(modDirectory, modName, out var mod)
|
||||
? mod.ChangedItems.ToDictionary(kvp => kvp.Key, kvp => kvp.Value?.ToInternalObject())
|
||||
? mod.ChangedItems.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToInternalObject())
|
||||
: [];
|
||||
|
||||
public IReadOnlyDictionary<string, IReadOnlyDictionary<string, object?>> GetChangedItemAdapterDictionary()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Frozen;
|
||||
using Luna;
|
||||
using Newtonsoft.Json;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods;
|
||||
|
|
@ -6,32 +7,47 @@ using Penumbra.Services;
|
|||
|
||||
namespace Penumbra.Api.Api;
|
||||
|
||||
public class PluginStateApi(Configuration config, CommunicatorService communicator) : IPenumbraApiPluginState, Luna.IApiService
|
||||
public class PluginStateApi : IPenumbraApiPluginState, IApiService, IDisposable
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
|
||||
public PluginStateApi(Configuration config, CommunicatorService communicator)
|
||||
{
|
||||
_config = config;
|
||||
_communicator = communicator;
|
||||
_communicator.ModDirectoryChanged.Subscribe(OnModDirectoryChanged, Communication.ModDirectoryChanged.Priority.Api);
|
||||
_communicator.EnabledChanged.Subscribe(OnEnabledChanged, EnabledChanged.Priority.Api);
|
||||
}
|
||||
|
||||
private void OnEnabledChanged(in EnabledChanged.Arguments arguments)
|
||||
=> EnabledChange?.Invoke(arguments.Enabled);
|
||||
|
||||
private void OnModDirectoryChanged(in ModDirectoryChanged.Arguments arguments)
|
||||
=> ModDirectoryChanged?.Invoke(arguments.Directory, arguments.Valid);
|
||||
|
||||
public string GetModDirectory()
|
||||
=> config.ModDirectory;
|
||||
=> _config.ModDirectory;
|
||||
|
||||
public string GetConfiguration()
|
||||
=> JsonConvert.SerializeObject(config, Formatting.Indented);
|
||||
=> JsonConvert.SerializeObject(_config, Formatting.Indented);
|
||||
|
||||
public event Action<string, bool>? ModDirectoryChanged
|
||||
{
|
||||
add => communicator.ModDirectoryChanged.Subscribe(value!, Communication.ModDirectoryChanged.Priority.Api);
|
||||
remove => communicator.ModDirectoryChanged.Unsubscribe(value!);
|
||||
}
|
||||
public event Action<string, bool>? ModDirectoryChanged;
|
||||
|
||||
public bool GetEnabledState()
|
||||
=> config.EnableMods;
|
||||
=> _config.EnableMods;
|
||||
|
||||
public event Action<bool>? EnabledChange
|
||||
{
|
||||
add => communicator.EnabledChanged.Subscribe(value!, EnabledChanged.Priority.Api);
|
||||
remove => communicator.EnabledChanged.Unsubscribe(value!);
|
||||
}
|
||||
public event Action<bool>? EnabledChange;
|
||||
|
||||
public FrozenSet<string> SupportedFeatures
|
||||
=> FeatureChecker.SupportedFeatures.ToFrozenSet();
|
||||
|
||||
public string[] CheckSupportedFeatures(IEnumerable<string> requiredFeatures)
|
||||
=> requiredFeatures.Where(f => !FeatureChecker.Supported(f)).ToArray();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_communicator.ModDirectoryChanged.Unsubscribe(OnModDirectoryChanged);
|
||||
_communicator.EnabledChanged.Unsubscribe(OnEnabledChanged);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using FFXIVClientStructs.FFXIV.Common.Lua;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.UI;
|
||||
|
|
@ -20,41 +20,40 @@ public class UiApi : IPenumbraApiUi, Luna.IApiService, IDisposable
|
|||
_modManager = modManager;
|
||||
_communicator.ChangedItemHover.Subscribe(OnChangedItemHover, ChangedItemHover.Priority.Default);
|
||||
_communicator.ChangedItemClick.Subscribe(OnChangedItemClick, ChangedItemClick.Priority.Default);
|
||||
_communicator.PreSettingsTabBarDraw.Subscribe(OnPreSettingsTabBarDraw, Communication.PreSettingsTabBarDraw.Priority.Default);
|
||||
_communicator.PreSettingsPanelDraw.Subscribe(OnPreSettingsPanelDraw, Communication.PreSettingsPanelDraw.Priority.Default);
|
||||
_communicator.PostEnabledDraw.Subscribe(OnPostEnabledDraw, Communication.PostEnabledDraw.Priority.Default);
|
||||
_communicator.PostSettingsPanelDraw.Subscribe(OnPostSettingsPanelDraw, Communication.PostSettingsPanelDraw.Priority.Default);
|
||||
}
|
||||
|
||||
private void OnPostSettingsPanelDraw(in PostSettingsPanelDraw.Arguments arguments)
|
||||
=> PostSettingsPanelDraw?.Invoke(arguments.Mod.Identifier);
|
||||
|
||||
private void OnPostEnabledDraw(in PostEnabledDraw.Arguments arguments)
|
||||
=> PostEnabledDraw?.Invoke(arguments.Mod.Identifier);
|
||||
|
||||
private void OnPreSettingsPanelDraw(in PreSettingsPanelDraw.Arguments arguments)
|
||||
=> PreSettingsPanelDraw?.Invoke(arguments.Mod.Identifier);
|
||||
|
||||
private void OnPreSettingsTabBarDraw(in PreSettingsTabBarDraw.Arguments arguments)
|
||||
=> PreSettingsTabBarDraw?.Invoke(arguments.Mod.Identifier, arguments.HeaderWidth, arguments.TitleBoxWidth);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_communicator.ChangedItemHover.Unsubscribe(OnChangedItemHover);
|
||||
_communicator.ChangedItemClick.Unsubscribe(OnChangedItemClick);
|
||||
_communicator.PreSettingsTabBarDraw.Unsubscribe(OnPreSettingsTabBarDraw);
|
||||
_communicator.PreSettingsPanelDraw.Unsubscribe(OnPreSettingsPanelDraw);
|
||||
_communicator.PostEnabledDraw.Unsubscribe(OnPostEnabledDraw);
|
||||
_communicator.PostSettingsPanelDraw.Unsubscribe(OnPostSettingsPanelDraw);
|
||||
}
|
||||
|
||||
public event Action<ChangedItemType, uint>? ChangedItemTooltip;
|
||||
|
||||
public event Action<ChangedItemType, uint>? ChangedItemTooltip;
|
||||
public event Action<MouseButton, ChangedItemType, uint>? ChangedItemClicked;
|
||||
|
||||
public event Action<string, float, float>? PreSettingsTabBarDraw
|
||||
{
|
||||
add => _communicator.PreSettingsTabBarDraw.Subscribe(value!, Communication.PreSettingsTabBarDraw.Priority.Default);
|
||||
remove => _communicator.PreSettingsTabBarDraw.Unsubscribe(value!);
|
||||
}
|
||||
|
||||
public event Action<string>? PreSettingsPanelDraw
|
||||
{
|
||||
add => _communicator.PreSettingsPanelDraw.Subscribe(value!, Communication.PreSettingsPanelDraw.Priority.Default);
|
||||
remove => _communicator.PreSettingsPanelDraw.Unsubscribe(value!);
|
||||
}
|
||||
|
||||
public event Action<string>? PostEnabledDraw
|
||||
{
|
||||
add => _communicator.PostEnabledDraw.Subscribe(value!, Communication.PostEnabledDraw.Priority.Default);
|
||||
remove => _communicator.PostEnabledDraw.Unsubscribe(value!);
|
||||
}
|
||||
|
||||
public event Action<string>? PostSettingsPanelDraw
|
||||
{
|
||||
add => _communicator.PostSettingsPanelDraw.Subscribe(value!, Communication.PostSettingsPanelDraw.Priority.Default);
|
||||
remove => _communicator.PostSettingsPanelDraw.Unsubscribe(value!);
|
||||
}
|
||||
public event Action<string, float, float>? PreSettingsTabBarDraw;
|
||||
public event Action<string>? PreSettingsPanelDraw;
|
||||
public event Action<string>? PostEnabledDraw;
|
||||
public event Action<string>? PostSettingsPanelDraw;
|
||||
|
||||
public PenumbraApiEc OpenMainWindow(TabType tab, string modDirectory, string modName)
|
||||
{
|
||||
|
|
@ -65,13 +64,13 @@ public class UiApi : IPenumbraApiUi, Luna.IApiService, IDisposable
|
|||
if (tab == TabType.Mods && (modDirectory.Length > 0 || modName.Length > 0))
|
||||
{
|
||||
if (_modManager.TryGetMod(modDirectory, modName, out var mod))
|
||||
_communicator.SelectTab.Invoke(tab, mod);
|
||||
_communicator.SelectTab.Invoke(new SelectTab.Arguments(tab, mod));
|
||||
else
|
||||
return PenumbraApiEc.ModMissing;
|
||||
}
|
||||
else if (tab != TabType.None)
|
||||
{
|
||||
_communicator.SelectTab.Invoke(tab, null);
|
||||
_communicator.SelectTab.Invoke(new SelectTab.Arguments(tab, null));
|
||||
}
|
||||
|
||||
return PenumbraApiEc.Success;
|
||||
|
|
@ -80,21 +79,21 @@ public class UiApi : IPenumbraApiUi, Luna.IApiService, IDisposable
|
|||
public void CloseMainWindow()
|
||||
=> _configWindow.IsOpen = false;
|
||||
|
||||
private void OnChangedItemClick(MouseButton button, IIdentifiedObjectData data)
|
||||
private void OnChangedItemClick(in ChangedItemClick.Arguments arguments)
|
||||
{
|
||||
if (ChangedItemClicked == null)
|
||||
return;
|
||||
|
||||
var (type, id) = data.ToApiObject();
|
||||
ChangedItemClicked.Invoke(button, type, id);
|
||||
var (type, id) = arguments.Data.ToApiObject();
|
||||
ChangedItemClicked.Invoke(arguments.Button, type, id);
|
||||
}
|
||||
|
||||
private void OnChangedItemHover(IIdentifiedObjectData data)
|
||||
private void OnChangedItemHover(in ChangedItemHover.Arguments arguments)
|
||||
{
|
||||
if (ChangedItemTooltip == null)
|
||||
return;
|
||||
|
||||
var (type, id) = data.ToApiObject();
|
||||
var (type, id) = arguments.Data.ToApiObject();
|
||||
ChangedItemTooltip.Invoke(type, id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
|
|
@ -74,42 +72,41 @@ public class DalamudSubstitutionProvider : IDisposable, Luna.IApiService
|
|||
public void Dispose()
|
||||
=> Unsubscribe();
|
||||
|
||||
private void OnCollectionChange(CollectionType type, ModCollection? oldCollection, ModCollection? newCollection, string _)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (type is not CollectionType.Interface)
|
||||
if (arguments.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());
|
||||
var enumerable = arguments.OldCollection?.ResolvedFiles.Keys ?? Array.Empty<Utf8GamePath>().AsEnumerable();
|
||||
enumerable = enumerable.Concat(arguments.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)
|
||||
private void OnResolvedFileChange(in ResolvedFileChanged.Arguments arguments)
|
||||
{
|
||||
if (_activeCollectionData.Interface != collection)
|
||||
if (_activeCollectionData.Interface != arguments.Collection)
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ResolvedFileChanged.Type.Added:
|
||||
case ResolvedFileChanged.Type.Removed:
|
||||
case ResolvedFileChanged.Type.Replaced:
|
||||
ResetSubstitutions([key]);
|
||||
ResetSubstitutions([arguments.GamePath]);
|
||||
break;
|
||||
case ResolvedFileChanged.Type.FullRecomputeStart:
|
||||
case ResolvedFileChanged.Type.FullRecomputeFinished:
|
||||
ResetSubstitutions(collection.ResolvedFiles.Keys);
|
||||
ResetSubstitutions(arguments.Collection.ResolvedFiles.Keys);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnabledChange(bool state)
|
||||
private void OnEnabledChange(in EnabledChanged.Arguments arguments)
|
||||
{
|
||||
if (state)
|
||||
OnCollectionChange(CollectionType.Interface, null, _activeCollectionData.Interface, string.Empty);
|
||||
if (arguments.Enabled)
|
||||
OnCollectionChange(new CollectionChange.Arguments(CollectionType.Interface, null, _activeCollectionData.Interface, string.Empty));
|
||||
else
|
||||
OnCollectionChange(CollectionType.Interface, _activeCollectionData.Interface, null, string.Empty);
|
||||
OnCollectionChange(new CollectionChange.Arguments(CollectionType.Interface, _activeCollectionData.Interface, null, string.Empty));
|
||||
}
|
||||
|
||||
private void Substitute(string path, ref string? replacementPath)
|
||||
|
|
@ -146,7 +143,7 @@ public class DalamudSubstitutionProvider : IDisposable, Luna.IApiService
|
|||
_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);
|
||||
OnCollectionChange(new CollectionChange.Arguments(CollectionType.Interface, null, _activeCollectionData.Interface, string.Empty));
|
||||
}
|
||||
|
||||
private void Unsubscribe()
|
||||
|
|
@ -155,6 +152,6 @@ public class DalamudSubstitutionProvider : IDisposable, Luna.IApiService
|
|||
_communicator.CollectionChange.Unsubscribe(OnCollectionChange);
|
||||
_communicator.ResolvedFileChanged.Unsubscribe(OnResolvedFileChange);
|
||||
_communicator.EnabledChanged.Unsubscribe(OnEnabledChange);
|
||||
OnCollectionChange(CollectionType.Interface, _activeCollectionData.Interface, null, string.Empty);
|
||||
OnCollectionChange(new CollectionChange.Arguments(CollectionType.Interface, _activeCollectionData.Interface, null, string.Empty));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,19 +86,20 @@ public class TempModManager : IDisposable, Luna.IService
|
|||
{
|
||||
Penumbra.Log.Verbose($"Removing temporary Mod {mod.Name} from {collection.Identity.AnonymizedName}.");
|
||||
collection.Remove(mod);
|
||||
_communicator.ModSettingChanged.Invoke(collection, ModSettingChange.TemporaryMod, null, Setting.False, 0, false);
|
||||
_communicator.ModSettingChanged.Invoke(new ModSettingChanged.Arguments(ModSettingChange.TemporaryMod, collection, null, Setting.False, 0, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
Penumbra.Log.Verbose($"Adding {(created ? "new " : string.Empty)}temporary Mod {mod.Name} to {collection.Identity.AnonymizedName}.");
|
||||
Penumbra.Log.Verbose(
|
||||
$"Adding {(created ? "new " : string.Empty)}temporary Mod {mod.Name} to {collection.Identity.AnonymizedName}.");
|
||||
collection.Apply(mod, created);
|
||||
_communicator.ModSettingChanged.Invoke(collection, ModSettingChange.TemporaryMod, null, Setting.True, 0, false);
|
||||
_communicator.ModSettingChanged.Invoke(new ModSettingChanged.Arguments(ModSettingChange.TemporaryMod, collection, null, Setting.True, 0, false));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Penumbra.Log.Verbose($"Triggering global mod change for {(created ? "new " : string.Empty)}temporary Mod {mod.Name}.");
|
||||
_communicator.TemporaryGlobalModChange.Invoke(mod, created, removed);
|
||||
_communicator.TemporaryGlobalModChange.Invoke(new TemporaryGlobalModChange.Arguments(mod, created, removed));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,10 +154,11 @@ public class TempModManager : IDisposable, Luna.IService
|
|||
return mod;
|
||||
}
|
||||
|
||||
private void OnCollectionChange(CollectionType collectionType, ModCollection? oldCollection, ModCollection? newCollection,
|
||||
string _)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (collectionType is CollectionType.Temporary or CollectionType.Inactive && newCollection == null && oldCollection != null)
|
||||
_mods.Remove(oldCollection);
|
||||
if (arguments.Type is CollectionType.Temporary or CollectionType.Inactive
|
||||
&& arguments.NewCollection is null
|
||||
&& arguments.OldCollection is not null)
|
||||
_mods.Remove(arguments.OldCollection);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ public sealed class CollectionCache : IDisposable
|
|||
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);
|
||||
_manager.ResolvedFileChanged.Invoke(new ResolvedFileChanged.Arguments(ResolvedFileChanged.Type.Removed, _collection, path, FullPath.Empty, mp.Path, mp.Mod));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -275,7 +275,7 @@ public sealed class CollectionCache : IDisposable
|
|||
FullPath old, IMod? mod)
|
||||
{
|
||||
if (Calculating == -1)
|
||||
_manager.ResolvedFileChanged.Invoke(collection, type, key, value, old, mod);
|
||||
_manager.ResolvedFileChanged.Invoke(new ResolvedFileChanged.Arguments(type, collection, key, value, old, mod));
|
||||
}
|
||||
|
||||
private static bool IsRedirectionSupported(Utf8GamePath path, IMod mod)
|
||||
|
|
|
|||
|
|
@ -7,11 +7,9 @@ using Penumbra.Communication;
|
|||
using Penumbra.Interop.Hooks.ResourceLoading;
|
||||
using Penumbra.Meta;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Mods.Settings;
|
||||
using Penumbra.Mods.SubMods;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
|
|
@ -70,7 +68,8 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.CollectionCacheManager);
|
||||
|
||||
if (!MetaFileManager.CharacterUtility.Ready)
|
||||
MetaFileManager.CharacterUtility.LoadingFinished.Subscribe(IncrementCounters, CharacterUtilityFinished.Priority.CollectionCacheManager);
|
||||
MetaFileManager.CharacterUtility.LoadingFinished.Subscribe(IncrementCounters,
|
||||
CharacterUtilityFinished.Priority.CollectionCacheManager);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -140,7 +139,8 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
if (collection.Identity.Index == 0)
|
||||
return;
|
||||
|
||||
Penumbra.Log.Debug($"[{Environment.CurrentManagedThreadId}] Recalculating effective file list for {collection.Identity.AnonymizedName}");
|
||||
Penumbra.Log.Debug(
|
||||
$"[{Environment.CurrentManagedThreadId}] Recalculating effective file list for {collection.Identity.AnonymizedName}");
|
||||
if (!collection.HasCache)
|
||||
{
|
||||
Penumbra.Log.Error(
|
||||
|
|
@ -169,8 +169,9 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
cache.Calculating = Environment.CurrentManagedThreadId;
|
||||
try
|
||||
{
|
||||
ResolvedFileChanged.Invoke(collection, ResolvedFileChanged.Type.FullRecomputeStart, Utf8GamePath.Empty, FullPath.Empty,
|
||||
FullPath.Empty, null);
|
||||
ResolvedFileChanged.Invoke(new ResolvedFileChanged.Arguments(ResolvedFileChanged.Type.FullRecomputeStart, collection,
|
||||
Utf8GamePath.Empty, FullPath.Empty,
|
||||
FullPath.Empty, null));
|
||||
cache.ResolvedFiles.Clear();
|
||||
cache.Meta.Reset();
|
||||
cache.ConflictDict.Clear();
|
||||
|
|
@ -188,9 +189,9 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
collection.Counters.IncrementChange();
|
||||
|
||||
MetaFileManager.ApplyDefaultFiles(collection);
|
||||
ResolvedFileChanged.Invoke(collection, ResolvedFileChanged.Type.FullRecomputeFinished, Utf8GamePath.Empty, FullPath.Empty,
|
||||
FullPath.Empty,
|
||||
null);
|
||||
ResolvedFileChanged.Invoke(new ResolvedFileChanged.Arguments(ResolvedFileChanged.Type.FullRecomputeFinished, collection,
|
||||
Utf8GamePath.Empty, FullPath.Empty,
|
||||
FullPath.Empty, null));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -198,63 +199,69 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
}
|
||||
}
|
||||
|
||||
private void OnCollectionChange(CollectionType type, ModCollection? old, ModCollection? newCollection, string displayName)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (type is CollectionType.Temporary)
|
||||
if (arguments.Type is CollectionType.Temporary)
|
||||
{
|
||||
if (newCollection != null && CreateCache(newCollection))
|
||||
CalculateEffectiveFileList(newCollection);
|
||||
if (arguments.NewCollection is not null && CreateCache(arguments.NewCollection))
|
||||
CalculateEffectiveFileList(arguments.NewCollection);
|
||||
|
||||
if (old != null)
|
||||
ClearCache(old);
|
||||
if (arguments.OldCollection is not null)
|
||||
ClearCache(arguments.OldCollection);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveCache(old);
|
||||
if (type is not CollectionType.Inactive && newCollection != null && newCollection.Identity.Index != 0 && CreateCache(newCollection))
|
||||
CalculateEffectiveFileList(newCollection);
|
||||
RemoveCache(arguments.OldCollection);
|
||||
if (arguments.Type is not CollectionType.Inactive
|
||||
&& arguments.NewCollection is not null
|
||||
&& arguments.NewCollection.Identity.Index is not 0
|
||||
&& CreateCache(arguments.NewCollection))
|
||||
CalculateEffectiveFileList(arguments.NewCollection);
|
||||
|
||||
if (type is CollectionType.Default)
|
||||
if (newCollection != null)
|
||||
MetaFileManager.ApplyDefaultFiles(newCollection);
|
||||
if (arguments.Type is CollectionType.Default)
|
||||
if (arguments.NewCollection is not null)
|
||||
MetaFileManager.ApplyDefaultFiles(arguments.NewCollection);
|
||||
else
|
||||
MetaFileManager.CharacterUtility.ResetAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnModChangeRemoval(ModPathChangeType type, Mod mod, DirectoryInfo? oldModPath, DirectoryInfo? newModPath)
|
||||
private void OnModChangeRemoval(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
var index = arguments.Mod.Index;
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Deleted:
|
||||
case ModPathChangeType.StartingReload:
|
||||
foreach (var collection in _storage.Where(c => c.HasCache && c.GetActualSettings(mod.Index).Settings?.Enabled == true))
|
||||
collection._cache!.RemoveMod(mod, true);
|
||||
foreach (var collection in _storage.Where(c => c.HasCache && c.GetActualSettings(index).Settings?.Enabled == true))
|
||||
collection._cache!.RemoveMod(arguments.Mod, true);
|
||||
break;
|
||||
case ModPathChangeType.Moved:
|
||||
foreach (var collection in _storage.Where(c => c.HasCache && c.GetActualSettings(mod.Index).Settings?.Enabled == true))
|
||||
collection._cache!.ReloadMod(mod, true);
|
||||
foreach (var collection in _storage.Where(c => c.HasCache && c.GetActualSettings(index).Settings?.Enabled == true))
|
||||
collection._cache!.ReloadMod(arguments.Mod, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModChangeAddition(ModPathChangeType type, Mod mod, DirectoryInfo? oldModPath, DirectoryInfo? newModPath)
|
||||
private void OnModChangeAddition(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
if (type is not (ModPathChangeType.Added or ModPathChangeType.Reloaded))
|
||||
if (arguments.Type is not ModPathChangeType.Added and not ModPathChangeType.Reloaded)
|
||||
return;
|
||||
|
||||
foreach (var collection in _storage.Where(c => c.HasCache && c.GetActualSettings(mod.Index).Settings?.Enabled == true))
|
||||
collection._cache!.AddMod(mod, true);
|
||||
var index = arguments.Mod.Index;
|
||||
foreach (var collection in _storage.Where(c => c.HasCache && c.GetActualSettings(index).Settings?.Enabled == true))
|
||||
collection._cache!.AddMod(arguments.Mod, true);
|
||||
}
|
||||
|
||||
/// <summary> Apply a mod change to all collections with a cache. </summary>
|
||||
private void OnGlobalModChange(TemporaryMod mod, bool created, bool removed)
|
||||
=> TempModManager.OnGlobalModChange(_storage.Where(c => c.HasCache), mod, created, removed);
|
||||
private void OnGlobalModChange(in TemporaryGlobalModChange.Arguments arguments)
|
||||
=> TempModManager.OnGlobalModChange(_storage.Where(c => c.HasCache), arguments.Mod, arguments.NewlyCreated, arguments.Deleted);
|
||||
|
||||
/// <summary> Remove a cache from a collection if it is active. </summary>
|
||||
private void RemoveCache(ModCollection? collection)
|
||||
{
|
||||
// ReSharper disable InconsistentlySynchronizedField
|
||||
if (collection != null
|
||||
&& collection.Identity.Index > ModCollection.Empty.Identity.Index
|
||||
&& collection.Identity.Index != _active.Default.Identity.Index
|
||||
|
|
@ -263,31 +270,35 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
&& _active.SpecialAssignments.All(c => c.Value.Identity.Index != collection.Identity.Index)
|
||||
&& _active.Individuals.All(c => c.Collection.Identity.Index != collection.Identity.Index))
|
||||
ClearCache(collection);
|
||||
// ReSharper restore InconsistentlySynchronizedField
|
||||
}
|
||||
|
||||
/// <summary> Prepare Changes by removing mods from caches with collections or add or reload mods. </summary>
|
||||
private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
|
||||
int movedToIdx)
|
||||
private void OnModOptionChange(in ModOptionChanged.Arguments arguments)
|
||||
{
|
||||
if (type is ModOptionChangeType.PrepareChange)
|
||||
if (arguments.Type is ModOptionChangeType.PrepareChange)
|
||||
{
|
||||
foreach (var collection in _storage.Where(collection => collection.HasCache && collection.GetActualSettings(mod.Index).Settings is { Enabled: true }))
|
||||
collection._cache!.RemoveMod(mod, false);
|
||||
|
||||
return;
|
||||
var index = arguments.Mod.Index;
|
||||
foreach (var collection in _storage.Where(collection
|
||||
=> collection.HasCache && collection.GetActualSettings(index).Settings is { Enabled: true }))
|
||||
collection._cache!.RemoveMod(arguments.Mod, false);
|
||||
}
|
||||
|
||||
type.HandlingInfo(out _, out var recomputeList, out var justAdd);
|
||||
|
||||
if (!recomputeList)
|
||||
return;
|
||||
|
||||
foreach (var collection in _storage.Where(collection => collection.HasCache && collection.GetActualSettings(mod.Index).Settings is { Enabled: true }))
|
||||
else
|
||||
{
|
||||
if (justAdd)
|
||||
collection._cache!.AddMod(mod, true);
|
||||
else
|
||||
collection._cache!.ReloadMod(mod, true);
|
||||
arguments.Type.HandlingInfo(out _, out var recomputeList, out var justAdd);
|
||||
|
||||
if (!recomputeList)
|
||||
return;
|
||||
|
||||
var index = arguments.Mod.Index;
|
||||
foreach (var collection in _storage.Where(collection
|
||||
=> collection.HasCache && collection.GetActualSettings(index).Settings is { Enabled: true }))
|
||||
{
|
||||
if (justAdd)
|
||||
collection._cache!.AddMod(arguments.Mod, true);
|
||||
else
|
||||
collection._cache!.ReloadMod(arguments.Mod, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -299,41 +310,38 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
MetaFileManager.CharacterUtility.LoadingFinished.Unsubscribe(IncrementCounters);
|
||||
}
|
||||
|
||||
private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, Setting oldValue, int groupIdx, bool _)
|
||||
private void OnModSettingChange(in ModSettingChanged.Arguments arguments)
|
||||
{
|
||||
var collection = arguments.Collection;
|
||||
if (!collection.HasCache)
|
||||
return;
|
||||
|
||||
var cache = collection._cache!;
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModSettingChange.Inheritance:
|
||||
cache.ReloadMod(mod!, true);
|
||||
break;
|
||||
case ModSettingChange.Inheritance: cache.ReloadMod(arguments.Mod!, true); break;
|
||||
case ModSettingChange.EnableState:
|
||||
if (oldValue == Setting.False)
|
||||
cache.AddMod(mod!, true);
|
||||
else if (oldValue == Setting.True)
|
||||
cache.RemoveMod(mod!, true);
|
||||
else if (collection.GetActualSettings(mod!.Index).Settings?.Enabled == true)
|
||||
cache.ReloadMod(mod!, true);
|
||||
if (arguments.OldValue == Setting.False)
|
||||
cache.AddMod(arguments.Mod!, true);
|
||||
else if (arguments.OldValue == Setting.True)
|
||||
cache.RemoveMod(arguments.Mod!, true);
|
||||
else if (collection.GetActualSettings(arguments.Mod!.Index).Settings?.Enabled == true)
|
||||
cache.ReloadMod(arguments.Mod!, true);
|
||||
else
|
||||
cache.RemoveMod(mod!, true);
|
||||
cache.RemoveMod(arguments.Mod!, true);
|
||||
|
||||
break;
|
||||
case ModSettingChange.Priority:
|
||||
if (cache.Conflicts(mod!).Count > 0)
|
||||
cache.ReloadMod(mod!, true);
|
||||
if (cache.Conflicts(arguments.Mod!).Count > 0)
|
||||
cache.ReloadMod(arguments.Mod!, true);
|
||||
|
||||
break;
|
||||
case ModSettingChange.Setting:
|
||||
if (collection.GetActualSettings(mod!.Index).Settings?.Enabled == true)
|
||||
cache.ReloadMod(mod, true);
|
||||
if (collection.GetActualSettings(arguments.Mod!.Index).Settings?.Enabled == true)
|
||||
cache.ReloadMod(arguments.Mod, true);
|
||||
|
||||
break;
|
||||
case ModSettingChange.TemporarySetting:
|
||||
cache.ReloadMod(mod!, true);
|
||||
break;
|
||||
case ModSettingChange.TemporarySetting: cache.ReloadMod(arguments.Mod!, true); break;
|
||||
case ModSettingChange.MultiInheritance:
|
||||
case ModSettingChange.MultiEnableState:
|
||||
FullRecalculation(collection);
|
||||
|
|
@ -349,8 +357,8 @@ public class CollectionCacheManager : IDisposable, IService
|
|||
/// Inheritance changes are too big to check for relevance,
|
||||
/// just recompute everything.
|
||||
/// </summary>
|
||||
private void OnCollectionInheritanceChange(ModCollection collection, bool _)
|
||||
=> FullRecalculation(collection);
|
||||
private void OnCollectionInheritanceChange(in CollectionInheritanceChanged.Arguments arguments)
|
||||
=> FullRecalculation(arguments.Collection);
|
||||
|
||||
/// <summary> Clear the current cache of a collection. </summary>
|
||||
private void ClearCache(ModCollection collection)
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ public class ActiveCollections : ISavable, IDisposable, IService
|
|||
return false;
|
||||
|
||||
SpecialCollections[(int)collectionType] = Default;
|
||||
_communicator.CollectionChange.Invoke(collectionType, null, Default, string.Empty);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(collectionType, null, Default, string.Empty));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -141,14 +141,14 @@ public class ActiveCollections : ISavable, IDisposable, IService
|
|||
return;
|
||||
|
||||
SpecialCollections[(int)collectionType] = null;
|
||||
_communicator.CollectionChange.Invoke(collectionType, old, null, string.Empty);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(collectionType, old, null, string.Empty));
|
||||
}
|
||||
|
||||
/// <summary>Create an individual collection if possible. </summary>
|
||||
public void CreateIndividualCollection(params ActorIdentifier[] identifiers)
|
||||
{
|
||||
if (Individuals.Add(identifiers, Default))
|
||||
_communicator.CollectionChange.Invoke(CollectionType.Individual, null, Default, Individuals.Last().DisplayName);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(CollectionType.Individual, null, Default, Individuals.Last().DisplayName));
|
||||
}
|
||||
|
||||
/// <summary> Remove an individual collection if it exists. </summary>
|
||||
|
|
@ -159,7 +159,7 @@ public class ActiveCollections : ISavable, IDisposable, IService
|
|||
|
||||
var (name, old) = Individuals[individualIndex];
|
||||
if (Individuals.Delete(individualIndex))
|
||||
_communicator.CollectionChange.Invoke(CollectionType.Individual, old, null, name);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(CollectionType.Individual, old, null, name));
|
||||
}
|
||||
|
||||
/// <summary> Move an individual collection from one index to another. </summary>
|
||||
|
|
@ -234,8 +234,8 @@ public class ActiveCollections : ISavable, IDisposable, IService
|
|||
}
|
||||
|
||||
UpdateCurrentCollectionInUse();
|
||||
_communicator.CollectionChange.Invoke(collectionType, oldCollection, collection,
|
||||
collectionType == CollectionType.Individual ? Individuals[individualIndex].DisplayName : string.Empty);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(collectionType, oldCollection, collection,
|
||||
collectionType == CollectionType.Individual ? Individuals[individualIndex].DisplayName : string.Empty));
|
||||
}
|
||||
|
||||
public string ToFilePath(FilenameService fileNames)
|
||||
|
|
@ -275,38 +275,38 @@ public class ActiveCollections : ISavable, IDisposable, IService
|
|||
.SelectMany(c => c.Inheritance.FlatHierarchy).Contains(Current);
|
||||
|
||||
/// <summary> Save if any of the active collections is changed and set new collections to Current. </summary>
|
||||
private void OnCollectionChange(CollectionType collectionType, ModCollection? oldCollection, ModCollection? newCollection, string _3)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (collectionType is CollectionType.Inactive)
|
||||
if (arguments.Type is CollectionType.Inactive)
|
||||
{
|
||||
if (newCollection != null)
|
||||
if (arguments.NewCollection is not null)
|
||||
{
|
||||
SetCollection(newCollection, CollectionType.Current);
|
||||
SetCollection(arguments.NewCollection, CollectionType.Current);
|
||||
}
|
||||
else if (oldCollection != null)
|
||||
else if (arguments.OldCollection != null)
|
||||
{
|
||||
if (oldCollection == Default)
|
||||
if (arguments.OldCollection == Default)
|
||||
SetCollection(ModCollection.Empty, CollectionType.Default);
|
||||
if (oldCollection == Interface)
|
||||
if (arguments.OldCollection == Interface)
|
||||
SetCollection(ModCollection.Empty, CollectionType.Interface);
|
||||
if (oldCollection == Current)
|
||||
if (arguments.OldCollection == Current)
|
||||
SetCollection(Default.Identity.Index > ModCollection.Empty.Identity.Index ? Default : _storage.DefaultNamed,
|
||||
CollectionType.Current);
|
||||
|
||||
for (var i = 0; i < SpecialCollections.Length; ++i)
|
||||
{
|
||||
if (oldCollection == SpecialCollections[i])
|
||||
if (arguments.OldCollection == SpecialCollections[i])
|
||||
SetCollection(ModCollection.Empty, (CollectionType)i);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Individuals.Count; ++i)
|
||||
{
|
||||
if (oldCollection == Individuals[i].Collection)
|
||||
if (arguments.OldCollection == Individuals[i].Collection)
|
||||
SetCollection(ModCollection.Empty, CollectionType.Individual, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (collectionType is not CollectionType.Temporary)
|
||||
else if (arguments.Type is not CollectionType.Temporary)
|
||||
{
|
||||
_saveService.DelaySave(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Settings;
|
||||
|
|
@ -208,7 +209,7 @@ public class CollectionEditor(SaveService saveService, CommunicatorService commu
|
|||
{
|
||||
if (type is not ModSettingChange.TemporarySetting)
|
||||
saveService.QueueSave(new ModCollectionSave(modStorage, changedCollection));
|
||||
communicator.ModSettingChanged.Invoke(changedCollection, type, mod, oldValue, groupIdx, false);
|
||||
communicator.ModSettingChanged.Invoke(new ModSettingChanged.Arguments(type, changedCollection, mod, oldValue, groupIdx, false));
|
||||
if (type is not ModSettingChange.TemporarySetting)
|
||||
RecurseInheritors(changedCollection, type, mod, oldValue, groupIdx);
|
||||
}
|
||||
|
|
@ -223,11 +224,11 @@ public class CollectionEditor(SaveService saveService, CommunicatorService commu
|
|||
{
|
||||
case ModSettingChange.MultiInheritance:
|
||||
case ModSettingChange.MultiEnableState:
|
||||
communicator.ModSettingChanged.Invoke(directInheritor, type, null, oldValue, groupIdx, true);
|
||||
communicator.ModSettingChanged.Invoke(new ModSettingChanged.Arguments(type, directInheritor, null, oldValue, groupIdx, true));
|
||||
break;
|
||||
default:
|
||||
if (directInheritor.GetOwnSettings(mod!.Index) == null)
|
||||
communicator.ModSettingChanged.Invoke(directInheritor, type, mod, oldValue, groupIdx, true);
|
||||
communicator.ModSettingChanged.Invoke(new ModSettingChanged.Arguments(type, directInheritor, mod, oldValue, groupIdx, true));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Luna;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Mods.Settings;
|
||||
using Penumbra.Mods.SubMods;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.Collections.Manager;
|
||||
|
|
@ -21,7 +17,7 @@ public readonly record struct LocalCollectionId(int Id) : IAdditionOperators<Loc
|
|||
=> new(left.Id + right);
|
||||
}
|
||||
|
||||
public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, Luna.IService
|
||||
public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, IService
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly SaveService _saveService;
|
||||
|
|
@ -157,7 +153,7 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, Luna
|
|||
_collections.Add(newCollection);
|
||||
_saveService.ImmediateSave(new ModCollectionSave(_modStorage, newCollection));
|
||||
Penumbra.Messager.NotificationMessage($"Created new collection {newCollection.Identity.AnonymizedName}.", NotificationType.Success, false);
|
||||
_communicator.CollectionChange.Invoke(CollectionType.Inactive, null, newCollection, string.Empty);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(CollectionType.Inactive, null, newCollection, string.Empty));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +183,7 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, Luna
|
|||
_collectionsByLocal.Remove(collection.Identity.LocalId);
|
||||
|
||||
Penumbra.Messager.NotificationMessage($"Deleted collection {collection.Identity.AnonymizedName}.", NotificationType.Success, false);
|
||||
_communicator.CollectionChange.Invoke(CollectionType.Inactive, collection, null, string.Empty);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(CollectionType.Inactive, collection, null, string.Empty));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -321,29 +317,29 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, Luna
|
|||
}
|
||||
|
||||
/// <summary> Add or remove a mod from all collections, or re-save all collections where the mod has settings. </summary>
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||
DirectoryInfo? newDirectory)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Added:
|
||||
foreach (var collection in this)
|
||||
collection.Settings.AddMod(mod);
|
||||
collection.Settings.AddMod(arguments.Mod);
|
||||
break;
|
||||
case ModPathChangeType.Deleted:
|
||||
foreach (var collection in this)
|
||||
collection.Settings.RemoveMod(mod);
|
||||
collection.Settings.RemoveMod(arguments.Mod);
|
||||
break;
|
||||
case ModPathChangeType.Moved:
|
||||
foreach (var collection in this.Where(collection => collection.GetOwnSettings(mod.Index) != null))
|
||||
var index = arguments.Mod.Index;
|
||||
foreach (var collection in this.Where(collection => collection.GetOwnSettings(index) is not null))
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||
break;
|
||||
case ModPathChangeType.Reloaded:
|
||||
foreach (var collection in this)
|
||||
{
|
||||
if (collection.GetOwnSettings(mod.Index)?.Settings.FixAll(mod) ?? false)
|
||||
if (collection.GetOwnSettings(arguments.Mod.Index)?.Settings.FixAll(arguments.Mod) ?? false)
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||
collection.Settings.SetTemporary(mod.Index, null);
|
||||
collection.Settings.SetTemporary(arguments.Mod.Index, null);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -351,30 +347,29 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, Luna
|
|||
}
|
||||
|
||||
/// <summary> Save all collections where the mod has settings and the change requires saving. </summary>
|
||||
private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
|
||||
int movedToIdx)
|
||||
private void OnModOptionChange(in ModOptionChanged.Arguments arguments)
|
||||
{
|
||||
type.HandlingInfo(out var requiresSaving, out _, out _);
|
||||
arguments.Type.HandlingInfo(out var requiresSaving, out _, out _);
|
||||
if (!requiresSaving)
|
||||
return;
|
||||
|
||||
foreach (var collection in this)
|
||||
{
|
||||
if (collection.GetOwnSettings(mod.Index)?.HandleChanges(type, mod, group, option, movedToIdx) ?? false)
|
||||
if (collection.GetOwnSettings(arguments.Mod.Index)?.HandleChanges(arguments.Type, arguments.Mod, arguments.Group, arguments.Option, arguments.DeletedIndex) ?? false)
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||
collection.Settings.SetTemporary(mod.Index, null);
|
||||
collection.Settings.SetTemporary(arguments.Mod.Index, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Update change counters when changing files. </summary>
|
||||
private void OnModFileChanged(Mod mod, FileRegistry file)
|
||||
private void OnModFileChanged(in ModFileChanged.Arguments arguments)
|
||||
{
|
||||
if (file.CurrentUsage == 0)
|
||||
if (arguments.File.CurrentUsage == 0)
|
||||
return;
|
||||
|
||||
foreach (var collection in this)
|
||||
{
|
||||
var (settings, _) = collection.GetActualSettings(mod.Index);
|
||||
var (settings, _) = collection.GetActualSettings(arguments.Mod.Index);
|
||||
if (settings is { Enabled: true })
|
||||
collection.Counters.IncrementChange();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Penumbra.Collections.Manager;
|
|||
/// This is transitive, so a collection A inheriting from B also inherits from everything B inherits.
|
||||
/// Circular dependencies are resolved by distinctness.
|
||||
/// </summary>
|
||||
public class InheritanceManager : IDisposable, Luna.IService
|
||||
public class InheritanceManager : IDisposable, IService
|
||||
{
|
||||
public enum ValidInheritance
|
||||
{
|
||||
|
|
@ -82,7 +82,7 @@ public class InheritanceManager : IDisposable, Luna.IService
|
|||
{
|
||||
var parent = inheritor.Inheritance.RemoveInheritanceAt(inheritor, idx);
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, inheritor));
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
|
||||
_communicator.CollectionInheritanceChanged.Invoke(new CollectionInheritanceChanged.Arguments(inheritor, false));
|
||||
RecurseInheritanceChanges(inheritor, true);
|
||||
Penumbra.Log.Debug($"Removed {parent.Identity.AnonymizedName} from {inheritor.Identity.AnonymizedName} inheritances.");
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ public class InheritanceManager : IDisposable, Luna.IService
|
|||
return;
|
||||
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, inheritor));
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
|
||||
_communicator.CollectionInheritanceChanged.Invoke(new CollectionInheritanceChanged.Arguments(inheritor, false));
|
||||
RecurseInheritanceChanges(inheritor, true);
|
||||
Penumbra.Log.Debug($"Moved {inheritor.Identity.AnonymizedName}s inheritance {from} to {to}.");
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ public class InheritanceManager : IDisposable, Luna.IService
|
|||
if (invokeEvent)
|
||||
{
|
||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, inheritor));
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
|
||||
_communicator.CollectionInheritanceChanged.Invoke(new CollectionInheritanceChanged.Arguments(inheritor, false));
|
||||
}
|
||||
|
||||
RecurseInheritanceChanges(inheritor, invokeEvent);
|
||||
|
|
@ -167,18 +167,18 @@ public class InheritanceManager : IDisposable, Luna.IService
|
|||
}
|
||||
}
|
||||
|
||||
private void OnCollectionChange(CollectionType collectionType, ModCollection? old, ModCollection? newCollection, string _3)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (collectionType is not CollectionType.Inactive || old == null)
|
||||
if (arguments.Type is not CollectionType.Inactive || arguments.OldCollection is null)
|
||||
return;
|
||||
|
||||
foreach (var c in _storage)
|
||||
{
|
||||
var inheritedIdx = c.Inheritance.DirectlyInheritsFrom.IndexOf(old);
|
||||
var inheritedIdx = c.Inheritance.DirectlyInheritsFrom.IndexOf(arguments.OldCollection);
|
||||
if (inheritedIdx >= 0)
|
||||
RemoveInheritance(c, inheritedIdx);
|
||||
|
||||
c.Inheritance.RemoveChild(old);
|
||||
c.Inheritance.RemoveChild(arguments.OldCollection);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ public class InheritanceManager : IDisposable, Luna.IService
|
|||
ModCollectionInheritance.UpdateFlattenedInheritance(inheritor);
|
||||
RecurseInheritanceChanges(inheritor, invokeEvent);
|
||||
if (invokeEvent)
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, true);
|
||||
_communicator.CollectionInheritanceChanged.Invoke(new CollectionInheritanceChanged.Arguments(inheritor, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ public class TempCollectionManager : IDisposable, Luna.IService
|
|||
_communicator.TemporaryGlobalModChange.Unsubscribe(OnGlobalModChange);
|
||||
}
|
||||
|
||||
private void OnGlobalModChange(TemporaryMod mod, bool created, bool removed)
|
||||
=> TempModManager.OnGlobalModChange(_customCollections.Values, mod, created, removed);
|
||||
private void OnGlobalModChange(in TemporaryGlobalModChange.Arguments arguments)
|
||||
=> TempModManager.OnGlobalModChange(_customCollections.Values, arguments.Mod, arguments.NewlyCreated, arguments.Deleted);
|
||||
|
||||
public int Count
|
||||
=> _customCollections.Count;
|
||||
|
|
@ -57,7 +57,7 @@ public class TempCollectionManager : IDisposable, Luna.IService
|
|||
if (_customCollections.TryAdd(collection.Identity.Id, collection))
|
||||
{
|
||||
// Temporary collection created.
|
||||
_communicator.CollectionChange.Invoke(CollectionType.Temporary, null, collection, string.Empty);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(CollectionType.Temporary, null, collection, string.Empty));
|
||||
return collection.Identity.Id;
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ public class TempCollectionManager : IDisposable, Luna.IService
|
|||
continue;
|
||||
|
||||
// Temporary collection assignment removed.
|
||||
_communicator.CollectionChange.Invoke(CollectionType.Temporary, collection, null, Collections[i].DisplayName);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(CollectionType.Temporary, collection, null, Collections[i].DisplayName));
|
||||
Penumbra.Log.Verbose($"Unassigned temporary collection {collection.Identity.Id} from {Collections[i].DisplayName}.");
|
||||
Collections.Delete(i--);
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ public class TempCollectionManager : IDisposable, Luna.IService
|
|||
|
||||
// Temporary collection assignment added.
|
||||
Penumbra.Log.Verbose($"Assigned temporary collection {collection.Identity.AnonymizedName} to {Collections.Last().DisplayName}.");
|
||||
_communicator.CollectionChange.Invoke(CollectionType.Temporary, null, collection, Collections.Last().DisplayName);
|
||||
_communicator.CollectionChange.Invoke(new CollectionChange.Arguments(CollectionType.Temporary, null, collection, Collections.Last().DisplayName));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,13 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData.Data;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when a Changed Item in Penumbra is clicked.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the clicked mouse button. </item>
|
||||
/// <item>Parameter is the clicked object data if any. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class ChangedItemClick() : EventWrapper<MouseButton, IIdentifiedObjectData, ChangedItemClick.Priority>(nameof(ChangedItemClick))
|
||||
/// <summary> Triggered when a Changed Item in Penumbra is clicked. </summary>
|
||||
public sealed class ChangedItemClick(Logger log)
|
||||
: EventBase<ChangedItemClick.Arguments, ChangedItemClick.Priority>(nameof(ChangedItemClick), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -22,4 +17,9 @@ public sealed class ChangedItemClick() : EventWrapper<MouseButton, IIdentifiedOb
|
|||
/// <seealso cref="Penumbra.SetupApi"/>
|
||||
Link = 1,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a changed item click event. </summary>
|
||||
/// <param name="Button"> The clicked mouse button. </param>
|
||||
/// <param name="Data"> The associated data for the clicked object, if any. </param>
|
||||
public readonly record struct Arguments(MouseButton Button, IIdentifiedObjectData Data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.GameData.Data;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when a Changed Item in Penumbra is hovered.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the hovered object data if any. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class ChangedItemHover() : EventWrapper<IIdentifiedObjectData, ChangedItemHover.Priority>(nameof(ChangedItemHover))
|
||||
/// <summary> Triggered when a Changed Item in Penumbra is hovered. </summary>
|
||||
public sealed class ChangedItemHover(Logger log)
|
||||
: EventBase<ChangedItemHover.Arguments, ChangedItemHover.Priority>(nameof(ChangedItemHover), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -21,6 +17,11 @@ public sealed class ChangedItemHover() : EventWrapper<IIdentifiedObjectData, Cha
|
|||
Link = 1,
|
||||
}
|
||||
|
||||
/// <summary> Whether this event has any subscribers. </summary>
|
||||
public bool HasTooltip
|
||||
=> HasSubscribers;
|
||||
|
||||
/// <summary> The arguments for a changed item hover event. </summary>
|
||||
/// <param name="Data"> The associated data for the hovered object, if any. </param>
|
||||
public readonly record struct Arguments(IIdentifiedObjectData Data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Interop.Services;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the Character Utility becomes ready.
|
||||
/// </summary>
|
||||
public sealed class CharacterUtilityFinished() : EventWrapper<CharacterUtilityFinished.Priority>(nameof(CharacterUtilityFinished))
|
||||
/// <summary> Triggered when the Character Utility becomes ready. </summary>
|
||||
public sealed class CharacterUtilityFinished(Logger log) : EventBase<CharacterUtilityFinished.Priority>(nameof(CharacterUtilityFinished), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,19 +1,12 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever collection setup is changed.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the type of the changed collection. (Inactive or Temporary for additions or deletions)</item>
|
||||
/// <item>Parameter is the old collection, or null on additions.</item>
|
||||
/// <item>Parameter is the new collection, or null on deletions.</item>
|
||||
/// <item>Parameter is the display name for Individual collections or an empty string otherwise.</item>
|
||||
/// </list> </summary>
|
||||
public sealed class CollectionChange()
|
||||
: EventWrapper<CollectionType, ModCollection?, ModCollection?, string, CollectionChange.Priority>(nameof(CollectionChange))
|
||||
/// <summary> Triggered whenever collection setup is changed. </summary>
|
||||
public sealed class CollectionChange(Logger log)
|
||||
: EventBase<CollectionChange.Arguments, CollectionChange.Priority>(nameof(CollectionChange), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -32,7 +25,7 @@ public sealed class CollectionChange()
|
|||
/// <seealso cref="Collections.Manager.InheritanceManager.OnCollectionChange" />
|
||||
InheritanceManager = 0,
|
||||
|
||||
/// <seealso cref="Interop.PathResolving.IdentifiedCollectionCache.CollectionChangeClear" />
|
||||
/// <seealso cref="global::Penumbra.Interop.PathResolving.IdentifiedCollectionCache.CollectionChangeClear" />
|
||||
IdentifiedCollectionCache = 0,
|
||||
|
||||
/// <seealso cref="UI.AdvancedWindow.ItemSwapTab.OnCollectionChange" />
|
||||
|
|
@ -50,4 +43,15 @@ public sealed class CollectionChange()
|
|||
/// <seealso cref="Mods.ModSelection.OnCollectionChange"/>
|
||||
ModSelection = 10,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a collection change event. </summary>
|
||||
/// <param name="Type"> The type of the changed collection (<see cref="CollectionType.Inactive"/> or <see cref="CollectionType.Temporary"/> for additions or deletions). </param>
|
||||
/// <param name="OldCollection"> The old collection, or null on additions. </param>
|
||||
/// <param name="NewCollection"> The new collection, or null on deletions. </param>
|
||||
/// <param name="DisplayName"> The display name for Individual collections or an empty string otherwise. </param>
|
||||
public readonly record struct Arguments(
|
||||
CollectionType Type,
|
||||
ModCollection? OldCollection,
|
||||
ModCollection? NewCollection,
|
||||
string DisplayName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
|
@ -10,8 +10,8 @@ namespace Penumbra.Communication;
|
|||
/// <item>Parameter is whether the change was itself inherited, i.e. if it happened in a direct parent (false) or a more removed ancestor (true). </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class CollectionInheritanceChanged()
|
||||
: EventWrapper<ModCollection, bool, CollectionInheritanceChanged.Priority>(nameof(CollectionInheritanceChanged))
|
||||
public sealed class CollectionInheritanceChanged(Logger log)
|
||||
: EventBase<CollectionInheritanceChanged.Arguments, CollectionInheritanceChanged.Priority>(nameof(CollectionInheritanceChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -27,4 +27,9 @@ public sealed class CollectionInheritanceChanged()
|
|||
/// <seealso cref="Mods.ModSelection.OnInheritanceChange"/>
|
||||
ModSelection = 10,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a collection inheritance changed event. </summary>
|
||||
/// <param name="Collection"> The collection whose ancestors were changed. </param>
|
||||
/// <param name="Inherited"> Whether the change was itself inherited, i.e. if it happened in a direct parent (false) or a more removed ancestor (true). </param>
|
||||
public readonly record struct Arguments(ModCollection Collection, bool Inherited);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Api;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary> <list type="number">
|
||||
/// <item>Parameter is the game object for which a draw object is created. </item>
|
||||
/// <item>Parameter is the applied collection. </item>
|
||||
/// <item>Parameter is the created draw object. </item>
|
||||
/// </list> </summary>
|
||||
public sealed class CreatedCharacterBase()
|
||||
: EventWrapper<nint, ModCollection, nint, CreatedCharacterBase.Priority>(nameof(CreatedCharacterBase))
|
||||
/// <summary> Invoked whenever a draw object is created for a game object. </summary>
|
||||
public sealed class CreatedCharacterBase(Logger log)
|
||||
: EventBase<CreatedCharacterBase.Arguments, CreatedCharacterBase.Priority>(nameof(CreatedCharacterBase), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PenumbraApi.CreatedCharacterBase"/>
|
||||
/// <seealso cref="GameStateApi.CreatedCharacterBase"/>
|
||||
Api = int.MinValue,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a created CharacterBase event. </summary>
|
||||
/// <param name="GameObject"> The address of the game object for which a draw object was created. </param>
|
||||
/// <param name="Collection"> The associated collection. </param>
|
||||
/// <param name="DrawObject"> The newly created draw object for the game object. </param>
|
||||
public readonly record struct Arguments(Actor GameObject, ModCollection Collection, Model DrawObject);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,14 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever a character base draw object is being created by the game.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the game object for which a draw object is created. </item>
|
||||
/// <item>Parameter is the name of the applied collection. </item>
|
||||
/// <item>Parameter is a pointer to the model id (an uint). </item>
|
||||
/// <item>Parameter is a pointer to the customize array. </item>
|
||||
/// <item>Parameter is a pointer to the equip data array. </item>
|
||||
/// </list> </summary>
|
||||
public sealed class CreatingCharacterBase()
|
||||
: EventWrapper<nint, Guid, nint, nint, nint, CreatingCharacterBase.Priority>(nameof(CreatingCharacterBase))
|
||||
/// <summary> Triggered whenever a character base draw object is being created by the game. </summary>
|
||||
public sealed class CreatingCharacterBase(Logger log)
|
||||
: EventBase<CreatingCharacterBase.Arguments, CreatingCharacterBase.Priority>(nameof(CreatingCharacterBase), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -24,4 +18,12 @@ public sealed class CreatingCharacterBase()
|
|||
/// <seealso cref="CrashHandlerService.OnCreatingCharacterBase"/>
|
||||
CrashHandler = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a created CharacterBase event. </summary>
|
||||
/// <param name="GameObject"> The address of the game object for which a draw object is being created. </param>
|
||||
/// <param name="Collection"> The associated collection. </param>
|
||||
/// <param name="ModelCharaId"> The address of the model ID that is being used. </param>
|
||||
/// <param name="Customize"> The address of the customize array that is being used. </param>
|
||||
/// <param name="EquipData"> The address of the equip data array that is being used. </param>
|
||||
public readonly record struct Arguments(Actor GameObject, ModCollection Collection, nint ModelCharaId, nint Customize, nint EquipData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Api.IpcSubscribers;
|
||||
using Luna;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the general Enabled state of Penumbra is changed.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is whether Penumbra is now Enabled (true) or Disabled (false). </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class EnabledChanged() : EventWrapper<bool, EnabledChanged.Priority>(nameof(EnabledChanged))
|
||||
/// <summary> Triggered when the general Enabled state of Penumbra is changed. </summary>
|
||||
public sealed class EnabledChanged(Logger log) : EventBase<EnabledChanged.Arguments, EnabledChanged.Priority>(nameof(EnabledChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.IpcSubscribers.Ipc.EnabledChange"/>
|
||||
/// <seealso cref="Api.Api.PluginStateApi.EnabledChange"/>
|
||||
Api = int.MinValue,
|
||||
|
||||
/// <seealso cref="Api.DalamudSubstitutionProvider.OnEnabledChange"/>
|
||||
DalamudSubstitutionProvider = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a EnabledChanged event. </summary>
|
||||
/// <param name="Enabled"> Whether Penumbra is now Enabled (true) or Disabled (false). </param>
|
||||
public readonly record struct Arguments(bool Enabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,11 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever mod meta data or local data is changed.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the type of data change for the mod, which can be multiple flags. </item>
|
||||
/// <item>Parameter is the changed mod. </item>
|
||||
/// <item>Parameter is the old name of the mod in case of a name change, and null otherwise. </item>
|
||||
/// </list> </summary>
|
||||
public sealed class ModDataChanged() : EventWrapper<ModDataChangeType, Mod, string?, ModDataChanged.Priority>(nameof(ModDataChanged))
|
||||
/// <summary> Triggered whenever mod meta data or local data is changed. </summary>
|
||||
public sealed class ModDataChanged(Logger log) : EventBase<ModDataChanged.Arguments, ModDataChanged.Priority>(nameof(ModDataChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -27,4 +21,10 @@ public sealed class ModDataChanged() : EventWrapper<ModDataChangeType, Mod, stri
|
|||
/// <seealso cref="UI.ModsTab.ModPanelHeader.OnModDataChange"/>
|
||||
ModPanelHeader = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a ModDataChanged event. </summary>
|
||||
/// <param name="Type"> The type of data change for the mod, which can be multiple flags. </param>
|
||||
/// <param name="Mod"> The changed mod. </param>
|
||||
/// <param name="OldName"> The old name of the mod in case of a name change, and null otherwise. </param>
|
||||
public readonly record struct Arguments(ModDataChangeType Type, Mod Mod, string? OldName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever the mod root directory changes.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the full path of the new directory. </item>
|
||||
/// <item>Parameter is whether the new directory is valid. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class ModDirectoryChanged() : EventWrapper<string, bool, ModDirectoryChanged.Priority>(nameof(ModDirectoryChanged))
|
||||
/// <summary> Triggered whenever the mod root directory changes. </summary>
|
||||
public sealed class ModDirectoryChanged(Logger log)
|
||||
: EventBase<ModDirectoryChanged.Arguments, ModDirectoryChanged.Priority>(nameof(ModDirectoryChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -20,4 +15,9 @@ public sealed class ModDirectoryChanged() : EventWrapper<string, bool, ModDirect
|
|||
/// <seealso cref="UI.FileDialogService.OnModDirectoryChange"/>
|
||||
FileDialogService = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a ModFileChanged event. </summary>
|
||||
/// <param name="Directory"> The full path of the new mod directory. </param>
|
||||
/// <param name="Valid"> Whether the directory is valid. </param>
|
||||
public readonly record struct Arguments(string Directory, bool Valid);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary> Triggered whenever a new mod discovery has finished. </summary>
|
||||
public sealed class ModDiscoveryFinished() : EventWrapper<ModDiscoveryFinished.Priority>(nameof(ModDiscoveryFinished))
|
||||
public sealed class ModDiscoveryFinished(Logger log) : EventBase<ModDiscoveryFinished.Priority>(nameof(ModDiscoveryFinished), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary> Triggered whenever mods are prepared to be rediscovered. </summary>
|
||||
public sealed class ModDiscoveryStarted() : EventWrapper<ModDiscoveryStarted.Priority>(nameof(ModDiscoveryStarted))
|
||||
public sealed class ModDiscoveryStarted(Logger log) : EventBase<ModDiscoveryStarted.Priority>(nameof(ModDiscoveryStarted), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,19 +1,12 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Api;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Editor;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever an existing file in a mod is overwritten by Penumbra.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the changed mod. </item>
|
||||
/// <item>Parameter file registry of the changed file. </item>
|
||||
/// </list> </summary>
|
||||
public sealed class ModFileChanged()
|
||||
: EventWrapper<Mod, FileRegistry, ModFileChanged.Priority>(nameof(ModFileChanged))
|
||||
/// <summary> Triggered whenever an existing file in a mod is overwritten by Penumbra. </summary>
|
||||
public sealed class ModFileChanged(Logger log) : EventBase<ModFileChanged.Arguments, ModFileChanged.Priority>(nameof(ModFileChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -26,4 +19,9 @@ public sealed class ModFileChanged()
|
|||
/// <seealso cref="Collections.Manager.CollectionStorage.OnModFileChanged"/>
|
||||
CollectionStorage = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a ModFileChanged event. </summary>
|
||||
/// <param name="Mod"> The changed mod. </param>
|
||||
/// <param name="File"> The file registry of the changed file. </param>
|
||||
public readonly record struct Arguments(Mod Mod, FileRegistry File);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,16 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Mods.SubMods;
|
||||
using static Penumbra.Communication.ModOptionChanged;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever an option of a mod is changed inside the mod.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the type option change. </item>
|
||||
/// <item>Parameter is the changed mod. </item>
|
||||
/// <item>Parameter is the changed group inside the mod. </item>
|
||||
/// <item>Parameter is the changed option inside the group or null if it does not concern a specific option. </item>
|
||||
/// <item>Parameter is the changed data container inside the group or null if it does not concern a specific data container. </item>
|
||||
/// <item>Parameter is the index of the group or option moved or deleted from. </item>
|
||||
/// </list> </summary>
|
||||
public sealed class ModOptionChanged()
|
||||
: EventWrapper<ModOptionChangeType, Mod, IModGroup?, IModOption?, IModDataContainer?, int, Priority>(nameof(ModOptionChanged))
|
||||
/// <summary> Triggered whenever an option of a mod is changed inside the mod. </summary>
|
||||
public sealed class ModOptionChanged(Logger log)
|
||||
: EventBase<ModOptionChanged.Arguments, ModOptionChanged.Priority>(nameof(ModOptionChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -39,4 +29,19 @@ public sealed class ModOptionChanged()
|
|||
/// <seealso cref="Collections.Manager.CollectionStorage.OnModOptionChange"/>
|
||||
CollectionStorage = 100,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a ModOptionChanged event. </summary>
|
||||
/// <param name="Type"> The type of option change for the mod. </param>
|
||||
/// <param name="Mod"> The changed mod. </param>
|
||||
/// <param name="Group"> The changed group inside the mod, if any. </param>
|
||||
/// <param name="Option"> The changed option inside the group or null if it does not concern a specific option. </param>
|
||||
/// <param name="Container"> The changed data container inside the group or null if it does not concern a specific data container. </param>
|
||||
/// <param name="DeletedIndex"> The index of the group or option moved or deleted from. </param>
|
||||
public readonly record struct Arguments(
|
||||
ModOptionChangeType Type,
|
||||
Mod Mod,
|
||||
IModGroup? Group,
|
||||
IModOption? Option,
|
||||
IModDataContainer? Container,
|
||||
int DeletedIndex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Api;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
|
|
@ -7,17 +6,9 @@ using Penumbra.Services;
|
|||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever a mod is added, deleted, moved or reloaded.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the type of change. </item>
|
||||
/// <item>Parameter is the changed mod. </item>
|
||||
/// <item>Parameter is the old directory on deletion, move or reload and null on addition. </item>
|
||||
/// <item>Parameter is the new directory on addition, move or reload and null on deletion. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class ModPathChanged()
|
||||
: EventWrapper<ModPathChangeType, Mod, DirectoryInfo?, DirectoryInfo?, ModPathChanged.Priority>(nameof(ModPathChanged))
|
||||
/// <summary> Triggered whenever a mod is added, deleted, moved or reloaded. </summary>
|
||||
public sealed class ModPathChanged(Logger log)
|
||||
: EventBase<ModPathChanged.Arguments, ModPathChanged.Priority>(nameof(ModPathChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -60,4 +51,11 @@ public sealed class ModPathChanged()
|
|||
/// <seealso cref="Collections.Cache.CollectionCacheManager.OnModChangeRemoval"/>
|
||||
CollectionCacheManagerRemoval = 100,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a ModPathChanged event. </summary>
|
||||
/// <param name="Type"> The type of change for the mod. </param>
|
||||
/// <param name="Mod"> The changed mod. </param>
|
||||
/// <param name="OldDirectory"> The old directory on deletion, move or reload and null on addition. </param>
|
||||
/// <param name="NewDirectory"> The new directory on addition, move or reload and null on deletion. </param>
|
||||
public readonly record struct Arguments(ModPathChangeType Type, Mod Mod, DirectoryInfo? OldDirectory, DirectoryInfo? NewDirectory);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
|
|
@ -7,19 +7,9 @@ using Penumbra.Mods.Settings;
|
|||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever a mod setting is changed.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the collection in which the setting was changed. </item>
|
||||
/// <item>Parameter is the type of change. </item>
|
||||
/// <item>Parameter is the mod the setting was changed for, unless it was a multi-change. </item>
|
||||
/// <item>Parameter is the old value of the setting before the change as Setting. </item>
|
||||
/// <item>Parameter is the index of the changed group if the change type is Setting. </item>
|
||||
/// <item>Parameter is whether the change was inherited from another collection. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class ModSettingChanged()
|
||||
: EventWrapper<ModCollection, ModSettingChange, Mod?, Setting, int, bool, ModSettingChanged.Priority>(nameof(ModSettingChanged))
|
||||
/// <summary> Triggered whenever a mod setting is changed. </summary>
|
||||
public sealed class ModSettingChanged(Logger log)
|
||||
: EventBase<ModSettingChanged.Arguments, ModSettingChanged.Priority>(nameof(ModSettingChanged), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -38,4 +28,19 @@ public sealed class ModSettingChanged()
|
|||
/// <seealso cref="Mods.ModSelection.OnSettingChange"/>
|
||||
ModSelection = 10,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a ModSettingChanged event. </summary>
|
||||
/// <param name="Type"> The type of change for the mod settings. </param>
|
||||
/// <param name="Collection"> The collection in which the settings were changed, unless it was a multi-change. </param>
|
||||
/// <param name="Mod"> The changed mod. </param>
|
||||
/// <param name="OldValue"> The old value of the setting before the change. </param>
|
||||
/// <param name="GroupIndex"> The index of the changed group if the change type is Setting. </param>
|
||||
/// <param name="Inherited"> Whether the change was inherited from another collection </param>
|
||||
public readonly record struct Arguments(
|
||||
ModSettingChange Type,
|
||||
ModCollection Collection,
|
||||
Mod? Mod,
|
||||
Setting OldValue,
|
||||
int GroupIndex,
|
||||
bool Inherited);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.Hooks.PostProcessing;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary> <list type="number">
|
||||
/// <item>Parameter is the material resource handle for which the shader package has been loaded. </item>
|
||||
/// <item>Parameter is the associated game object. </item>
|
||||
/// </list> </summary>
|
||||
public sealed class MtrlLoaded() : EventWrapper<nint, nint, MtrlLoaded.Priority>(nameof(MtrlLoaded))
|
||||
/// <summary> Invoked whenever a material is loaded. </summary>
|
||||
public sealed class MtrlLoaded(Logger log) : EventBase<MtrlLoaded.Arguments, MtrlLoaded.Priority>(nameof(MtrlLoaded), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Interop.Hooks.PostProcessing.ShaderReplacementFixer.OnMtrlLoaded"/>
|
||||
/// <seealso cref="ShaderReplacementFixer.OnMtrlLoaded"/>
|
||||
ShaderReplacementFixer = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a MtrlLoaded event. </summary>
|
||||
/// <param name="MaterialResourceHandle"> The material resource handle for which the shader package has been loaded. </param>
|
||||
/// <param name="GameObject"> The associated game object </param>
|
||||
public readonly record struct Arguments(nint MaterialResourceHandle, Actor GameObject);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
using Luna;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the character.json file for a .pcp file is written.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the JObject that gets written to file. </item>
|
||||
/// <item>Parameter is the object index of the game object this is written for. </item>
|
||||
/// <item>Parameter is the full path to the directory being set up for the PCP creation. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class PcpCreation() : EventWrapper<JObject, ushort, string, PcpCreation.Priority>(nameof(PcpCreation))
|
||||
/// <summary> Triggered when the character.json file for a .pcp file is written. </summary>
|
||||
public sealed class PcpCreation(Logger log) : EventBase<PcpCreation.Arguments, PcpCreation.Priority>(nameof(PcpCreation), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.Api.ModsApi"/>
|
||||
ModsApi = int.MinValue,
|
||||
ApiMods = int.MinValue,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a PcpCreation event. </summary>
|
||||
/// <param name="JObject"> The JObject that gets written to file. </param>
|
||||
/// <param name="ObjectIndex"> The object index of the game object this is written for. </param>
|
||||
/// <param name="DirectoryPath"> The full path to the directory being set up for the PCP creation. </param>
|
||||
public readonly record struct Arguments(JObject JObject, ObjectIndex ObjectIndex, string DirectoryPath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
using Luna;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the character.json file for a .pcp file is parsed and applied.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is parsed JObject that contains the data. </item>
|
||||
/// <item>Parameter is the identifier of the created mod. </item>
|
||||
/// <item>Parameter is the GUID of the created collection. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class PcpParsing() : EventWrapper<JObject, string, Guid, PcpParsing.Priority>(nameof(PcpParsing))
|
||||
/// <summary> Triggered when the character.json file for a .pcp file is parsed and applied. </summary>
|
||||
public sealed class PcpParsing(Logger log) : EventBase<PcpParsing.Arguments, PcpParsing.Priority>(nameof(PcpParsing), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.Api.ModsApi"/>
|
||||
ModsApi = int.MinValue,
|
||||
ApiMods = int.MinValue,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a PcpParsing event. </summary>
|
||||
/// <param name="JObject"> The parsed JObject that contains the data. </param>
|
||||
/// <param name="Mod"> The created mod. </param>
|
||||
/// <param name="Collection"> The created collection, if any. </param>
|
||||
public readonly record struct Arguments(JObject JObject, Mod Mod, ModCollection? Collection);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered after the Enabled Checkbox line in settings is drawn, but before options are drawn.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the identifier (directory name) of the currently selected mod. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class PostEnabledDraw() : EventWrapper<string, PostEnabledDraw.Priority>(nameof(PostEnabledDraw))
|
||||
/// <summary> Triggered after the Enabled Checkbox line in settings is drawn, but before options are drawn. </summary>
|
||||
public sealed class PostEnabledDraw(Logger log) : EventBase<PostEnabledDraw.Arguments, PostEnabledDraw.Priority>(nameof(PostEnabledDraw), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PenumbraApi.PostEnabledDraw"/>
|
||||
Default = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a PostEnabledDraw event. </summary>
|
||||
/// <param name="Mod"> The mod currently being drawn. </param>
|
||||
public readonly record struct Arguments(Mod Mod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered after the settings panel is drawn.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the identifier (directory name) of the currently selected mod. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class PostSettingsPanelDraw() : EventWrapper<string, PostSettingsPanelDraw.Priority>(nameof(PostSettingsPanelDraw))
|
||||
/// <summary> Triggered after the settings panel is drawn. </summary>
|
||||
public sealed class PostSettingsPanelDraw(Logger log) : EventBase<PostSettingsPanelDraw.Arguments, PostSettingsPanelDraw.Priority>(nameof(PostSettingsPanelDraw), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PenumbraApi.PostSettingsPanelDraw"/>
|
||||
Default = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a PostSettingsPanelDraw event. </summary>
|
||||
/// <param name="Mod"> The mod currently being drawn. </param>
|
||||
public readonly record struct Arguments(Mod Mod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered before the settings panel is drawn.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the identifier (directory name) of the currently selected mod. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class PreSettingsPanelDraw() : EventWrapper<string, PreSettingsPanelDraw.Priority>(nameof(PreSettingsPanelDraw))
|
||||
/// <summary> Triggered before the settings panel is drawn. </summary>
|
||||
public sealed class PreSettingsPanelDraw(Logger log) : EventBase<PreSettingsPanelDraw.Arguments, PreSettingsPanelDraw.Priority>(nameof(PreSettingsPanelDraw), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PenumbraApi.PreSettingsPanelDraw"/>
|
||||
Default = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a PreSettingsPanelDraw event. </summary>
|
||||
/// <param name="Mod"> The mod currently being drawn. </param>
|
||||
public readonly record struct Arguments(Mod Mod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Api.Api;
|
||||
using Penumbra.Api.IpcSubscribers;
|
||||
using Luna;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered before the settings tab bar for a mod is drawn, after the title group is drawn.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the identifier (directory name) of the currently selected mod. </item>
|
||||
/// <item>is the total width of the header group. </item>
|
||||
/// <item>is the width of the title box. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class PreSettingsTabBarDraw() : EventWrapper<string, float, float, PreSettingsTabBarDraw.Priority>(nameof(PreSettingsTabBarDraw))
|
||||
/// <summary> Triggered before the settings tab bar for a mod is drawn, after the title group is drawn. </summary>
|
||||
public sealed class PreSettingsTabBarDraw(Logger log)
|
||||
: EventBase<PreSettingsTabBarDraw.Arguments, PreSettingsTabBarDraw.Priority>(nameof(PreSettingsTabBarDraw), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.IpcSubscribers.PreSettingsTabBarDraw"/>
|
||||
Default = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a PreSettingsTabBarDraw event. </summary>
|
||||
/// <param name="Mod"> The mod currently being drawn. </param>
|
||||
/// <param name="HeaderWidth"> The total width of the header group. </param>
|
||||
/// <param name="TitleBoxWidth"> The width of the title box. </param>
|
||||
public readonly record struct Arguments(Mod Mod, float HeaderWidth, float TitleBoxWidth);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,13 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Mods.Editor;
|
||||
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<ModCollection, ResolvedFileChanged.Type, Utf8GamePath, FullPath, FullPath, IMod?, ResolvedFileChanged.Priority>(
|
||||
nameof(ResolvedFileChanged))
|
||||
/// <summary> Triggered whenever a redirection in a mod collection cache is manipulated. </summary>
|
||||
public sealed class ResolvedFileChanged(Logger log) : EventBase<ResolvedFileChanged.Arguments, ResolvedFileChanged.Priority>(
|
||||
nameof(ResolvedFileChanged), log)
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
|
|
@ -36,4 +26,19 @@ public sealed class ResolvedFileChanged()
|
|||
/// <seealso cref="Interop.Services.SchedulerResourceManagementService.OnResolvedFileChange"/>
|
||||
SchedulerResourceManagementService = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a ResolvedFileChanged event. </summary>
|
||||
/// <param name="Type"> The type of the redirection change. </param>
|
||||
/// <param name="Collection"> The collection with a changed cache. </param>
|
||||
/// <param name="GamePath"> The game path to be redirected or empty for FullRecompute </param>
|
||||
/// <param name="NewRedirection"> The new redirection path or empty for Removed or FullRecompute. </param>
|
||||
/// <param name="OldRedirection"> The old redirection path for Replaced, or empty. </param>
|
||||
/// <param name="Mod"> The mod responsible for the new redirection if any. </param>
|
||||
public readonly record struct Arguments(
|
||||
Type Type,
|
||||
ModCollection Collection,
|
||||
Utf8GamePath GamePath,
|
||||
FullPath OldRedirection,
|
||||
FullPath NewRedirection,
|
||||
IMod? Mod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,20 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to select a tab and mod in the Config Window.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the selected tab. </item>
|
||||
/// <item>Parameter is the selected mod, if any. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class SelectTab() : EventWrapper<TabType, Mod?, SelectTab.Priority>(nameof(SelectTab))
|
||||
/// <summary> Trigger to select a tab and mod in the Config Window. </summary>
|
||||
public sealed class SelectTab(Logger log) : EventBase<SelectTab.Arguments, SelectTab.Priority>(nameof(SelectTab), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="UI.Tabs.ConfigTabBar.OnSelectTab"/>
|
||||
ConfigTabBar = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a SelectTab event. </summary>
|
||||
/// <param name="Tab"> The selected tab. </param>
|
||||
/// <param name="Mod"> The selected mod, if any. </param>
|
||||
public readonly record struct Arguments(TabType Tab, Mod? Mod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,11 @@
|
|||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever a temporary mod for all collections is changed.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter added, deleted or edited temporary mod.</item>
|
||||
/// <item>Parameter is whether the mod was newly created.</item>
|
||||
/// <item>Parameter is whether the mod was deleted.</item>
|
||||
/// </list> </summary>
|
||||
public sealed class TemporaryGlobalModChange()
|
||||
: EventWrapper<TemporaryMod, bool, bool, TemporaryGlobalModChange.Priority>(nameof(TemporaryGlobalModChange))
|
||||
/// <summary> Triggered whenever a temporary mod for all collections is changed. </summary>
|
||||
public sealed class TemporaryGlobalModChange(Logger log)
|
||||
: EventBase<TemporaryGlobalModChange.Arguments, TemporaryGlobalModChange.Priority>(nameof(TemporaryGlobalModChange), log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -21,4 +15,10 @@ public sealed class TemporaryGlobalModChange()
|
|||
/// <seealso cref="Collections.Manager.TempCollectionManager.OnGlobalModChange"/>
|
||||
TempCollectionManager = 0,
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a TemporaryGlobalModChange event. </summary>
|
||||
/// <param name="Mod"> The changed mod. </param>
|
||||
/// <param name="NewlyCreated"> The changed mod. </param>
|
||||
/// <param name="Deleted"> The changed mod. </param>
|
||||
public readonly record struct Arguments(TemporaryMod Mod, bool NewlyCreated, bool Deleted);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,12 +106,13 @@ public class EphemeralConfig : ISavable, IDisposable, IService
|
|||
}
|
||||
|
||||
/// <summary> Overwrite the last saved mod path if it changes. </summary>
|
||||
private void OnModPathChanged(ModPathChangeType type, Mod mod, DirectoryInfo? old, DirectoryInfo? _)
|
||||
private void OnModPathChanged(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
if (type is not ModPathChangeType.Moved || !string.Equals(old?.Name, LastModPath, StringComparison.OrdinalIgnoreCase))
|
||||
if (arguments.Type is not ModPathChangeType.Moved
|
||||
|| !string.Equals(arguments.OldDirectory?.Name, LastModPath, StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
|
||||
LastModPath = mod.Identifier;
|
||||
LastModPath = arguments.Mod.Identifier;
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Objects;
|
||||
|
||||
public sealed unsafe class CharacterBaseDestructor : EventWrapperPtr<CharacterBase, CharacterBaseDestructor.Priority>, Luna.IHookService
|
||||
public sealed unsafe class CharacterBaseDestructor : EventBase<CharacterBaseDestructor.Arguments, CharacterBaseDestructor.Priority>,
|
||||
IHookService
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -15,8 +17,8 @@ public sealed unsafe class CharacterBaseDestructor : EventWrapperPtr<CharacterBa
|
|||
MtrlTab = -1000,
|
||||
}
|
||||
|
||||
public CharacterBaseDestructor(Luna.HookManager hooks)
|
||||
: base("Destroy CharacterBase")
|
||||
public CharacterBaseDestructor(Logger log, HookManager hooks)
|
||||
: base("Destroy CharacterBase", log)
|
||||
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.CharacterBaseDestructor);
|
||||
|
||||
private readonly Task<Hook<Delegate>> _task;
|
||||
|
|
@ -41,7 +43,11 @@ public sealed unsafe class CharacterBaseDestructor : EventWrapperPtr<CharacterBa
|
|||
private nint Detour(CharacterBase* characterBase)
|
||||
{
|
||||
Penumbra.Log.Excessive($"[{Name}] Triggered with 0x{(nint)characterBase:X}.");
|
||||
Invoke(characterBase);
|
||||
Invoke(new Arguments(characterBase));
|
||||
return _task.Result.Original(characterBase);
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a character base destructor event. </summary>
|
||||
/// <param name="CharacterBase"> The model that is being destroyed. </param>
|
||||
public readonly record struct Arguments(Model CharacterBase);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Objects;
|
||||
|
||||
public sealed unsafe class CharacterDestructor : EventWrapperPtr<Character, CharacterDestructor.Priority>, Luna.IHookService
|
||||
public sealed unsafe class CharacterDestructor : EventBase<CharacterDestructor.Arguments, CharacterDestructor.Priority>, IHookService
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -19,8 +20,8 @@ public sealed unsafe class CharacterDestructor : EventWrapperPtr<Character, Char
|
|||
DrawObjectState = 0,
|
||||
}
|
||||
|
||||
public CharacterDestructor(Luna.HookManager hooks)
|
||||
: base("Character Destructor")
|
||||
public CharacterDestructor(Logger log, HookManager hooks)
|
||||
: base("Character Destructor", log)
|
||||
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.CharacterDestructor, Detour, !HookOverrides.Instance.Objects.CharacterDestructor);
|
||||
|
||||
private readonly Task<Hook<Delegate>> _task;
|
||||
|
|
@ -45,7 +46,11 @@ public sealed unsafe class CharacterDestructor : EventWrapperPtr<Character, Char
|
|||
private void Detour(Character* character)
|
||||
{
|
||||
Penumbra.Log.Excessive($"[{Name}] Triggered with 0x{(nint)character:X}.");
|
||||
Invoke(character);
|
||||
Invoke(new Arguments(character));
|
||||
_task.Result.Original(character);
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a character destructor event. </summary>
|
||||
/// <param name="Character"> The game object that is being destroyed. </param>
|
||||
public readonly record struct Arguments(Actor Character);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Objects;
|
||||
|
||||
public sealed unsafe class ConstructCutsceneCharacter : EventWrapperPtr<Character, ConstructCutsceneCharacter.Priority>, Luna.IHookService
|
||||
public sealed unsafe class ConstructCutsceneCharacter : EventBase<ConstructCutsceneCharacter.Arguments, ConstructCutsceneCharacter.Priority>, IHookService
|
||||
{
|
||||
private readonly GameState _gameState;
|
||||
private readonly ObjectManager _objects;
|
||||
|
|
@ -18,8 +17,8 @@ public sealed unsafe class ConstructCutsceneCharacter : EventWrapperPtr<Characte
|
|||
CutsceneService = 0,
|
||||
}
|
||||
|
||||
public ConstructCutsceneCharacter(GameState gameState, Luna.HookManager hooks, ObjectManager objects)
|
||||
: base("ConstructCutsceneCharacter")
|
||||
public ConstructCutsceneCharacter(Logger log, GameState gameState, HookManager hooks, ObjectManager objects)
|
||||
: base("ConstructCutsceneCharacter", log)
|
||||
{
|
||||
_gameState = gameState;
|
||||
_objects = objects;
|
||||
|
|
@ -42,7 +41,7 @@ public sealed unsafe class ConstructCutsceneCharacter : EventWrapperPtr<Characte
|
|||
var character = _objects[ret + (int)ScreenActor.CutsceneStart].AsCharacter;
|
||||
if (character != null)
|
||||
{
|
||||
Invoke(character);
|
||||
Invoke(new Arguments(character));
|
||||
Penumbra.Log.Verbose(
|
||||
$"[{Name}] Created indirect copy of player character at 0x{(nint)character}, index {character->ObjectIndex}.");
|
||||
}
|
||||
|
|
@ -66,4 +65,8 @@ public sealed unsafe class ConstructCutsceneCharacter : EventWrapperPtr<Characte
|
|||
|
||||
public bool Finished
|
||||
=> _task.IsCompletedSuccessfully;
|
||||
|
||||
/// <summary> The arguments for a construct cutscene character event. </summary>
|
||||
/// <param name="Character"> The game object that is being destroyed. </param>
|
||||
public readonly record struct Arguments(Actor Character);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using OtterGui.Classes;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Objects;
|
||||
|
||||
public sealed unsafe class CopyCharacter : EventWrapperPtr<Character, Character, CopyCharacter.Priority>, Luna.IHookService
|
||||
{
|
||||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Objects;
|
||||
|
||||
public sealed unsafe class CopyCharacter : EventBase<CopyCharacter.Arguments, CopyCharacter.Priority>, IHookService
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PathResolving.CutsceneService.OnCharacterCopy"/>
|
||||
CutsceneService = 0,
|
||||
}
|
||||
|
||||
public CopyCharacter(Luna.HookManager hooks)
|
||||
: base("Copy Character")
|
||||
public CopyCharacter(Logger log, HookManager hooks)
|
||||
: base("Copy Character", log)
|
||||
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.CopyCharacter);
|
||||
|
||||
private readonly Task<Hook<Delegate>> _task;
|
||||
|
|
@ -39,7 +40,12 @@ public sealed unsafe class CopyCharacter : EventWrapperPtr<Character, Character,
|
|||
{
|
||||
var character = target->OwnerObject;
|
||||
Penumbra.Log.Verbose($"[{Name}] Triggered with target: 0x{(nint)target:X}, source : 0x{(nint)source:X} unk: {unk}.");
|
||||
Invoke(character, source);
|
||||
Invoke(new Arguments(character, source));
|
||||
return _task.Result.Original(target, source, unk);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> The arguments for a copy character event. </summary>
|
||||
/// <param name="TargetCharacter"> The character that is being created by a copy. </param>
|
||||
/// <param name="SourceCharacter"> The character that is being copied. </param>
|
||||
public readonly record struct Arguments(Actor TargetCharacter, Actor SourceCharacter);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,25 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Objects;
|
||||
|
||||
public sealed unsafe class CreateCharacterBase : EventWrapperPtr<ModelCharaId, CustomizeArray, CharacterArmor, CreateCharacterBase.Priority>, Luna.IHookService
|
||||
{
|
||||
public sealed unsafe class CreateCharacterBase : EventBase<CreateCharacterBase.Arguments, CreateCharacterBase.Priority>, IHookService
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PathResolving.MetaState.OnCreatingCharacterBase"/>
|
||||
MetaState = 0,
|
||||
}
|
||||
|
||||
public CreateCharacterBase(Luna.HookManager hooks)
|
||||
: base("Create CharacterBase")
|
||||
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.CreateCharacterBase);
|
||||
public CreateCharacterBase(Logger log, HookManager hooks)
|
||||
: base("Create CharacterBase", log)
|
||||
{
|
||||
_postEvent = new PostEvent("Created CharacterBase", log);
|
||||
_task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.CreateCharacterBase);
|
||||
}
|
||||
|
||||
private readonly Task<Hook<Delegate>> _task;
|
||||
|
||||
|
|
@ -38,36 +42,52 @@ public sealed unsafe class CreateCharacterBase : EventWrapperPtr<ModelCharaId, C
|
|||
|
||||
private CharacterBase* Detour(ModelCharaId model, CustomizeArray* customize, CharacterArmor* equipment, byte unk)
|
||||
{
|
||||
Penumbra.Log.Verbose($"[{Name}] Triggered with model: {model.Id}, customize: 0x{(nint)customize:X}, equipment: 0x{(nint)equipment:X}, unk: {unk}.");
|
||||
Invoke(&model, customize, equipment);
|
||||
Penumbra.Log.Verbose(
|
||||
$"[{Name}] Triggered with model: {model.Id}, customize: 0x{(nint)customize:X}, equipment: 0x{(nint)equipment:X}, unk: {unk}.");
|
||||
Invoke(new Arguments(ref model, customize, equipment));
|
||||
var ret = _task.Result.Original(model, customize, equipment, unk);
|
||||
_postEvent.Invoke(model, customize, equipment, ret);
|
||||
_postEvent.Invoke(new PostEvent.Arguments(model, customize, equipment, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Subscribe(ActionPtr234<ModelCharaId, CustomizeArray, CharacterArmor, CharacterBase> subscriber, PostEvent.Priority priority)
|
||||
public void Subscribe(InAction<PostEvent.Arguments> subscriber, PostEvent.Priority priority)
|
||||
=> _postEvent.Subscribe(subscriber, priority);
|
||||
|
||||
public void Unsubscribe(ActionPtr234<ModelCharaId, CustomizeArray, CharacterArmor, CharacterBase> subscriber)
|
||||
public void Unsubscribe(InAction<PostEvent.Arguments> subscriber)
|
||||
=> _postEvent.Unsubscribe(subscriber);
|
||||
|
||||
|
||||
private readonly PostEvent _postEvent = new("Created CharacterBase");
|
||||
private readonly PostEvent _postEvent;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_postEvent.Dispose();
|
||||
}
|
||||
|
||||
public class PostEvent(string name) : EventWrapperPtr234<ModelCharaId, CustomizeArray, CharacterArmor, CharacterBase, PostEvent.Priority>(name)
|
||||
{
|
||||
public class PostEvent(string name, Logger log) : EventBase<PostEvent.Arguments, PostEvent.Priority>(name, log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PathResolving.DrawObjectState.OnCharacterBaseCreated"/>
|
||||
DrawObjectState = 0,
|
||||
DrawObjectState = 0,
|
||||
|
||||
/// <seealso cref="PathResolving.MetaState.OnCharacterBaseCreated"/>
|
||||
MetaState = 0,
|
||||
}
|
||||
|
||||
public readonly struct Arguments(ModelCharaId modelCharaId, CustomizeArray* customize, CharacterArmor* equipment, Model characterBase)
|
||||
{
|
||||
public readonly ModelCharaId ModelCharaId = modelCharaId;
|
||||
public readonly CustomizeArray* Customize = customize;
|
||||
public readonly CharacterArmor* Equipment = equipment;
|
||||
public readonly Model CharacterBase = characterBase;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly ref struct Arguments(ref ModelCharaId modelCharaId, CustomizeArray* customize, CharacterArmor* equipment)
|
||||
{
|
||||
public readonly ref ModelCharaId ModelCharaId = ref modelCharaId;
|
||||
public readonly CustomizeArray* Customize = customize;
|
||||
public readonly CharacterArmor* Equipment = equipment;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Objects;
|
||||
|
||||
public sealed unsafe class WeaponReload : EventWrapperPtr<DrawDataContainer, Character, CharacterWeapon, WeaponReload.Priority>, Luna.IHookService
|
||||
public sealed unsafe class WeaponReload : EventBase<WeaponReload.Arguments, WeaponReload.Priority>, IHookService
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -13,9 +14,12 @@ public sealed unsafe class WeaponReload : EventWrapperPtr<DrawDataContainer, Cha
|
|||
DrawObjectState = 0,
|
||||
}
|
||||
|
||||
public WeaponReload(Luna.HookManager hooks)
|
||||
: base("Reload Weapon")
|
||||
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.WeaponReload);
|
||||
public WeaponReload(Logger log, HookManager hooks)
|
||||
: base("Reload Weapon", log)
|
||||
{
|
||||
_postEvent = new PostEvent("Created CharacterBase", log);
|
||||
_task = hooks.CreateHook<Delegate>(Name, Address, Detour, !HookOverrides.Instance.Objects.WeaponReload);
|
||||
}
|
||||
|
||||
private readonly Task<Hook<Delegate>> _task;
|
||||
|
||||
|
|
@ -40,31 +44,44 @@ public sealed unsafe class WeaponReload : EventWrapperPtr<DrawDataContainer, Cha
|
|||
{
|
||||
var gameObject = drawData->OwnerObject;
|
||||
Penumbra.Log.Verbose($"[{Name}] Triggered with drawData: 0x{(nint)drawData:X}, {slot}, {weapon}, {d}, {e}, {f}, {g}, {h}.");
|
||||
Invoke(drawData, gameObject, (CharacterWeapon*)(&weapon));
|
||||
Invoke(new Arguments(ref *drawData, gameObject, ref *(CharacterWeapon*)(&weapon)));
|
||||
_task.Result.Original(drawData, slot, weapon, d, e, f, g, h);
|
||||
_postEvent.Invoke(drawData, gameObject);
|
||||
_postEvent.Invoke(new PostEvent.Arguments(ref *drawData, gameObject));
|
||||
}
|
||||
|
||||
public void Subscribe(ActionPtr<DrawDataContainer, Character> subscriber, PostEvent.Priority priority)
|
||||
public void Subscribe(InAction<PostEvent.Arguments> subscriber, PostEvent.Priority priority)
|
||||
=> _postEvent.Subscribe(subscriber, priority);
|
||||
|
||||
public void Unsubscribe(ActionPtr<DrawDataContainer, Character> subscriber)
|
||||
public void Unsubscribe(InAction<PostEvent.Arguments> subscriber)
|
||||
=> _postEvent.Unsubscribe(subscriber);
|
||||
|
||||
|
||||
private readonly PostEvent _postEvent = new("Created CharacterBase");
|
||||
private readonly PostEvent _postEvent;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_postEvent.Dispose();
|
||||
}
|
||||
|
||||
public class PostEvent(string name) : EventWrapperPtr<DrawDataContainer, Character, PostEvent.Priority>(name)
|
||||
{
|
||||
public class PostEvent(string name, Logger log) : EventBase<PostEvent.Arguments, PostEvent.Priority>(name, log)
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="PathResolving.DrawObjectState"/>
|
||||
DrawObjectState = 0,
|
||||
}
|
||||
|
||||
public readonly ref struct Arguments(ref DrawDataContainer drawData, Actor owner)
|
||||
{
|
||||
public readonly ref DrawDataContainer DrawDataContainer = ref drawData;
|
||||
public readonly Actor Owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly ref struct Arguments(ref DrawDataContainer drawData, Actor owner, ref CharacterWeapon weapon)
|
||||
{
|
||||
public readonly ref DrawDataContainer DrawDataContainer = ref drawData;
|
||||
public readonly Actor Owner = owner;
|
||||
public readonly ref CharacterWeapon Weapon = ref weapon;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Dalamud.Hooking;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
|
@ -17,7 +17,7 @@ namespace Penumbra.Interop.Hooks.PostProcessing;
|
|||
/// <item>Parameter is the collection associated with the game object. </item>
|
||||
/// <item>Parameter is the slot that was recomputed. If this is Unknown, it is a general new update call. </item>
|
||||
/// </list> </summary>
|
||||
public sealed unsafe class AttributeHook : EventWrapper<Actor, Model, ModCollection, AttributeHook.Priority>, Luna.IHookService
|
||||
public sealed unsafe class AttributeHook : EventBase<AttributeHook.Arguments, AttributeHook.Priority>, IHookService
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -28,8 +28,8 @@ public sealed unsafe class AttributeHook : EventWrapper<Actor, Model, ModCollect
|
|||
private readonly CollectionResolver _resolver;
|
||||
private readonly Configuration _config;
|
||||
|
||||
public AttributeHook(Luna.HookManager hooks, Configuration config, CollectionResolver resolver)
|
||||
: base("Update Model Attributes")
|
||||
public AttributeHook(Logger log, HookManager hooks, Configuration config, CollectionResolver resolver)
|
||||
: base("Update Model Attributes", log)
|
||||
{
|
||||
_config = config;
|
||||
_resolver = resolver;
|
||||
|
|
@ -76,9 +76,11 @@ public sealed unsafe class AttributeHook : EventWrapper<Actor, Model, ModCollect
|
|||
var identifiedActor = resolveData.AssociatedGameObject;
|
||||
var identifiedCollection = resolveData.ModCollection;
|
||||
Penumbra.Log.Excessive($"[{Name}] Invoked on 0x{(ulong)human:X} (0x{identifiedActor:X}).");
|
||||
Invoke(identifiedActor, human, identifiedCollection);
|
||||
Invoke(new Arguments(identifiedActor, human, identifiedCollection));
|
||||
}
|
||||
|
||||
public readonly record struct Arguments(Actor Character, Model Human, ModCollection Collection);
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
=> _task.Result.Dispose();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,9 +185,9 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic
|
|||
_characterOcclusionState.GetAndResetSlowPathCallDelta(),
|
||||
_hairMaskState.GetAndResetSlowPathCallDelta());
|
||||
|
||||
private void OnMtrlLoaded(nint mtrlResourceHandle, nint gameObject)
|
||||
private void OnMtrlLoaded(in MtrlLoaded.Arguments arguments)
|
||||
{
|
||||
var mtrl = (MaterialResourceHandle*)mtrlResourceHandle;
|
||||
var mtrl = (MaterialResourceHandle*)arguments.MaterialResourceHandle;
|
||||
var shpk = mtrl->ShaderPackageResourceHandle;
|
||||
if (shpk == null)
|
||||
return;
|
||||
|
|
@ -199,20 +199,20 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic
|
|||
?? GetStateForModelRendererUnk(shpkName) ?? GetStateForColorTable(shpkName);
|
||||
|
||||
if (shpkState != null && shpk != shpkState.DefaultShaderPackage)
|
||||
shpkState.TryAddMaterial(mtrlResourceHandle);
|
||||
shpkState.TryAddMaterial(arguments.MaterialResourceHandle);
|
||||
}
|
||||
|
||||
private void OnResourceHandleDestructor(Structs.ResourceHandle* handle)
|
||||
private void OnResourceHandleDestructor(in ResourceHandleDestructor.Arguments arguments)
|
||||
{
|
||||
_skinState.TryRemoveMaterial(handle);
|
||||
_characterStockingsState.TryRemoveMaterial(handle);
|
||||
_characterLegacyState.TryRemoveMaterial(handle);
|
||||
_irisState.TryRemoveMaterial(handle);
|
||||
_characterGlassState.TryRemoveMaterial(handle);
|
||||
_characterTransparencyState.TryRemoveMaterial(handle);
|
||||
_characterTattooState.TryRemoveMaterial(handle);
|
||||
_characterOcclusionState.TryRemoveMaterial(handle);
|
||||
_hairMaskState.TryRemoveMaterial(handle);
|
||||
_skinState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_characterStockingsState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_characterLegacyState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_irisState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_characterGlassState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_characterTransparencyState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_characterTattooState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_characterOcclusionState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
_hairMaskState.TryRemoveMaterial(arguments.ResourceHandle);
|
||||
}
|
||||
|
||||
private ModdedShaderPackageState? GetStateForHumanSetup(MaterialResourceHandle* mtrlResource)
|
||||
|
|
|
|||
|
|
@ -347,9 +347,9 @@ public unsafe class ResourceLoader : IDisposable, Luna.IService
|
|||
returnValue = 1;
|
||||
}
|
||||
|
||||
private void ResourceDestructorHandler(ResourceHandle* handle)
|
||||
private void ResourceDestructorHandler(in ResourceHandleDestructor.Arguments arguments)
|
||||
{
|
||||
_ongoingLoads.TryRemove((nint)handle, out _);
|
||||
_ongoingLoads.TryRemove((nint)arguments.ResourceHandle, out _);
|
||||
}
|
||||
|
||||
/// <summary> Compute the CRC32 hash for a given path together with potential resource parameters. </summary>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Services;
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ public sealed unsafe class LoadMtrl : FastHook<LoadMtrl.Delegate>
|
|||
_gameState.MtrlData.Value = mtrlData;
|
||||
var ret = Task.Result.Original(handle, unk1, unk2);
|
||||
_gameState.MtrlData.Value = last;
|
||||
_communicator.MtrlLoaded.Invoke((nint)handle, mtrlData.AssociatedGameObject);
|
||||
_communicator.MtrlLoaded.Invoke(new MtrlLoaded.Arguments((nint)handle, mtrlData.AssociatedGameObject));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
using Dalamud.Hooking;
|
||||
using OtterGui.Classes;
|
||||
using Luna;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.UI.ResourceWatcher;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Resources;
|
||||
|
||||
public sealed unsafe class ResourceHandleDestructor : EventWrapperPtr<ResourceHandle, ResourceHandleDestructor.Priority>, Luna.IHookService
|
||||
public sealed unsafe class ResourceHandleDestructor : EventBase<ResourceHandleDestructor.Arguments, ResourceHandleDestructor.Priority>, IHookService
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
@ -23,8 +23,8 @@ public sealed unsafe class ResourceHandleDestructor : EventWrapperPtr<ResourceHa
|
|||
ResourceWatcher,
|
||||
}
|
||||
|
||||
public ResourceHandleDestructor(Luna.HookManager hooks)
|
||||
: base("Destroy ResourceHandle")
|
||||
public ResourceHandleDestructor(Logger log, HookManager hooks)
|
||||
: base("Destroy ResourceHandle", log)
|
||||
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.ResourceHandleDestructor, Detour,
|
||||
!HookOverrides.Instance.Resources.ResourceHandleDestructor);
|
||||
|
||||
|
|
@ -50,7 +50,12 @@ public sealed unsafe class ResourceHandleDestructor : EventWrapperPtr<ResourceHa
|
|||
private nint Detour(ResourceHandle* resourceHandle)
|
||||
{
|
||||
Penumbra.Log.Excessive($"[{Name}] Triggered with 0x{(nint)resourceHandle:X}.");
|
||||
Invoke(resourceHandle);
|
||||
Invoke(new Arguments(resourceHandle));
|
||||
return _task.Result.Original(resourceHandle);
|
||||
}
|
||||
|
||||
public readonly struct Arguments(ResourceHandle* resourceHandle)
|
||||
{
|
||||
public readonly ResourceHandle* ResourceHandle = resourceHandle;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.Interop.Hooks.Objects;
|
||||
|
|
@ -25,7 +24,7 @@ public sealed class CutsceneService : Luna.IRequiredService, IDisposable
|
|||
.Where(i => _objects[i].Valid)
|
||||
.Select(i => KeyValuePair.Create(i, this[i] ?? _objects.GetDalamudObject(i)!));
|
||||
|
||||
public unsafe CutsceneService(ObjectManager objects, CopyCharacter copyCharacter, CharacterDestructor characterDestructor,
|
||||
public CutsceneService(ObjectManager objects, CopyCharacter copyCharacter, CharacterDestructor characterDestructor,
|
||||
ConstructCutsceneCharacter constructCutsceneCharacter, IClientState clientState)
|
||||
{
|
||||
_objects = objects;
|
||||
|
|
@ -85,15 +84,16 @@ public sealed class CutsceneService : Luna.IRequiredService, IDisposable
|
|||
return -1;
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
_copyCharacter.Unsubscribe(OnCharacterCopy);
|
||||
_characterDestructor.Unsubscribe(OnCharacterDestructor);
|
||||
_constructCutsceneCharacter.Unsubscribe(OnSetupPlayerNpc);
|
||||
}
|
||||
|
||||
private unsafe void OnCharacterDestructor(Character* character)
|
||||
private unsafe void OnCharacterDestructor(in CharacterDestructor.Arguments arguments)
|
||||
{
|
||||
var character = arguments.Character.AsCharacter;
|
||||
if (character->GameObject.ObjectIndex < CutsceneStartIdx)
|
||||
{
|
||||
// Remove all associations for now non-existing actor.
|
||||
|
|
@ -118,21 +118,21 @@ public sealed class CutsceneService : Luna.IRequiredService, IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe void OnCharacterCopy(Character* target, Character* source)
|
||||
private void OnCharacterCopy(in CopyCharacter.Arguments arguments)
|
||||
{
|
||||
if (target == null || target->GameObject.ObjectIndex is < CutsceneStartIdx or >= CutsceneEndIdx)
|
||||
if (!arguments.TargetCharacter.Valid || arguments.TargetCharacter.Index.Index is < CutsceneStartIdx or >= CutsceneEndIdx)
|
||||
return;
|
||||
|
||||
var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||
_copiedCharacters[idx] = (short)(source != null ? source->GameObject.ObjectIndex : -1);
|
||||
var idx = arguments.TargetCharacter.Index.Index - CutsceneStartIdx;
|
||||
_copiedCharacters[idx] = (short)(arguments.SourceCharacter.Valid ? arguments.SourceCharacter.Index : -1);
|
||||
}
|
||||
|
||||
private unsafe void OnSetupPlayerNpc(Character* npc)
|
||||
private void OnSetupPlayerNpc(in ConstructCutsceneCharacter.Arguments arguments)
|
||||
{
|
||||
if (npc == null || npc->ObjectIndex is < CutsceneStartIdx or >= CutsceneEndIdx)
|
||||
if (!arguments.Character.Valid || arguments.Character.Index.Index is < CutsceneStartIdx or >= CutsceneEndIdx)
|
||||
return;
|
||||
|
||||
var idx = npc->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||
var idx = arguments.Character.Index.Index - CutsceneStartIdx;
|
||||
_copiedCharacters[idx] = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Object = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.Object;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -22,7 +20,7 @@ public sealed class DrawObjectState : IDisposable, IReadOnlyDictionary<Model, (A
|
|||
public nint LastGameObject
|
||||
=> _gameState.LastGameObject;
|
||||
|
||||
public unsafe DrawObjectState(ObjectManager objects, CreateCharacterBase createCharacterBase, WeaponReload weaponReload,
|
||||
public DrawObjectState(ObjectManager objects, CreateCharacterBase createCharacterBase, WeaponReload weaponReload,
|
||||
CharacterBaseDestructor characterBaseDestructor, GameState gameState, IFramework framework, CharacterDestructor characterDestructor)
|
||||
{
|
||||
_objects = objects;
|
||||
|
|
@ -76,7 +74,7 @@ public sealed class DrawObjectState : IDisposable, IReadOnlyDictionary<Model, (A
|
|||
public IEnumerable<(Actor, ObjectIndex, bool)> Values
|
||||
=> _drawObjectToGameObject.Values;
|
||||
|
||||
public unsafe void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
_weaponReload.Unsubscribe(OnWeaponReloading);
|
||||
_weaponReload.Unsubscribe(OnWeaponReloaded);
|
||||
|
|
@ -89,17 +87,16 @@ public sealed class DrawObjectState : IDisposable, IReadOnlyDictionary<Model, (A
|
|||
/// Seems like sometimes the draw object of a game object is destroyed in frames after the original game object is already destroyed.
|
||||
/// So protect against outdated game object pointers in the dictionary.
|
||||
/// </remarks>
|
||||
private unsafe void OnCharacterDestructor(Character* a)
|
||||
private unsafe void OnCharacterDestructor(in CharacterDestructor.Arguments arguments)
|
||||
{
|
||||
if (a is null)
|
||||
if (!arguments.Character.Valid)
|
||||
return;
|
||||
|
||||
var character = (nint)a;
|
||||
var delete = stackalloc nint[5];
|
||||
var current = 0;
|
||||
foreach (var (drawObject, (gameObject, _, _)) in _drawObjectToGameObject)
|
||||
{
|
||||
if (gameObject != character)
|
||||
if (gameObject != arguments.Character.Address)
|
||||
continue;
|
||||
|
||||
delete[current++] = drawObject;
|
||||
|
|
@ -111,28 +108,27 @@ public sealed class DrawObjectState : IDisposable, IReadOnlyDictionary<Model, (A
|
|||
{
|
||||
_drawObjectToGameObject.Remove(*ptr, out var pair);
|
||||
Penumbra.Log.Excessive(
|
||||
$"[DrawObjectState] Removed draw object 0x{*ptr:X} -> 0x{(nint)a:X} (actual: 0x{pair.GameObject.Address:X}, {pair.IsChild}).");
|
||||
$"[DrawObjectState] Removed draw object 0x{*ptr:X} -> 0x{arguments.Character.Address:X} (actual: 0x{pair.GameObject.Address:X}, {pair.IsChild}).");
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void OnWeaponReloading(DrawDataContainer* _, Character* character, CharacterWeapon* _2)
|
||||
=> _gameState.QueueGameObject((nint)character);
|
||||
private void OnWeaponReloading(in WeaponReload.Arguments arguments)
|
||||
=> _gameState.QueueGameObject(arguments.Owner);
|
||||
|
||||
private unsafe void OnWeaponReloaded(DrawDataContainer* _, Character* character)
|
||||
private unsafe void OnWeaponReloaded(in WeaponReload.PostEvent.Arguments arguments)
|
||||
{
|
||||
_gameState.DequeueGameObject();
|
||||
IterateDrawObjectTree((Object*)character->GameObject.DrawObject, (nint)character, false, false);
|
||||
IterateDrawObjectTree((Object*)arguments.Owner.Model.Address, arguments.Owner, false, false);
|
||||
}
|
||||
|
||||
private unsafe void OnCharacterBaseDestructor(CharacterBase* characterBase)
|
||||
=> _drawObjectToGameObject.Remove((nint)characterBase);
|
||||
private void OnCharacterBaseDestructor(in CharacterBaseDestructor.Arguments arguments)
|
||||
=> _drawObjectToGameObject.Remove(arguments.CharacterBase.Address);
|
||||
|
||||
private unsafe void OnCharacterBaseCreated(ModelCharaId modelCharaId, CustomizeArray* customize, CharacterArmor* equipment,
|
||||
CharacterBase* drawObject)
|
||||
private void OnCharacterBaseCreated(in CreateCharacterBase.PostEvent.Arguments arguments)
|
||||
{
|
||||
Actor gameObject = LastGameObject;
|
||||
if (gameObject.Valid)
|
||||
_drawObjectToGameObject[(nint)drawObject] = (gameObject, gameObject.Index, false);
|
||||
_drawObjectToGameObject[arguments.CharacterBase] = (gameObject, gameObject.Index, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
|
|
@ -80,15 +79,15 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(nint A
|
|||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
private void CollectionChangeClear(CollectionType type, ModCollection? _1, ModCollection? _2, string _3)
|
||||
private void CollectionChangeClear(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (type is not (CollectionType.Current or CollectionType.Interface or CollectionType.Inactive))
|
||||
if (arguments.Type is not (CollectionType.Current or CollectionType.Interface or CollectionType.Inactive))
|
||||
_dirty = _cache.Count > 0;
|
||||
}
|
||||
|
||||
private void TerritoryClear(ushort _2)
|
||||
=> _dirty = _cache.Count > 0;
|
||||
|
||||
private void OnCharacterDestructor(Character* character)
|
||||
=> _cache.Remove((nint)character);
|
||||
private void OnCharacterDestructor(in CharacterDestructor.Arguments arguments)
|
||||
=> _cache.Remove(arguments.Character);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -34,7 +34,7 @@ namespace Penumbra.Interop.PathResolving;
|
|||
// ChangeCustomize and RspSetupCharacter, which is hooked here, as well as Character.CalculateHeight.
|
||||
|
||||
// GMP Entries seem to be only used by "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", which is SetupVisor.
|
||||
public sealed unsafe class MetaState : IDisposable, Luna.IService
|
||||
public sealed unsafe class MetaState : IDisposable, IService
|
||||
{
|
||||
public readonly Configuration Config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
|
|
@ -92,27 +92,27 @@ public sealed unsafe class MetaState : IDisposable, Luna.IService
|
|||
_createCharacterBase.Unsubscribe(OnCharacterBaseCreated);
|
||||
}
|
||||
|
||||
private void OnCreatingCharacterBase(ModelCharaId* modelCharaId, CustomizeArray* customize, CharacterArmor* equipData)
|
||||
private void OnCreatingCharacterBase(in CreateCharacterBase.Arguments arguments)
|
||||
{
|
||||
_lastCreatedCollection = _collectionResolver.IdentifyLastGameObjectCollection(true);
|
||||
if (_lastCreatedCollection.Valid && _lastCreatedCollection.AssociatedGameObject != nint.Zero)
|
||||
_communicator.CreatingCharacterBase.Invoke(_lastCreatedCollection.AssociatedGameObject,
|
||||
_lastCreatedCollection.ModCollection.Identity.Id, (nint)modelCharaId, (nint)customize, (nint)equipData);
|
||||
_communicator.CreatingCharacterBase.Invoke(new CreatingCharacterBase.Arguments(_lastCreatedCollection.AssociatedGameObject,
|
||||
_lastCreatedCollection.ModCollection, (nint)Unsafe.AsPointer(ref arguments.ModelCharaId), (nint)arguments.Customize, (nint)arguments.Equipment));
|
||||
|
||||
var decal = new DecalReverter(Config, _characterUtility, _resources, _lastCreatedCollection,
|
||||
UsesDecal(*(uint*)modelCharaId, (nint)customize));
|
||||
UsesDecal(arguments.ModelCharaId, (nint)arguments.Customize));
|
||||
RspCollection.Push(_lastCreatedCollection);
|
||||
_characterBaseCreateMetaChanges.Dispose(); // Should always be empty.
|
||||
_characterBaseCreateMetaChanges = new DisposableContainer(decal);
|
||||
}
|
||||
|
||||
private void OnCharacterBaseCreated(ModelCharaId _1, CustomizeArray* _2, CharacterArmor* _3, CharacterBase* drawObject)
|
||||
private void OnCharacterBaseCreated(in CreateCharacterBase.PostEvent.Arguments arguments)
|
||||
{
|
||||
_characterBaseCreateMetaChanges.Dispose();
|
||||
_characterBaseCreateMetaChanges = DisposableContainer.Empty;
|
||||
if (_lastCreatedCollection.Valid && _lastCreatedCollection.AssociatedGameObject != nint.Zero && drawObject != null)
|
||||
_communicator.CreatedCharacterBase.Invoke(_lastCreatedCollection.AssociatedGameObject,
|
||||
_lastCreatedCollection.ModCollection, (nint)drawObject);
|
||||
if (_lastCreatedCollection.Valid && _lastCreatedCollection.AssociatedGameObject != nint.Zero && arguments.CharacterBase.Valid)
|
||||
_communicator.CreatedCharacterBase.Invoke(new CreatedCharacterBase.Arguments(_lastCreatedCollection.AssociatedGameObject,
|
||||
_lastCreatedCollection.ModCollection, arguments.CharacterBase));
|
||||
RspCollection.Pop();
|
||||
_lastCreatedCollection = ResolveData.Invalid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,6 @@ public sealed unsafe class SubfileHelper : IDisposable, IReadOnlyCollection<KeyV
|
|||
}
|
||||
}
|
||||
|
||||
private void ResourceDestroyed(ResourceHandle* handle)
|
||||
=> _gameState.SubFileCollection.TryRemove((nint)handle, out _);
|
||||
private void ResourceDestroyed(in ResourceHandleDestructor.Arguments arguments)
|
||||
=> _gameState.SubFileCollection.TryRemove((nint)arguments.ResourceHandle, out _);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public unsafe class CharacterUtility : IDisposable, Luna.IRequiredService
|
|||
|
||||
public bool Ready { get; private set; }
|
||||
|
||||
public readonly CharacterUtilityFinished LoadingFinished = new();
|
||||
public readonly CharacterUtilityFinished LoadingFinished;
|
||||
|
||||
public nint DefaultHumanPbdResource { get; private set; }
|
||||
public nint DefaultTransparentResource { get; private set; }
|
||||
|
|
@ -56,14 +56,16 @@ public unsafe class CharacterUtility : IDisposable, Luna.IRequiredService
|
|||
|
||||
private readonly IFramework _framework;
|
||||
|
||||
public CharacterUtility(IFramework framework, IGameInteropProvider interop)
|
||||
public CharacterUtility(IFramework framework, IGameInteropProvider interop, CharacterUtilityFinished finished)
|
||||
{
|
||||
LoadingFinished = finished;
|
||||
interop.InitializeFromAttributes(this);
|
||||
_lists = Enumerable.Range(0, RelevantIndices.Length)
|
||||
.Select(idx => new MetaList(new InternalIndex(idx)))
|
||||
.ToArray();
|
||||
_framework = framework;
|
||||
LoadingFinished.Subscribe(() => Penumbra.Log.Debug("Loading of CharacterUtility finished."), CharacterUtilityFinished.Priority.OnFinishedLoading);
|
||||
_framework = framework;
|
||||
LoadingFinished.Subscribe(() => Penumbra.Log.Debug("Loading of CharacterUtility finished."),
|
||||
CharacterUtilityFinished.Priority.OnFinishedLoading);
|
||||
LoadDefaultResources(null!);
|
||||
if (!Ready)
|
||||
_framework.Update += LoadDefaultResources;
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ public sealed unsafe partial class RedrawService : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private void OnModFileChanged(Mod _1, FileRegistry _2)
|
||||
private void OnModFileChanged(in ModFileChanged.Arguments _)
|
||||
{
|
||||
if (!_config.Ephemeral.ForceRedrawOnFileChange)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -3,17 +3,16 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Penumbra.Collections;
|
||||
using Luna;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Mods.Editor;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
namespace Penumbra.Interop.Services;
|
||||
|
||||
public unsafe class SchedulerResourceManagementService : Luna.IService, IDisposable
|
||||
public unsafe class SchedulerResourceManagementService : IService, IDisposable
|
||||
{
|
||||
private static readonly CiByteString TmbExtension = new(".tmb"u8, MetaDataComputation.All);
|
||||
private static readonly CiByteString FolderPrefix = new("chara/action/"u8, MetaDataComputation.All);
|
||||
|
|
@ -40,16 +39,15 @@ public unsafe class SchedulerResourceManagementService : Luna.IService, IDisposa
|
|||
interop.InitializeFromAttributes(this);
|
||||
}
|
||||
|
||||
private void OnResolvedFileChange(ModCollection collection, ResolvedFileChanged.Type type, Utf8GamePath gamePath, FullPath oldPath,
|
||||
FullPath newPath, IMod? mod)
|
||||
private void OnResolvedFileChange(in ResolvedFileChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ResolvedFileChanged.Type.Added:
|
||||
CheckFile(gamePath);
|
||||
CheckFile(arguments.GamePath);
|
||||
return;
|
||||
case ResolvedFileChanged.Type.FullRecomputeFinished:
|
||||
foreach (var path in collection.ResolvedFiles.Keys)
|
||||
foreach (var path in arguments.Collection.ResolvedFiles.Keys)
|
||||
CheckFile(path);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Cache;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
|
@ -41,27 +40,27 @@ public unsafe class ShapeAttributeManager : Luna.IRequiredService, IDisposable
|
|||
public void Dispose()
|
||||
=> _attributeHook.Unsubscribe(OnAttributeComputed);
|
||||
|
||||
private void OnAttributeComputed(Actor actor, Model model, ModCollection collection)
|
||||
private void OnAttributeComputed(in AttributeHook.Arguments arguments)
|
||||
{
|
||||
if (!collection.HasCache)
|
||||
if (!arguments.Collection.HasCache)
|
||||
return;
|
||||
|
||||
_genderRace = (GenderRace)model.AsHuman->RaceSexId;
|
||||
_genderRace = (GenderRace)arguments.Human.AsHuman->RaceSexId;
|
||||
for (_slotIndex = 0; _slotIndex < NumSlots; ++_slotIndex)
|
||||
{
|
||||
_modelIndex = UsedModels[_slotIndex];
|
||||
_model = model.AsHuman->Models[_modelIndex.ToIndex()];
|
||||
_model = arguments.Human.AsHuman->Models[_modelIndex.ToIndex()];
|
||||
if (_model is null || _model->ModelResourceHandle is null)
|
||||
continue;
|
||||
|
||||
_ids[(int)_modelIndex] = model.GetModelId(_modelIndex);
|
||||
CheckShapes(collection.MetaCache!.Shp);
|
||||
CheckAttributes(collection.MetaCache!.Atr);
|
||||
_ids[(int)_modelIndex] = arguments.Human.GetModelId(_modelIndex);
|
||||
CheckShapes(arguments.Collection.MetaCache!.Shp);
|
||||
CheckAttributes(arguments.Collection.MetaCache!.Atr);
|
||||
if (_modelIndex is <= HumanSlot.LFinger and >= HumanSlot.Ears)
|
||||
AccessoryImcCheck(model);
|
||||
AccessoryImcCheck(arguments.Human);
|
||||
}
|
||||
|
||||
UpdateDefaultMasks(model, collection.MetaCache!.Shp);
|
||||
UpdateDefaultMasks(arguments.Human, arguments.Collection.MetaCache!.Shp);
|
||||
}
|
||||
|
||||
private void AccessoryImcCheck(Model model)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Luna.Files;
|
||||
using Luna;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.SubMods;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Mods.SubMods;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -137,7 +138,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
|
|||
try
|
||||
{
|
||||
File.Delete(file.File.FullName);
|
||||
communicator.ModFileChanged.Invoke(mod, file);
|
||||
communicator.ModFileChanged.Invoke(new ModFileChanged.Arguments(mod, file));
|
||||
Penumbra.Log.Debug($"[DeleteFiles] Deleted {file.File.FullName} from {mod.Name}.");
|
||||
++deletions;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Utility;
|
||||
using Luna;
|
||||
using Luna.Files;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Groups;
|
||||
|
|
@ -478,27 +477,27 @@ public class ModMerger : IDisposable, IService
|
|||
}
|
||||
}
|
||||
|
||||
private void OnSelectionChange(Mod? oldSelection, Mod? newSelection)
|
||||
private void OnSelectionChange(in ModSelection.Arguments arguments)
|
||||
{
|
||||
if (OptionGroupName == "Merges" && OptionName.Length == 0 || OptionName == oldSelection?.Name.Text)
|
||||
OptionName = newSelection?.Name.Text ?? string.Empty;
|
||||
if (OptionGroupName == "Merges" && OptionName.Length == 0 || OptionName == arguments.OldSelection?.Name.Text)
|
||||
OptionName = arguments.NewSelection?.Name.Text ?? string.Empty;
|
||||
|
||||
if (MergeToMod == newSelection)
|
||||
if (MergeToMod == arguments.NewSelection)
|
||||
MergeToMod = null;
|
||||
|
||||
SelectedOptions.Clear();
|
||||
}
|
||||
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? _1, DirectoryInfo? _2)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Deleted:
|
||||
{
|
||||
if (mod == MergeFromMod)
|
||||
if (arguments.Mod == MergeFromMod)
|
||||
SelectedOptions.Clear();
|
||||
|
||||
if (mod == MergeToMod)
|
||||
if (arguments.Mod == MergeToMod)
|
||||
MergeToMod = null;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Luna;
|
||||
using Luna.Files;
|
||||
using OtterGui.Tasks;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Luna.Files;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Mods.SubMods;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
|
|
@ -39,52 +37,51 @@ public class ModCacheManager : IDisposable, Luna.IService
|
|||
_communicator.ModDiscoveryFinished.Unsubscribe(OnModDiscoveryFinished);
|
||||
}
|
||||
|
||||
private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
|
||||
int fromIdx)
|
||||
private void OnModOptionChange(in ModOptionChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModOptionChangeType.GroupAdded:
|
||||
case ModOptionChangeType.GroupDeleted:
|
||||
case ModOptionChangeType.OptionAdded:
|
||||
case ModOptionChangeType.OptionDeleted:
|
||||
UpdateChangedItems(mod);
|
||||
UpdateCounts(mod);
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateCounts(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.GroupTypeChanged:
|
||||
UpdateHasOptions(mod);
|
||||
UpdateHasOptions(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionFilesChanged:
|
||||
case ModOptionChangeType.OptionFilesAdded:
|
||||
UpdateChangedItems(mod);
|
||||
UpdateFileCount(mod);
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateFileCount(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionSwapsChanged:
|
||||
UpdateChangedItems(mod);
|
||||
UpdateSwapCount(mod);
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateSwapCount(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionMetaChanged:
|
||||
UpdateChangedItems(mod);
|
||||
UpdateMetaCount(mod);
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateMetaCount(arguments.Mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? old, DirectoryInfo? @new)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Added:
|
||||
case ModPathChangeType.Reloaded:
|
||||
RefreshWithChangedItems(mod);
|
||||
RefreshWithChangedItems(arguments.Mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnModDataChange(ModDataChangeType type, Mod mod, string? _)
|
||||
private static void OnModDataChange(in ModDataChanged.Arguments arguments)
|
||||
{
|
||||
if ((type & (ModDataChangeType.LocalTags | ModDataChangeType.ModTags)) != 0)
|
||||
UpdateTags(mod);
|
||||
if ((arguments.Type & (ModDataChangeType.LocalTags | ModDataChangeType.ModTags)) is not 0)
|
||||
UpdateTags(arguments.Mod);
|
||||
}
|
||||
|
||||
private void OnModDiscoveryFinished()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Dalamud.Utility;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -55,7 +56,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
var oldName = mod.Name;
|
||||
mod.Name = newName;
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.Name, mod, oldName.Text);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.Name, mod, oldName.Text));
|
||||
}
|
||||
|
||||
public void ChangeModAuthor(Mod mod, string newAuthor)
|
||||
|
|
@ -65,7 +66,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.Author = newAuthor;
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.Author, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.Author, mod, null));
|
||||
}
|
||||
|
||||
public void ChangeModDescription(Mod mod, string newDescription)
|
||||
|
|
@ -75,7 +76,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.Description = newDescription;
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.Description, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.Description, mod, null));
|
||||
}
|
||||
|
||||
public void ChangeModVersion(Mod mod, string newVersion)
|
||||
|
|
@ -85,7 +86,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.Version = newVersion;
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.Version, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.Version, mod, null));
|
||||
}
|
||||
|
||||
public void ChangeModWebsite(Mod mod, string newWebsite)
|
||||
|
|
@ -95,7 +96,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.Website = newWebsite;
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.Website, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.Website, mod, null));
|
||||
}
|
||||
|
||||
public void ChangeRequiredFeatures(Mod mod, FeatureFlags flags)
|
||||
|
|
@ -105,7 +106,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.RequiredFeatures = flags;
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.RequiredFeatures, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.RequiredFeatures, mod, null));
|
||||
}
|
||||
|
||||
public void ChangeModTag(Mod mod, int tagIdx, string newTag)
|
||||
|
|
@ -121,7 +122,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.Favorite = state;
|
||||
saveService.QueueSave(new ModLocalData(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.Favorite, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.Favorite, mod, null));
|
||||
}
|
||||
|
||||
public void ResetModImportDate(Mod mod)
|
||||
|
|
@ -132,7 +133,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.ImportDate = newDate;
|
||||
saveService.QueueSave(new ModLocalData(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.ImportDate, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.ImportDate, mod, null));
|
||||
}
|
||||
|
||||
public void ChangeModNote(Mod mod, string newNote)
|
||||
|
|
@ -142,7 +143,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
|
||||
mod.Note = newNote;
|
||||
saveService.QueueSave(new ModLocalData(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.Favorite, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.Favorite, mod, null));
|
||||
}
|
||||
|
||||
private void ChangeTag(Mod mod, int tagIdx, string newTag, bool local)
|
||||
|
|
@ -170,7 +171,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
saveService.QueueSave(new ModLocalData(mod));
|
||||
|
||||
if (flags != 0)
|
||||
communicatorService.ModDataChanged.Invoke(flags, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(flags, mod, null));
|
||||
}
|
||||
|
||||
public void MoveDataFile(DirectoryInfo oldMod, DirectoryInfo newMod)
|
||||
|
|
@ -196,13 +197,13 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
{
|
||||
++mod.LastChangedItemsUpdate;
|
||||
saveService.QueueSave(new ModLocalData(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.PreferredChangedItems, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.PreferredChangedItems, mod, null));
|
||||
}
|
||||
|
||||
if (toDefault && CleanExisting(mod.DefaultPreferredItems))
|
||||
{
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.DefaultChangedItems, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.DefaultChangedItems, mod, null));
|
||||
}
|
||||
|
||||
bool CleanExisting(HashSet<CustomItemId> items)
|
||||
|
|
@ -251,13 +252,13 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
{
|
||||
++mod.LastChangedItemsUpdate;
|
||||
saveService.QueueSave(new ModLocalData(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.PreferredChangedItems, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.PreferredChangedItems, mod, null));
|
||||
}
|
||||
|
||||
if (fromDefault && mod.DefaultPreferredItems.Remove(id))
|
||||
{
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.DefaultChangedItems, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.DefaultChangedItems, mod, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +272,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
mod.PreferredChangedItems = newSet;
|
||||
++mod.LastChangedItemsUpdate;
|
||||
saveService.QueueSave(new ModLocalData(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.PreferredChangedItems, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.PreferredChangedItems, mod, null));
|
||||
}
|
||||
|
||||
newSet = new HashSet<CustomItemId>(mod.DefaultPreferredItems.Count);
|
||||
|
|
@ -279,7 +280,7 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
{
|
||||
mod.DefaultPreferredItems = newSet;
|
||||
saveService.QueueSave(new ModMeta(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.DefaultChangedItems, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.DefaultChangedItems, mod, null));
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -308,6 +309,6 @@ public class ModDataEditor(SaveService saveService, CommunicatorService communic
|
|||
mod.PreferredChangedItems.UnionWith(mod.DefaultPreferredItems);
|
||||
++mod.LastChangedItemsUpdate;
|
||||
saveService.QueueSave(new ModLocalData(mod));
|
||||
communicatorService.ModDataChanged.Invoke(ModDataChangeType.PreferredChangedItems, mod, null);
|
||||
communicatorService.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.PreferredChangedItems, mod, null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,14 +79,13 @@ public class ModExportManager : IDisposable, Luna.IService
|
|||
=> _communicator.ModPathChanged.Unsubscribe(OnModPathChange);
|
||||
|
||||
/// <summary> Automatically migrate the backup file to the new name if any exists. </summary>
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||
DirectoryInfo? newDirectory)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
if (type is not ModPathChangeType.Moved || oldDirectory == null || newDirectory == null)
|
||||
if (arguments.Type is not ModPathChangeType.Moved || arguments.OldDirectory is null || arguments.NewDirectory is null)
|
||||
return;
|
||||
|
||||
mod.ModPath = oldDirectory;
|
||||
new ModBackup(this, mod).Move(null, newDirectory.Name);
|
||||
mod.ModPath = newDirectory;
|
||||
arguments.Mod.ModPath = arguments.OldDirectory;
|
||||
new ModBackup(this, arguments.Mod).Move(null, arguments.NewDirectory.Name);
|
||||
arguments.Mod.ModPath = arguments.NewDirectory;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,21 +77,21 @@ public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable, ISer
|
|||
}
|
||||
|
||||
// Update sort order when defaulted mod names change.
|
||||
private void OnModDataChange(ModDataChangeType type, Mod mod, string? oldName)
|
||||
private void OnModDataChange(in ModDataChanged.Arguments arguments)
|
||||
{
|
||||
if (!type.HasFlag(ModDataChangeType.Name) || oldName == null || !TryGetValue(mod, out var leaf))
|
||||
if (!arguments.Type.HasFlag(ModDataChangeType.Name) || arguments.OldName == null || !TryGetValue(arguments.Mod, out var leaf))
|
||||
return;
|
||||
|
||||
var old = oldName.FixName();
|
||||
var old = arguments.OldName.FixName();
|
||||
if (old == leaf.Name || leaf.Name.IsDuplicateName(out var baseName, out _) && baseName == old)
|
||||
RenameWithDuplicates(leaf, mod.Name.Text);
|
||||
RenameWithDuplicates(leaf, arguments.Mod.Name.Text);
|
||||
}
|
||||
|
||||
// Update the filesystem if a mod has been added or removed.
|
||||
// Save it, if the mod directory has been moved, since this will change the save format.
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldPath, DirectoryInfo? newPath)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Added:
|
||||
var parent = Root;
|
||||
|
|
@ -103,14 +103,14 @@ public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable, ISer
|
|||
catch (Exception e)
|
||||
{
|
||||
Penumbra.Messager.NotificationMessage(e,
|
||||
$"Could not move newly imported mod {mod.Name} to default import folder {_config.DefaultImportFolder}.",
|
||||
$"Could not move newly imported mod {arguments.Mod.Name} to default import folder {_config.DefaultImportFolder}.",
|
||||
NotificationType.Warning);
|
||||
}
|
||||
|
||||
CreateDuplicateLeaf(parent, mod.Name.Text, mod);
|
||||
CreateDuplicateLeaf(parent, arguments.Mod.Name.Text, arguments.Mod);
|
||||
break;
|
||||
case ModPathChangeType.Deleted:
|
||||
if (TryGetValue(mod, out var leaf))
|
||||
if (TryGetValue(arguments.Mod, out var leaf))
|
||||
Delete(leaf);
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
|
||||
mod.Index = Count;
|
||||
Mods.Add(mod);
|
||||
_communicator.ModPathChanged.Invoke(ModPathChangeType.Added, mod, null, mod.ModPath);
|
||||
_communicator.ModPathChanged.Invoke(new ModPathChanged.Arguments(ModPathChangeType.Added, mod, null, mod.ModPath));
|
||||
Penumbra.Log.Debug($"Added new mod {mod.Name} from {modFolder.FullName}.");
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
/// </summary>
|
||||
public void RemoveMod(Mod mod)
|
||||
{
|
||||
_communicator.ModPathChanged.Invoke(ModPathChangeType.Deleted, mod, mod.ModPath, null);
|
||||
_communicator.ModPathChanged.Invoke(new ModPathChanged.Arguments(ModPathChangeType.Deleted, mod, mod.ModPath, null));
|
||||
foreach (var remainingMod in Mods.Skip(mod.Index + 1))
|
||||
--remainingMod.Index;
|
||||
Mods.RemoveAt(mod.Index);
|
||||
|
|
@ -140,7 +140,7 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
{
|
||||
var oldName = mod.Name;
|
||||
|
||||
_communicator.ModPathChanged.Invoke(ModPathChangeType.StartingReload, mod, mod.ModPath, mod.ModPath);
|
||||
_communicator.ModPathChanged.Invoke(new ModPathChanged.Arguments(ModPathChangeType.StartingReload, mod, mod.ModPath, mod.ModPath));
|
||||
if (!Creator.ReloadMod(mod, true, false, out var metaChange))
|
||||
{
|
||||
if (mod.RequiredFeatures is not FeatureFlags.Invalid)
|
||||
|
|
@ -151,9 +151,9 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
return;
|
||||
}
|
||||
|
||||
_communicator.ModPathChanged.Invoke(ModPathChangeType.Reloaded, mod, mod.ModPath, mod.ModPath);
|
||||
_communicator.ModPathChanged.Invoke(new ModPathChanged.Arguments(ModPathChangeType.Reloaded, mod, mod.ModPath, mod.ModPath));
|
||||
if (metaChange != ModDataChangeType.None)
|
||||
_communicator.ModDataChanged.Invoke(metaChange, mod, oldName);
|
||||
_communicator.ModDataChanged.Invoke(new ModDataChanged.Arguments(metaChange, mod, oldName));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -213,9 +213,9 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
return;
|
||||
}
|
||||
|
||||
_communicator.ModPathChanged.Invoke(ModPathChangeType.Moved, mod, oldDirectory, dir);
|
||||
_communicator.ModPathChanged.Invoke(new ModPathChanged.Arguments(ModPathChangeType.Moved, mod, oldDirectory, dir));
|
||||
if (metaChange != ModDataChangeType.None)
|
||||
_communicator.ModDataChanged.Invoke(metaChange, mod, oldName);
|
||||
_communicator.ModDataChanged.Invoke(new ModDataChanged.Arguments(metaChange, mod, oldName));
|
||||
}
|
||||
|
||||
/// <summary> Return the state of the new potential name of a directory. </summary>
|
||||
|
|
@ -247,16 +247,15 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
|
||||
|
||||
/// <summary> Add new mods to NewMods and remove deleted mods from NewMods. </summary>
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||
DirectoryInfo? newDirectory)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Added: SetNew(mod); break;
|
||||
case ModPathChangeType.Deleted: SetKnown(mod); break;
|
||||
case ModPathChangeType.Added: SetNew(arguments.Mod); break;
|
||||
case ModPathChangeType.Deleted: SetKnown(arguments.Mod); break;
|
||||
case ModPathChangeType.Moved:
|
||||
if (oldDirectory != null && newDirectory != null)
|
||||
DataEditor.MoveDataFile(oldDirectory, newDirectory);
|
||||
if (arguments.OldDirectory is not null && arguments.NewDirectory is not null)
|
||||
DataEditor.MoveDataFile(arguments.OldDirectory, arguments.NewDirectory);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -313,7 +312,7 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
_config.ModDirectory = newPath;
|
||||
_config.Save();
|
||||
Penumbra.Log.Information($"Set new mod base directory from {_config.ModDirectory} to {newPath}.");
|
||||
_communicator.ModDirectoryChanged.Invoke(newPath, valid);
|
||||
_communicator.ModDirectoryChanged.Invoke(new ModDirectoryChanged.Arguments(newPath, valid));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -346,7 +345,7 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
|
|||
catch (Exception ex)
|
||||
{
|
||||
Valid = false;
|
||||
_communicator.ModDirectoryChanged.Invoke(BasePath.FullName, false);
|
||||
_communicator.ModDirectoryChanged.Invoke(new ModDirectoryChanged.Arguments(BasePath.FullName, false));
|
||||
Penumbra.Log.Error($"Could not scan for mods:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Luna;
|
||||
using Luna.Files;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Settings;
|
||||
using Penumbra.Mods.SubMods;
|
||||
|
|
@ -42,6 +42,6 @@ public sealed class CombiningModGroupEditor(CommunicatorService communicator, Sa
|
|||
|
||||
container.Name = name;
|
||||
SaveService.Save(saveType, new ModSaveGroup(container.Group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, container.Group.Mod, container.Group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.DisplayChange, container.Group.Mod, container.Group, null, null, -1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Luna.Files;
|
||||
using Luna;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods.Groups;
|
||||
|
|
@ -10,7 +11,7 @@ using Penumbra.Services;
|
|||
namespace Penumbra.Mods.Manager.OptionEditor;
|
||||
|
||||
public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveService saveService, Configuration config)
|
||||
: ModOptionEditor<ImcModGroup, ImcSubMod>(communicator, saveService, config), Luna.IService
|
||||
: ModOptionEditor<ImcModGroup, ImcSubMod>(communicator, saveService, config), IService
|
||||
{
|
||||
/// <summary> Add a new, empty imc group with the given manipulation data. </summary>
|
||||
public ImcModGroup? AddModGroup(Mod mod, string newName, ImcIdentifier identifier, ImcEntry defaultEntry,
|
||||
|
|
@ -23,7 +24,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
var group = CreateGroup(mod, newName, identifier, defaultEntry, maxPriority);
|
||||
mod.Groups.Add(group);
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.GroupAdded, mod, group, null, null, -1));
|
||||
return group;
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +42,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
};
|
||||
group.OptionData.Add(subMod);
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionAdded, group.Mod, group, subMod, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionAdded, group.Mod, group, subMod, null, -1));
|
||||
return subMod;
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
return;
|
||||
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
public void ChangeDefaultEntry(ImcModGroup group, in ImcEntry newEntry, SaveType saveType = SaveType.Queue)
|
||||
|
|
@ -66,7 +67,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
|
||||
group.DefaultEntry = entry;
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
public void ChangeOptionAttribute(ImcSubMod option, in ImcAttributeCache cache, int idx, bool value, SaveType saveType = SaveType.Queue)
|
||||
|
|
@ -75,7 +76,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
return;
|
||||
|
||||
SaveService.Save(saveType, new ModSaveGroup(option.Group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, option.Mod, option.Group, option, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMetaChanged, option.Mod, option.Group, option, null, -1));
|
||||
}
|
||||
|
||||
public void ChangeAllVariants(ImcModGroup group, bool allVariants, SaveType saveType = SaveType.Queue)
|
||||
|
|
@ -85,7 +86,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
|
||||
group.AllVariants = allVariants;
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
public void ChangeOnlyAttributes(ImcModGroup group, bool onlyAttributes, SaveType saveType = SaveType.Queue)
|
||||
|
|
@ -95,7 +96,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
|
||||
group.OnlyAttributes = onlyAttributes;
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
public void ChangeCanBeDisabled(ImcModGroup group, bool canBeDisabled, SaveType saveType = SaveType.Queue)
|
||||
|
|
@ -105,7 +106,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
|
||||
group.CanBeDisabled = canBeDisabled;
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
protected override ImcModGroup CreateGroup(Mod mod, string newName, ModPriority priority, SaveType saveType = SaveType.ImmediateSync)
|
||||
|
|
@ -116,8 +117,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
};
|
||||
|
||||
|
||||
private static ImcModGroup CreateGroup(Mod mod, string newName, ImcIdentifier identifier, ImcEntry defaultEntry, ModPriority priority,
|
||||
SaveType saveType = SaveType.ImmediateSync)
|
||||
private static ImcModGroup CreateGroup(Mod mod, string newName, ImcIdentifier identifier, ImcEntry defaultEntry, ModPriority priority, SaveType saveType = SaveType.ImmediateSync)
|
||||
=> new(mod)
|
||||
{
|
||||
Name = newName,
|
||||
|
|
@ -137,7 +137,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
|
|||
|
||||
protected override bool MoveOption(ImcModGroup group, int optionIdxFrom, int optionIdxTo)
|
||||
{
|
||||
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
|
||||
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo))
|
||||
return false;
|
||||
|
||||
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Luna.Files;
|
||||
using Luna;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Settings;
|
||||
|
|
@ -62,7 +62,7 @@ public class ModGroupEditor(
|
|||
|
||||
group.DefaultSettings = defaultOption;
|
||||
saveService.QueueSave(new ModSaveGroup(group, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.DefaultOptionChanged, group.Mod, group, null, null, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.DefaultOptionChanged, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
/// <summary> Rename an option group if possible. </summary>
|
||||
|
|
@ -75,7 +75,7 @@ public class ModGroupEditor(
|
|||
saveService.ImmediateDelete(new ModSaveGroup(group, config.ReplaceNonAsciiOnImport));
|
||||
group.Name = newName;
|
||||
saveService.ImmediateSave(new ModSaveGroup(group, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupRenamed, group.Mod, group, null, null, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.GroupRenamed, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
/// <summary> Delete a given option group. Fires an event to prepare before actually deleting. </summary>
|
||||
|
|
@ -83,10 +83,10 @@ public class ModGroupEditor(
|
|||
{
|
||||
var mod = group.Mod;
|
||||
var idx = group.GetIndex();
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, group, null, null, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.PrepareChange, mod, group, null, null, -1));
|
||||
mod.Groups.RemoveAt(idx);
|
||||
saveService.SaveAllOptionGroups(mod, false, config.ReplaceNonAsciiOnImport);
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupDeleted, mod, null, null, null, idx);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.GroupDeleted, mod, null, null, null, idx));
|
||||
}
|
||||
|
||||
/// <summary> Move the index of a given option group. </summary>
|
||||
|
|
@ -98,7 +98,7 @@ public class ModGroupEditor(
|
|||
return;
|
||||
|
||||
saveService.SaveAllOptionGroups(mod, false, config.ReplaceNonAsciiOnImport);
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupMoved, mod, group, null, null, idxFrom);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.GroupMoved, mod, group, null, null, idxFrom));
|
||||
}
|
||||
|
||||
/// <summary> Change the internal priority of the given option group. </summary>
|
||||
|
|
@ -109,7 +109,7 @@ public class ModGroupEditor(
|
|||
|
||||
group.Priority = newPriority;
|
||||
saveService.QueueSave(new ModSaveGroup(group, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PriorityChanged, group.Mod, group, null, null, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.PriorityChanged, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
/// <summary> Change the description of the given option group. </summary>
|
||||
|
|
@ -120,7 +120,7 @@ public class ModGroupEditor(
|
|||
|
||||
group.Description = newDescription;
|
||||
saveService.QueueSave(new ModSaveGroup(group, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, group.Mod, group, null, null, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.DisplayChange, group.Mod, group, null, null, -1));
|
||||
}
|
||||
|
||||
/// <summary> Rename the given option. </summary>
|
||||
|
|
@ -131,7 +131,7 @@ public class ModGroupEditor(
|
|||
|
||||
option.Name = newName;
|
||||
saveService.QueueSave(new ModSaveGroup(option.Group, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, option.Mod, option.Group, option, null, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.DisplayChange, option.Mod, option.Group, option, null, -1));
|
||||
}
|
||||
|
||||
/// <summary> Change the description of the given option. </summary>
|
||||
|
|
@ -142,7 +142,7 @@ public class ModGroupEditor(
|
|||
|
||||
option.Description = newDescription;
|
||||
saveService.QueueSave(new ModSaveGroup(option.Group, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, option.Mod, option.Group, option, null, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.DisplayChange, option.Mod, option.Group, option, null, -1));
|
||||
}
|
||||
|
||||
/// <summary> Set the meta manipulations for a given option. Replaces existing manipulations. </summary>
|
||||
|
|
@ -151,10 +151,10 @@ public class ModGroupEditor(
|
|||
if (subMod.Manipulations.Equals(manipulations))
|
||||
return;
|
||||
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, (Mod)subMod.Mod, subMod.Group, null, subMod, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.PrepareChange, (Mod)subMod.Mod, subMod.Group, null, subMod, -1));
|
||||
subMod.Manipulations.SetTo(manipulations);
|
||||
saveService.Save(saveType, new ModSaveGroup(subMod, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, (Mod)subMod.Mod, subMod.Group, null, subMod, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMetaChanged, (Mod)subMod.Mod, subMod.Group, null, subMod, -1));
|
||||
}
|
||||
|
||||
/// <summary> Set the file redirections for a given option. Replaces existing redirections. </summary>
|
||||
|
|
@ -163,10 +163,10 @@ public class ModGroupEditor(
|
|||
if (subMod.Files.SetEquals(replacements))
|
||||
return;
|
||||
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, (Mod)subMod.Mod, subMod.Group, null, subMod, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.PrepareChange, (Mod)subMod.Mod, subMod.Group, null, subMod, -1));
|
||||
subMod.Files.SetTo(replacements);
|
||||
saveService.Save(saveType, new ModSaveGroup(subMod, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionFilesChanged, (Mod)subMod.Mod, subMod.Group, null, subMod, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionFilesChanged, (Mod)subMod.Mod, subMod.Group, null, subMod, -1));
|
||||
}
|
||||
|
||||
/// <summary> Forces a file save of the given container's group. </summary>
|
||||
|
|
@ -181,7 +181,7 @@ public class ModGroupEditor(
|
|||
if (oldCount != subMod.Files.Count)
|
||||
{
|
||||
saveService.QueueSave(new ModSaveGroup(subMod, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionFilesAdded, (Mod)subMod.Mod, subMod.Group, null, subMod, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionFilesAdded, (Mod)subMod.Mod, subMod.Group, null, subMod, -1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,10 +191,10 @@ public class ModGroupEditor(
|
|||
if (subMod.FileSwaps.SetEquals(swaps))
|
||||
return;
|
||||
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, (Mod)subMod.Mod, subMod.Group, null, subMod, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.PrepareChange, (Mod)subMod.Mod, subMod.Group, null, subMod, -1));
|
||||
subMod.FileSwaps.SetTo(swaps);
|
||||
saveService.Save(saveType, new ModSaveGroup(subMod, config.ReplaceNonAsciiOnImport));
|
||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionSwapsChanged, (Mod)subMod.Mod, subMod.Group, null, subMod, -1);
|
||||
communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionSwapsChanged, (Mod)subMod.Mod, subMod.Group, null, subMod, -1));
|
||||
}
|
||||
|
||||
/// <summary> Verify that a new option group name is unique in this mod. </summary>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Luna;
|
||||
using Luna.Files;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Settings;
|
||||
using Penumbra.Mods.SubMods;
|
||||
|
|
@ -28,7 +28,7 @@ public abstract class ModOptionEditor<TGroup, TOption>(
|
|||
var group = CreateGroup(mod, newName, maxPriority);
|
||||
mod.Groups.Add(group);
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, group, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.GroupAdded, mod, group, null, null, -1));
|
||||
return group;
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ public abstract class ModOptionEditor<TGroup, TOption>(
|
|||
return null;
|
||||
|
||||
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionAdded, group.Mod, group, option, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionAdded, group.Mod, group, option, null, -1));
|
||||
return option;
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ public abstract class ModOptionEditor<TGroup, TOption>(
|
|||
return null;
|
||||
|
||||
SaveService.QueueSave(new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionAdded, group.Mod, group, clonedOption, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionAdded, group.Mod, group, clonedOption, null, -1));
|
||||
return clonedOption;
|
||||
}
|
||||
|
||||
|
|
@ -95,10 +95,10 @@ public abstract class ModOptionEditor<TGroup, TOption>(
|
|||
var mod = option.Mod;
|
||||
var group = option.Group;
|
||||
var optionIdx = option.GetIndex();
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, group, option, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.PrepareChange, mod, group, option, null, -1));
|
||||
RemoveOption((TGroup)group, optionIdx);
|
||||
SaveService.QueueSave(new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionDeleted, mod, group, null, null, optionIdx);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionDeleted, mod, group, null, null, optionIdx));
|
||||
}
|
||||
|
||||
/// <summary> Move an option inside the given option group. </summary>
|
||||
|
|
@ -110,7 +110,7 @@ public abstract class ModOptionEditor<TGroup, TOption>(
|
|||
return;
|
||||
|
||||
SaveService.QueueSave(new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMoved, group.Mod, group, option, null, idx);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.OptionMoved, group.Mod, group, option, null, idx));
|
||||
}
|
||||
|
||||
protected abstract TGroup CreateGroup(Mod mod, string newName, ModPriority priority, SaveType saveType = SaveType.ImmediateSync);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Luna.Files;
|
||||
using Luna;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Settings;
|
||||
using Penumbra.Mods.SubMods;
|
||||
|
|
@ -16,7 +17,7 @@ public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveSe
|
|||
var singleGroup = group.ConvertToSingle();
|
||||
group.Mod.Groups[idx] = singleGroup;
|
||||
SaveService.QueueSave(new ModSaveGroup(singleGroup, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupTypeChanged, singleGroup.Mod, singleGroup, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.GroupTypeChanged, singleGroup.Mod, singleGroup, null, null, -1));
|
||||
}
|
||||
|
||||
/// <summary> Change the internal priority of the given option. </summary>
|
||||
|
|
@ -27,7 +28,7 @@ public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveSe
|
|||
|
||||
option.Priority = newPriority;
|
||||
SaveService.QueueSave(new ModSaveGroup(option.Group, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.PriorityChanged, option.Mod, option.Group, option, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.PriorityChanged, option.Mod, option.Group, option, null, -1));
|
||||
}
|
||||
|
||||
protected override MultiModGroup CreateGroup(Mod mod, string newName, ModPriority priority, SaveType saveType = SaveType.ImmediateSync)
|
||||
|
|
@ -74,7 +75,7 @@ public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveSe
|
|||
|
||||
protected override bool MoveOption(MultiModGroup group, int optionIdxFrom, int optionIdxTo)
|
||||
{
|
||||
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
|
||||
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo))
|
||||
return false;
|
||||
|
||||
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Luna.Files;
|
||||
using Luna;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods.Groups;
|
||||
using Penumbra.Mods.Settings;
|
||||
using Penumbra.Mods.SubMods;
|
||||
|
|
@ -8,7 +9,7 @@ using Penumbra.Services;
|
|||
namespace Penumbra.Mods.Manager.OptionEditor;
|
||||
|
||||
public sealed class SingleModGroupEditor(CommunicatorService communicator, SaveService saveService, Configuration config)
|
||||
: ModOptionEditor<SingleModGroup, SingleSubMod>(communicator, saveService, config), Luna.IService
|
||||
: ModOptionEditor<SingleModGroup, SingleSubMod>(communicator, saveService, config), IService
|
||||
{
|
||||
public void ChangeToMulti(SingleModGroup group)
|
||||
{
|
||||
|
|
@ -16,7 +17,7 @@ public sealed class SingleModGroupEditor(CommunicatorService communicator, SaveS
|
|||
var multiGroup = group.ConvertToMulti();
|
||||
group.Mod.Groups[idx] = multiGroup;
|
||||
SaveService.QueueSave(new ModSaveGroup(multiGroup, Config.ReplaceNonAsciiOnImport));
|
||||
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupTypeChanged, multiGroup.Mod, multiGroup, null, null, -1);
|
||||
Communicator.ModOptionChanged.Invoke(new ModOptionChanged.Arguments(ModOptionChangeType.GroupTypeChanged, multiGroup.Mod, multiGroup, null, null, -1));
|
||||
}
|
||||
|
||||
protected override SingleModGroup CreateGroup(Mod mod, string newName, ModPriority priority, SaveType saveType = SaveType.ImmediateSync)
|
||||
|
|
@ -47,7 +48,7 @@ public sealed class SingleModGroupEditor(CommunicatorService communicator, SaveS
|
|||
|
||||
protected override bool MoveOption(SingleModGroup group, int optionIdxFrom, int optionIdxTo)
|
||||
{
|
||||
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
|
||||
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo))
|
||||
return false;
|
||||
|
||||
group.DefaultSettings = group.DefaultSettings.MoveSingle(optionIdxFrom, optionIdxTo);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.Api.Enums;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
|
|
@ -16,14 +15,14 @@ namespace Penumbra.Mods;
|
|||
/// <item>Parameter is the new selected mod </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public class ModSelection : EventWrapper<Mod?, Mod?, ModSelection.Priority>
|
||||
public class ModSelection : EventBase<ModSelection.Arguments, ModSelection.Priority>
|
||||
{
|
||||
private readonly ActiveCollections _collections;
|
||||
private readonly EphemeralConfig _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
|
||||
public ModSelection(CommunicatorService communicator, ModManager mods, ActiveCollections collections, EphemeralConfig config)
|
||||
: base(nameof(ModSelection))
|
||||
public ModSelection(Logger log, CommunicatorService communicator, ModManager mods, ActiveCollections collections, EphemeralConfig config)
|
||||
: base(nameof(ModSelection), log)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_collections = collections;
|
||||
|
|
@ -49,8 +48,8 @@ public class ModSelection : EventWrapper<Mod?, Mod?, ModSelection.Priority>
|
|||
|
||||
var oldMod = Mod;
|
||||
Mod = mod;
|
||||
OnCollectionChange(CollectionType.Current, null, _collections.Current, string.Empty);
|
||||
Invoke(oldMod, Mod);
|
||||
OnCollectionChange(new CollectionChange.Arguments(CollectionType.Current, null, _collections.Current, string.Empty));
|
||||
Invoke(new Arguments(oldMod, Mod));
|
||||
_config.LastModPath = mod?.ModPath.Name ?? string.Empty;
|
||||
_config.Save();
|
||||
}
|
||||
|
|
@ -62,21 +61,21 @@ public class ModSelection : EventWrapper<Mod?, Mod?, ModSelection.Priority>
|
|||
_communicator.ModSettingChanged.Unsubscribe(OnSettingChange);
|
||||
}
|
||||
|
||||
private void OnCollectionChange(CollectionType type, ModCollection? oldCollection, ModCollection? newCollection, string _2)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (type is CollectionType.Current && oldCollection != newCollection)
|
||||
if (arguments.Type is CollectionType.Current && arguments.OldCollection != arguments.NewCollection)
|
||||
UpdateSettings();
|
||||
}
|
||||
|
||||
private void OnSettingChange(ModCollection collection, ModSettingChange _1, Mod? mod, Setting _2, int _3, bool _4)
|
||||
private void OnSettingChange(in ModSettingChanged.Arguments arguments)
|
||||
{
|
||||
if (collection == _collections.Current && mod == Mod)
|
||||
if (arguments.Collection == _collections.Current && arguments.Mod == Mod)
|
||||
UpdateSettings();
|
||||
}
|
||||
|
||||
private void OnInheritanceChange(ModCollection collection, bool arg2)
|
||||
private void OnInheritanceChange(in CollectionInheritanceChanged.Arguments arguments)
|
||||
{
|
||||
if (collection == _collections.Current)
|
||||
if (arguments.Collection == _collections.Current)
|
||||
UpdateSettings();
|
||||
}
|
||||
|
||||
|
|
@ -105,4 +104,6 @@ public class ModSelection : EventWrapper<Mod?, Mod?, ModSelection.Priority>
|
|||
/// <seealso cref="Editor.ModMerger.OnSelectionChange"/>
|
||||
ModMerger = 0,
|
||||
}
|
||||
|
||||
public readonly record struct Arguments(Mod? OldSelection, Mod? NewSelection);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManage
|
|||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Luna;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Interop;
|
||||
using Penumbra.Interop.Hooks;
|
||||
|
|
@ -31,9 +32,9 @@ namespace Penumbra;
|
|||
|
||||
public class Penumbra : IDalamudPlugin
|
||||
{
|
||||
public static readonly OtterGui.Log.Logger Log = new();
|
||||
public static MessageService Messager { get; private set; } = null!;
|
||||
public static DynamisIpc Dynamis { get; private set; } = null!;
|
||||
public static readonly OtterGui.Log.Logger Log = new();
|
||||
public static MessageService Messager { get; private set; } = null!;
|
||||
public static DynamisIpc Dynamis { get; private set; } = null!;
|
||||
|
||||
private readonly ValidityChecker _validityChecker;
|
||||
private readonly ResidentResourceManager _residentResources;
|
||||
|
|
@ -49,14 +50,14 @@ public class Penumbra : IDalamudPlugin
|
|||
private PenumbraWindowSystem? _windowSystem;
|
||||
private bool _disposed;
|
||||
|
||||
private readonly Luna.ServiceManager _services;
|
||||
private readonly ServiceManager _services;
|
||||
|
||||
public Penumbra(IDalamudPluginInterface pluginInterface)
|
||||
{
|
||||
try
|
||||
{
|
||||
HookOverrides.Instance = HookOverrides.LoadFile(pluginInterface);
|
||||
_services = StaticServiceManager.CreateProvider(this, pluginInterface, new("Penumbra"));
|
||||
_services = StaticServiceManager.CreateProvider(this, pluginInterface, new Logger("Penumbra"));
|
||||
// Invoke the IPC Penumbra.Launching method before any hooks or other services are created.
|
||||
_services.GetService<IpcLaunchingProvider>();
|
||||
Messager = _services.GetService<MessageService>();
|
||||
|
|
@ -64,7 +65,7 @@ public class Penumbra : IDalamudPlugin
|
|||
_validityChecker = _services.GetService<ValidityChecker>();
|
||||
_services.EnsureRequiredServices();
|
||||
_services.EnsureRequiredServices<OtterGui.Services.IRequiredService>();
|
||||
|
||||
|
||||
var startup = _services.GetService<DalamudConfigService>()
|
||||
.GetDalamudConfig(DalamudConfigService.WaitingForPluginsOption, out bool s)
|
||||
? s.ToString()
|
||||
|
|
@ -87,21 +88,21 @@ public class Penumbra : IDalamudPlugin
|
|||
_services.GetService<ModCacheManager>(); // Initialize because not required anywhere else.
|
||||
_collectionManager.Caches.CreateNecessaryCaches();
|
||||
_services.GetService<PathResolver>();
|
||||
|
||||
|
||||
_services.GetService<DalamudSubstitutionProvider>(); // Initialize before Interface.
|
||||
|
||||
foreach (var service in _services.GetServicesImplementing<Luna.IAwaitedService>())
|
||||
|
||||
foreach (var service in _services.GetServicesImplementing<IAwaitedService>())
|
||||
service.Awaiter.Wait();
|
||||
|
||||
|
||||
SetupInterface();
|
||||
SetupApi();
|
||||
|
||||
|
||||
_validityChecker.LogExceptions();
|
||||
Log.Information(
|
||||
$"Penumbra Version {_validityChecker.Version}, Commit #{_validityChecker.CommitHash} successfully Loaded from {pluginInterface.SourceRepository}.");
|
||||
OtterTex.NativeDll.Initialize(pluginInterface.AssemblyLocation.DirectoryName);
|
||||
Log.Information($"Loading native OtterTex assembly from {OtterTex.NativeDll.Directory}.");
|
||||
|
||||
|
||||
if (_characterUtility.Ready)
|
||||
_residentResources.Reload();
|
||||
}
|
||||
|
|
@ -117,15 +118,15 @@ public class Penumbra : IDalamudPlugin
|
|||
{
|
||||
_services.GetService<IpcProviders>();
|
||||
var itemSheet = _services.GetService<IDataManager>().GetExcelSheet<Item>();
|
||||
_communicatorService.ChangedItemHover.Subscribe(it =>
|
||||
_communicatorService.ChangedItemHover.Subscribe((in ChangedItemHover.Arguments args) =>
|
||||
{
|
||||
if (it is IdentifiedItem { Item.Id.IsItem: true })
|
||||
if (args.Data is IdentifiedItem { Item.Id.IsItem: true })
|
||||
ImGui.TextUnformatted("Left Click to create an item link in chat.");
|
||||
}, ChangedItemHover.Priority.Link);
|
||||
|
||||
_communicatorService.ChangedItemClick.Subscribe((button, it) =>
|
||||
_communicatorService.ChangedItemClick.Subscribe((in ChangedItemClick.Arguments args) =>
|
||||
{
|
||||
if (button == MouseButton.Left && it is IdentifiedItem item && itemSheet.GetRow(item.Item.ItemId.Id) is { } i)
|
||||
if (args is { Button: MouseButton.Left, Data: IdentifiedItem item } && itemSheet.GetRow(item.Item.ItemId.Id) is { } i)
|
||||
Messager.LinkItem(i);
|
||||
}, ChangedItemClick.Priority.Link);
|
||||
}
|
||||
|
|
@ -169,7 +170,7 @@ public class Penumbra : IDalamudPlugin
|
|||
}
|
||||
|
||||
_config.Save();
|
||||
_communicatorService.EnabledChanged.Invoke(enabled);
|
||||
_communicatorService.EnabledChanged.Invoke(new EnabledChanged.Arguments(enabled));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,44 +3,8 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace Penumbra.Services;
|
||||
|
||||
public class BackupService : IAsyncService
|
||||
public sealed class BackupService(Logger log, FilenameService provider) : BaseBackupService<FilenameService>(log, provider)
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly DirectoryInfo _configDirectory;
|
||||
private readonly IReadOnlyList<FileInfo> _fileNames;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task Awaiter { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Finished
|
||||
=> Awaiter.IsCompletedSuccessfully;
|
||||
|
||||
/// <summary> Start a backup process on the collected files. </summary>
|
||||
public BackupService(Logger logger, FilenameService fileNames)
|
||||
{
|
||||
_logger = logger;
|
||||
_fileNames = PenumbraFiles(fileNames);
|
||||
_configDirectory = new DirectoryInfo(fileNames.ConfigurationDirectory);
|
||||
Awaiter = Task.Run(() => Backup.CreateAutomaticBackup(logger, new DirectoryInfo(fileNames.ConfigurationDirectory), _fileNames));
|
||||
}
|
||||
|
||||
/// <summary> Create a permanent backup with a given name for migrations. </summary>
|
||||
public void CreateMigrationBackup(string name)
|
||||
=> Backup.CreatePermanentBackup(_logger, _configDirectory, _fileNames, name);
|
||||
|
||||
/// <summary> Collect all relevant files for penumbra configuration. </summary>
|
||||
private static IReadOnlyList<FileInfo> PenumbraFiles(FilenameService fileNames)
|
||||
{
|
||||
var list = fileNames.CollectionFiles.ToList();
|
||||
list.AddRange(fileNames.LocalDataFiles);
|
||||
list.Add(new FileInfo(fileNames.ConfigurationFile));
|
||||
list.Add(new FileInfo(fileNames.FilesystemFile));
|
||||
list.Add(new FileInfo(fileNames.ActiveCollectionsFile));
|
||||
list.Add(new FileInfo(fileNames.PredefinedTagFile));
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary> Try to parse a file to JObject and check backups if this does not succeed. </summary>
|
||||
public static JObject? GetJObjectForFile(FilenameService fileNames, string fileName)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,116 +1,85 @@
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
using Luna;
|
||||
using Penumbra.Communication;
|
||||
|
||||
namespace Penumbra.Services;
|
||||
|
||||
public class CommunicatorService : IDisposable, Luna.IService
|
||||
public class CommunicatorService(ServiceManager services) : IService
|
||||
{
|
||||
public CommunicatorService(Logger logger)
|
||||
{
|
||||
EventWrapperBase.ChangeLogger(logger);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Communication.CollectionChange"/>
|
||||
public readonly CollectionChange CollectionChange = new();
|
||||
public readonly CollectionChange CollectionChange = services.GetService<CollectionChange>();
|
||||
|
||||
/// <inheritdoc cref="Communication.TemporaryGlobalModChange"/>
|
||||
public readonly TemporaryGlobalModChange TemporaryGlobalModChange = new();
|
||||
public readonly TemporaryGlobalModChange TemporaryGlobalModChange = services.GetService<TemporaryGlobalModChange>();
|
||||
|
||||
/// <inheritdoc cref="Communication.CreatingCharacterBase"/>
|
||||
public readonly CreatingCharacterBase CreatingCharacterBase = new();
|
||||
public readonly CreatingCharacterBase CreatingCharacterBase = services.GetService<CreatingCharacterBase>();
|
||||
|
||||
/// <inheritdoc cref="Communication.CreatedCharacterBase"/>
|
||||
public readonly CreatedCharacterBase CreatedCharacterBase = new();
|
||||
public readonly CreatedCharacterBase CreatedCharacterBase = services.GetService<CreatedCharacterBase>();
|
||||
|
||||
/// <inheritdoc cref="Communication.MtrlLoaded"/>
|
||||
public readonly MtrlLoaded MtrlLoaded = new();
|
||||
public readonly MtrlLoaded MtrlLoaded = services.GetService<MtrlLoaded>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModDataChanged"/>
|
||||
public readonly ModDataChanged ModDataChanged = new();
|
||||
public readonly ModDataChanged ModDataChanged = services.GetService<ModDataChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModOptionChanged"/>
|
||||
public readonly ModOptionChanged ModOptionChanged = new();
|
||||
public readonly ModOptionChanged ModOptionChanged = services.GetService<ModOptionChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModDiscoveryStarted"/>
|
||||
public readonly ModDiscoveryStarted ModDiscoveryStarted = new();
|
||||
public readonly ModDiscoveryStarted ModDiscoveryStarted = services.GetService<ModDiscoveryStarted>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModDiscoveryFinished"/>
|
||||
public readonly ModDiscoveryFinished ModDiscoveryFinished = new();
|
||||
public readonly ModDiscoveryFinished ModDiscoveryFinished = services.GetService<ModDiscoveryFinished>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModDirectoryChanged"/>
|
||||
public readonly ModDirectoryChanged ModDirectoryChanged = new();
|
||||
public readonly ModDirectoryChanged ModDirectoryChanged = services.GetService<ModDirectoryChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModFileChanged"/>
|
||||
public readonly ModFileChanged ModFileChanged = new();
|
||||
public readonly ModFileChanged ModFileChanged = services.GetService<ModFileChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModPathChanged"/>
|
||||
public readonly ModPathChanged ModPathChanged = new();
|
||||
public readonly ModPathChanged ModPathChanged = services.GetService<ModPathChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ModSettingChanged"/>
|
||||
public readonly ModSettingChanged ModSettingChanged = new();
|
||||
public readonly ModSettingChanged ModSettingChanged = services.GetService<ModSettingChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.CollectionInheritanceChanged"/>
|
||||
public readonly CollectionInheritanceChanged CollectionInheritanceChanged = new();
|
||||
public readonly CollectionInheritanceChanged CollectionInheritanceChanged = services.GetService<CollectionInheritanceChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.EnabledChanged"/>
|
||||
public readonly EnabledChanged EnabledChanged = new();
|
||||
public readonly EnabledChanged EnabledChanged = services.GetService<EnabledChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.PreSettingsTabBarDraw"/>
|
||||
public readonly PreSettingsTabBarDraw PreSettingsTabBarDraw = new();
|
||||
public readonly PreSettingsTabBarDraw PreSettingsTabBarDraw = services.GetService<PreSettingsTabBarDraw>();
|
||||
|
||||
/// <inheritdoc cref="Communication.PreSettingsPanelDraw"/>
|
||||
public readonly PreSettingsPanelDraw PreSettingsPanelDraw = new();
|
||||
public readonly PreSettingsPanelDraw PreSettingsPanelDraw = services.GetService<PreSettingsPanelDraw>();
|
||||
|
||||
/// <inheritdoc cref="Communication.PostEnabledDraw"/>
|
||||
public readonly PostEnabledDraw PostEnabledDraw = new();
|
||||
public readonly PostEnabledDraw PostEnabledDraw = services.GetService<PostEnabledDraw>();
|
||||
|
||||
/// <inheritdoc cref="Communication.PostSettingsPanelDraw"/>
|
||||
public readonly PostSettingsPanelDraw PostSettingsPanelDraw = new();
|
||||
public readonly PostSettingsPanelDraw PostSettingsPanelDraw = services.GetService<PostSettingsPanelDraw>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ChangedItemHover"/>
|
||||
public readonly ChangedItemHover ChangedItemHover = new();
|
||||
public readonly ChangedItemHover ChangedItemHover = services.GetService<ChangedItemHover>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ChangedItemClick"/>
|
||||
public readonly ChangedItemClick ChangedItemClick = new();
|
||||
public readonly ChangedItemClick ChangedItemClick = services.GetService<ChangedItemClick>();
|
||||
|
||||
/// <inheritdoc cref="Communication.SelectTab"/>
|
||||
public readonly SelectTab SelectTab = new();
|
||||
public readonly SelectTab SelectTab = services.GetService<SelectTab>();
|
||||
|
||||
/// <inheritdoc cref="Communication.ResolvedFileChanged"/>
|
||||
public readonly ResolvedFileChanged ResolvedFileChanged = new();
|
||||
public readonly ResolvedFileChanged ResolvedFileChanged = services.GetService<ResolvedFileChanged>();
|
||||
|
||||
/// <inheritdoc cref="Communication.PcpCreation"/>
|
||||
public readonly PcpCreation PcpCreation = new();
|
||||
public readonly PcpCreation PcpCreation = services.GetService<PcpCreation>();
|
||||
|
||||
/// <inheritdoc cref="Communication.PcpParsing"/>
|
||||
public readonly PcpParsing PcpParsing = new();
|
||||
public readonly PcpParsing PcpParsing = services.GetService<PcpParsing>();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CollectionChange.Dispose();
|
||||
TemporaryGlobalModChange.Dispose();
|
||||
CreatingCharacterBase.Dispose();
|
||||
CreatedCharacterBase.Dispose();
|
||||
MtrlLoaded.Dispose();
|
||||
ModDataChanged.Dispose();
|
||||
ModOptionChanged.Dispose();
|
||||
ModDiscoveryStarted.Dispose();
|
||||
ModDiscoveryFinished.Dispose();
|
||||
ModDirectoryChanged.Dispose();
|
||||
ModPathChanged.Dispose();
|
||||
ModSettingChanged.Dispose();
|
||||
CollectionInheritanceChanged.Dispose();
|
||||
EnabledChanged.Dispose();
|
||||
PreSettingsTabBarDraw.Dispose();
|
||||
PreSettingsPanelDraw.Dispose();
|
||||
PostEnabledDraw.Dispose();
|
||||
PostSettingsPanelDraw.Dispose();
|
||||
ChangedItemHover.Dispose();
|
||||
ChangedItemClick.Dispose();
|
||||
SelectTab.Dispose();
|
||||
ResolvedFileChanged.Dispose();
|
||||
PcpCreation.Dispose();
|
||||
PcpParsing.Dispose();
|
||||
}
|
||||
/// <inheritdoc cref="Communication.CharacterUtilityFinished"/>
|
||||
public readonly CharacterUtilityFinished LoadingFinished = services.GetService<CharacterUtilityFinished>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,18 +248,18 @@ public sealed class CrashHandlerService : IDisposable, Luna.IService
|
|||
}
|
||||
}
|
||||
|
||||
private void OnCreatingCharacterBase(nint address, Guid collection, nint _1, nint _2, nint _3)
|
||||
private void OnCreatingCharacterBase(in CreatingCharacterBase.Arguments arguments)
|
||||
{
|
||||
if (_eventWriter == null)
|
||||
if (_eventWriter is null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var name = GetActorName(address);
|
||||
var name = GetActorName(arguments.GameObject);
|
||||
|
||||
lock (_eventWriter)
|
||||
{
|
||||
_eventWriter?.CharacterBase.WriteLine(address, name.Span, collection);
|
||||
_eventWriter?.CharacterBase.WriteLine(arguments.GameObject, name.Span, arguments.Collection.Identity.Id);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Plugin;
|
||||
using Luna.Files;
|
||||
using Luna;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Mods;
|
||||
|
||||
|
|
@ -80,4 +80,16 @@ public sealed class FilenameService(IDalamudPluginInterface pi) : BaseFilePathPr
|
|||
/// <summary> Enumerate all group files for a given mod. </summary>
|
||||
public IEnumerable<FileInfo> GetOptionGroupFiles(Mod mod)
|
||||
=> mod.ModPath.EnumerateFiles("group_*.json");
|
||||
|
||||
/// <summary> Collect all relevant files for penumbra configuration. </summary>
|
||||
public override List<FileInfo> GetBackupFiles()
|
||||
{
|
||||
var list = CollectionFiles.ToList();
|
||||
list.AddRange(LocalDataFiles);
|
||||
list.Add(new FileInfo(ConfigurationFile));
|
||||
list.Add(new FileInfo(FilesystemFile));
|
||||
list.Add(new FileInfo(ActiveCollectionsFile));
|
||||
list.Add(new FileInfo(PredefinedTagFile));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,18 +86,18 @@ public class PcpService : IApiService, IDisposable
|
|||
_collections.Storage.RemoveCollection(collection);
|
||||
}
|
||||
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, DirectoryInfo? newDirectory)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
if (type is not ModPathChangeType.Added || _config.PcpSettings.DisableHandling || newDirectory is null)
|
||||
if (arguments.Type is not ModPathChangeType.Added || _config.PcpSettings.DisableHandling || arguments.NewDirectory is null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var file = Path.Combine(newDirectory.FullName, "character.json");
|
||||
var file = Path.Combine(arguments.NewDirectory.FullName, "character.json");
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
// First version had collection.json, changed.
|
||||
var oldFile = Path.Combine(newDirectory.FullName, "collection.json");
|
||||
var oldFile = Path.Combine(arguments.NewDirectory.FullName, "collection.json");
|
||||
if (File.Exists(oldFile))
|
||||
{
|
||||
Penumbra.Log.Information("[PCPService] Renaming old PCP file from collection.json to character.json.");
|
||||
|
|
@ -107,7 +107,7 @@ public class PcpService : IApiService, IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
Penumbra.Log.Information($"[PCPService] Found a PCP file for {mod.Name}, applying.");
|
||||
Penumbra.Log.Information($"[PCPService] Found a PCP file for {arguments.Mod.Name}, applying.");
|
||||
var text = File.ReadAllText(file);
|
||||
var jObj = JObject.Parse(text);
|
||||
var collection = ModCollection.Empty;
|
||||
|
|
@ -121,7 +121,7 @@ public class PcpService : IApiService, IDisposable
|
|||
if (_collections.Storage.AddCollection(name, null))
|
||||
{
|
||||
collection = _collections.Storage[^1];
|
||||
_collections.Editor.SetModState(collection, mod, true);
|
||||
_collections.Editor.SetModState(collection, arguments.Mod, true);
|
||||
|
||||
// Assign collection.
|
||||
if (_config.PcpSettings.AssignCollection)
|
||||
|
|
@ -134,7 +134,7 @@ public class PcpService : IApiService, IDisposable
|
|||
}
|
||||
|
||||
// Move to folder.
|
||||
if (_fileSystem.TryGetValue(mod, out var leaf))
|
||||
if (_fileSystem.TryGetValue(arguments.Mod, out var leaf))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -149,11 +149,11 @@ public class PcpService : IApiService, IDisposable
|
|||
|
||||
// Invoke IPC.
|
||||
if (_config.PcpSettings.AllowIpc)
|
||||
_communicator.PcpParsing.Invoke(jObj, mod.Identifier, collection.Identity.Id);
|
||||
_communicator.PcpParsing.Invoke(new PcpParsing.Arguments(jObj, arguments.Mod, collection));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Penumbra.Log.Error($"Error reading the character.json file from {mod.Identifier}:\n{ex}");
|
||||
Penumbra.Log.Error($"Error reading the character.json file from {arguments.Mod.Identifier}:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ public class PcpService : IApiService, IDisposable
|
|||
if (note.Length > 0)
|
||||
cancel.ThrowIfCancellationRequested();
|
||||
if (_config.PcpSettings.AllowIpc)
|
||||
await _framework.Framework.RunOnFrameworkThread(() => _communicator.PcpCreation.Invoke(jObj, index.Index, directory.FullName));
|
||||
await _framework.Framework.RunOnFrameworkThread(() => _communicator.PcpCreation.Invoke(new PcpCreation.Arguments(jObj, index.Index, directory.FullName)));
|
||||
var filePath = Path.Combine(directory.FullName, "character.json");
|
||||
await using var file = File.Open(filePath, File.Exists(filePath) ? FileMode.Truncate : FileMode.CreateNew);
|
||||
await using var stream = new StreamWriter(file);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Luna;
|
||||
using Luna.Files;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Groups;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using OtterGui.Classes;
|
|||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.Mods.Editor;
|
||||
|
|
@ -216,7 +217,7 @@ public class FileEditor<T>(
|
|||
{
|
||||
compactor.WriteAllBytes(_currentPath!.File.FullName, _currentFile!.Write());
|
||||
if (owner.Mod != null)
|
||||
communicator.ModFileChanged.Invoke(owner.Mod, _currentPath);
|
||||
communicator.ModFileChanged.Invoke(new ModFileChanged.Arguments(owner.Mod, _currentPath));
|
||||
_changed = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using OtterGui.Raii;
|
|||
using OtterGui.Text;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
|
|
@ -28,7 +27,7 @@ using Penumbra.UI.ModsTab;
|
|||
|
||||
namespace Penumbra.UI.AdvancedWindow;
|
||||
|
||||
public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
||||
public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
|
|
@ -141,11 +140,16 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
{
|
||||
var list = data.ByType[type];
|
||||
var enumerable = selector?.Selected is { } mod && mod.ChangedItems.Values.Any(o => o is IdentifiedItem i && i.Item.Type == type)
|
||||
? list.Select(i => (i, mod.ChangedItems.ContainsKey(i.Name), collections.Current.ChangedItems.TryGetValue(i.Name, out var m) ? m.Item1 : new SingleArray<IMod>()))
|
||||
? list.Select(i => (i, mod.ChangedItems.ContainsKey(i.Name),
|
||||
collections.Current.ChangedItems.TryGetValue(i.Name, out var m) ? m.Item1 : new SingleArray<IMod>()))
|
||||
.OrderByDescending(p => p.Item2).ThenByDescending(p => p.Item3.Count)
|
||||
: selector is null
|
||||
? list.Select(i => (i, false, collections.Current.ChangedItems.TryGetValue(i.Name, out var m) ? m.Item1 : new SingleArray<IMod>())).OrderBy(p => p.Item3.Count)
|
||||
: list.Select(i => (i, false, collections.Current.ChangedItems.TryGetValue(i.Name, out var m) ? m.Item1 : new SingleArray<IMod>())).OrderByDescending(p => p.Item3.Count);
|
||||
? list.Select(i => (i, false,
|
||||
collections.Current.ChangedItems.TryGetValue(i.Name, out var m) ? m.Item1 : new SingleArray<IMod>()))
|
||||
.OrderBy(p => p.Item3.Count)
|
||||
: list.Select(i => (i, false,
|
||||
collections.Current.ChangedItems.TryGetValue(i.Name, out var m) ? m.Item1 : new SingleArray<IMod>()))
|
||||
.OrderByDescending(p => p.Item3.Count);
|
||||
return enumerable.ToList();
|
||||
}, MouseWheelType.None, Penumbra.Log)
|
||||
{
|
||||
|
|
@ -526,7 +530,7 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
_dirty |= selector.Draw("##itemSource", selector.CurrentSelection.Item.Name ?? string.Empty, string.Empty,
|
||||
_dirty |= selector.Draw("##itemSource", selector.CurrentSelection.Item.Name, string.Empty,
|
||||
InputWidth * 2 * UiHelpers.Scale,
|
||||
ImGui.GetTextLineHeightWithSpacing());
|
||||
|
||||
|
|
@ -638,19 +642,6 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
DrawGenderInput();
|
||||
}
|
||||
|
||||
private void DrawFaceSwap()
|
||||
{
|
||||
using var disabled = ImRaii.Disabled();
|
||||
using var tab = DrawTab(SwapType.Face);
|
||||
if (!tab)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table("##settings", 2, ImGuiTableFlags.SizingFixedFit);
|
||||
DrawTargetIdInput("Take this Face Type");
|
||||
DrawSourceIdInput();
|
||||
DrawGenderInput();
|
||||
}
|
||||
|
||||
private void DrawTailSwap()
|
||||
{
|
||||
using var tab = DrawTab(SwapType.Tail);
|
||||
|
|
@ -686,7 +677,7 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.SetNextItemWidth(InputWidth * UiHelpers.Scale);
|
||||
if (ImGui.InputInt("##targetId", ref _targetId, 0, 0))
|
||||
if (ImGui.InputInt("##targetId", ref _targetId))
|
||||
_targetId = Math.Clamp(_targetId, 0, byte.MaxValue);
|
||||
|
||||
_dirty |= ImGui.IsItemDeactivatedAfterEdit();
|
||||
|
|
@ -700,7 +691,7 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.SetNextItemWidth(InputWidth * UiHelpers.Scale);
|
||||
if (ImGui.InputInt("##sourceId", ref _sourceId, 0, 0))
|
||||
if (ImGui.InputInt("##sourceId", ref _sourceId))
|
||||
_sourceId = Math.Clamp(_sourceId, 0, byte.MaxValue);
|
||||
|
||||
_dirty |= ImGui.IsItemDeactivatedAfterEdit();
|
||||
|
|
@ -713,7 +704,7 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
ImGui.TextUnformatted(text);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
_dirty |= Combos.Gender("##Gender", _currentGender, out _currentGender, InputWidth);
|
||||
_dirty |= Combos.Gender("##Gender", _currentGender, out _currentGender);
|
||||
if (drawRace == 1)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
|
|
@ -725,12 +716,11 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
if (_currentRace is not ModelRace.Miqote and not ModelRace.AuRa and not ModelRace.Hrothgar)
|
||||
_currentRace = ModelRace.Miqote;
|
||||
|
||||
_dirty |= ImGuiUtil.GenericEnumCombo("##Race", InputWidth, _currentRace, out _currentRace, new[]
|
||||
{
|
||||
_dirty |= ImGuiUtil.GenericEnumCombo("##Race", InputWidth, _currentRace, out _currentRace, [
|
||||
ModelRace.Miqote,
|
||||
ModelRace.AuRa,
|
||||
ModelRace.Hrothgar,
|
||||
},
|
||||
],
|
||||
RaceEnumExtensions.ToName);
|
||||
}
|
||||
}
|
||||
|
|
@ -767,38 +757,40 @@ public class ItemSwapTab : IDisposable, ITab, Luna.IUiService
|
|||
DrawSwap(child);
|
||||
}
|
||||
|
||||
private void OnCollectionChange(CollectionType collectionType, ModCollection? oldCollection,
|
||||
ModCollection? newCollection, string _)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (collectionType is not CollectionType.Current || _mod == null || newCollection == null)
|
||||
if (arguments.Type is not CollectionType.Current || _mod is null || arguments.NewCollection is null)
|
||||
return;
|
||||
|
||||
UpdateMod(_mod, _mod.Index < newCollection.Settings.Count ? newCollection.GetInheritedSettings(_mod.Index).Settings : null);
|
||||
UpdateMod(_mod,
|
||||
_mod.Index < arguments.NewCollection.Settings.Count ? arguments.NewCollection.GetInheritedSettings(_mod.Index).Settings : null);
|
||||
}
|
||||
|
||||
private void OnSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, Setting oldValue, int groupIdx, bool inherited)
|
||||
private void OnSettingChange(in ModSettingChanged.Arguments arguments)
|
||||
{
|
||||
if (collection != _collectionManager.Active.Current || mod != _mod || type is ModSettingChange.TemporarySetting)
|
||||
if (arguments.Collection != _collectionManager.Active.Current
|
||||
|| arguments.Mod != _mod
|
||||
|| arguments.Type is ModSettingChange.TemporarySetting)
|
||||
return;
|
||||
|
||||
_swapData.LoadMod(_mod, _modSettings);
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
private void OnInheritanceChange(ModCollection collection, bool _)
|
||||
private void OnInheritanceChange(in CollectionInheritanceChanged.Arguments arguments)
|
||||
{
|
||||
if (collection != _collectionManager.Active.Current || _mod == null)
|
||||
if (arguments.Collection != _collectionManager.Active.Current || _mod == null)
|
||||
return;
|
||||
|
||||
UpdateMod(_mod, collection.GetInheritedSettings(_mod.Index).Settings);
|
||||
UpdateMod(_mod, arguments.Collection.GetInheritedSettings(_mod.Index).Settings);
|
||||
_swapData.LoadMod(_mod, _modSettings);
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
|
||||
int fromIdx)
|
||||
private void OnModOptionChange(in ModOptionChanged.Arguments arguments)
|
||||
{
|
||||
if (type is ModOptionChangeType.PrepareChange or ModOptionChangeType.GroupAdded or ModOptionChangeType.OptionAdded || mod != _mod)
|
||||
if (arguments.Type is ModOptionChangeType.PrepareChange or ModOptionChangeType.GroupAdded or ModOptionChangeType.OptionAdded
|
||||
|| arguments.Mod != _mod)
|
||||
return;
|
||||
|
||||
_swapData.LoadMod(_mod, _modSettings);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using Dalamud.Bindings.ImGui;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Files.MaterialStructs;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Hooks.Objects;
|
||||
using Penumbra.Interop.MaterialPreview;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.UI.Classes;
|
||||
|
|
@ -91,12 +91,12 @@ public partial class MtrlTab
|
|||
_colorTablePreviewers.Clear();
|
||||
}
|
||||
|
||||
private unsafe void UnbindFromDrawObjectMaterialInstances(CharacterBase* characterBase)
|
||||
private unsafe void UnbindFromDrawObjectMaterialInstances(in CharacterBaseDestructor.Arguments arguments)
|
||||
{
|
||||
for (var i = _materialPreviewers.Count; i-- > 0;)
|
||||
{
|
||||
var previewer = _materialPreviewers[i];
|
||||
if (previewer.DrawObject != characterBase)
|
||||
if (previewer.DrawObject != arguments.CharacterBase)
|
||||
continue;
|
||||
|
||||
previewer.Dispose();
|
||||
|
|
@ -106,7 +106,7 @@ public partial class MtrlTab
|
|||
for (var i = _colorTablePreviewers.Count; i-- > 0;)
|
||||
{
|
||||
var previewer = _colorTablePreviewers[i];
|
||||
if (previewer.DrawObject != characterBase)
|
||||
if (previewer.DrawObject != arguments.CharacterBase)
|
||||
continue;
|
||||
|
||||
previewer.Dispose();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Luna;
|
|||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterTex;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Import.Textures;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.UI.Classes;
|
||||
|
|
@ -229,7 +230,7 @@ public partial class ModEditWindow
|
|||
out var registry))
|
||||
return;
|
||||
|
||||
_communicator.ModFileChanged.Invoke(mod, registry);
|
||||
_communicator.ModFileChanged.Invoke(new ModFileChanged.Arguments(mod, registry));
|
||||
}
|
||||
|
||||
private void OpenSaveAsDialog(string defaultExtension)
|
||||
|
|
|
|||
|
|
@ -681,12 +681,12 @@ public partial class ModEditWindow : Window, IDisposable, Luna.IUiService
|
|||
_center.Dispose();
|
||||
}
|
||||
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? _1, DirectoryInfo? _2)
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
if (type is not (ModPathChangeType.Reloaded or ModPathChangeType.Moved) || mod != Mod)
|
||||
if (arguments.Type is not (ModPathChangeType.Reloaded or ModPathChangeType.Moved) || arguments.Mod != Mod)
|
||||
return;
|
||||
|
||||
Mod = null;
|
||||
ChangeMod(mod);
|
||||
ChangeMod(arguments.Mod);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using OtterGui;
|
|||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.ResourceTree;
|
||||
|
|
@ -344,7 +345,7 @@ public class ResourceTreeViewer(
|
|||
if (ImGui.IsItemClicked())
|
||||
ImGui.SetClipboardText(resourceNode.FullPath.ToPath());
|
||||
if (hasMod && ImGui.IsItemClicked(ImGuiMouseButton.Right) && ImGui.GetIO().KeyCtrl)
|
||||
communicator.SelectTab.Invoke(TabType.Mods, mod);
|
||||
communicator.SelectTab.Invoke(new SelectTab.Arguments(TabType.Mods, mod));
|
||||
|
||||
ImGuiUtil.HoverTooltip(
|
||||
$"{resourceNode.FullPath.ToPath()}\n\nClick to copy to clipboard.{(hasMod ? "\nControl + Right-Click to jump to mod." : string.Empty)}{GetAdditionalDataSuffix(resourceNode.AdditionalData)}");
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using OtterGui.Classes;
|
|||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.UI.Classes;
|
||||
|
|
@ -122,7 +123,7 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
|
|||
ret = ImGui.IsItemClicked(ImGuiMouseButton.Right) ? MouseButton.Right : ret;
|
||||
ret = ImGui.IsItemClicked(ImGuiMouseButton.Middle) ? MouseButton.Middle : ret;
|
||||
if (ret != MouseButton.None)
|
||||
_communicator.ChangedItemClick.Invoke(ret, data);
|
||||
_communicator.ChangedItemClick.Invoke(new ChangedItemClick.Arguments(ret, data));
|
||||
if (!ImGui.IsItemHovered())
|
||||
return;
|
||||
|
||||
|
|
@ -134,7 +135,7 @@ public class ChangedItemDrawer : IDisposable, Luna.IUiService
|
|||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3 * ImUtf8.GlobalScale);
|
||||
ImGui.Separator();
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3 * ImUtf8.GlobalScale);
|
||||
_communicator.ChangedItemHover.Invoke(data);
|
||||
_communicator.ChangedItemHover.Invoke(new ChangedItemHover.Arguments(data));
|
||||
}
|
||||
|
||||
/// <summary> Draw the model information, right-justified. </summary>
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ public sealed class CollectionSelector : ItemSelector<ModCollection>, IDisposabl
|
|||
|
||||
_communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.CollectionSelector);
|
||||
// Set items.
|
||||
OnCollectionChange(CollectionType.Inactive, null, null, string.Empty);
|
||||
OnCollectionChange(new CollectionChange.Arguments(CollectionType.Inactive, null, null, string.Empty));
|
||||
// Set selection.
|
||||
OnCollectionChange(CollectionType.Current, null, _active.Current, string.Empty);
|
||||
OnCollectionChange(new CollectionChange.Arguments(CollectionType.Current, null, _active.Current, string.Empty));
|
||||
}
|
||||
|
||||
protected override bool OnDelete(int idx)
|
||||
|
|
@ -85,7 +85,7 @@ public sealed class CollectionSelector : ItemSelector<ModCollection>, IDisposabl
|
|||
if (source)
|
||||
{
|
||||
_dragging = Items[idx];
|
||||
ImGui.SetDragDropPayload(PayloadString, null, 0);
|
||||
ImGui.SetDragDropPayload(PayloadString, null);
|
||||
ImGui.TextUnformatted($"Assigning {Name(_dragging)} to...");
|
||||
}
|
||||
|
||||
|
|
@ -123,14 +123,14 @@ public sealed class CollectionSelector : ItemSelector<ModCollection>, IDisposabl
|
|||
SetCurrent(_active.Current);
|
||||
}
|
||||
|
||||
private void OnCollectionChange(CollectionType type, ModCollection? old, ModCollection? @new, string _3)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
switch (type)
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case CollectionType.Temporary: return;
|
||||
case CollectionType.Current:
|
||||
if (@new != null)
|
||||
SetCurrent(@new);
|
||||
if (arguments.NewCollection is not null)
|
||||
SetCurrent(arguments.NewCollection);
|
||||
SetFilterDirty();
|
||||
return;
|
||||
case CollectionType.Inactive:
|
||||
|
|
|
|||
|
|
@ -135,9 +135,9 @@ public class IndividualAssignmentUi : IDisposable
|
|||
_ready = true;
|
||||
}
|
||||
|
||||
private void UpdateIdentifiers(CollectionType type, ModCollection? _1, ModCollection? _2, string _3)
|
||||
private void UpdateIdentifiers(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (type == CollectionType.Individual)
|
||||
if (arguments.Type is CollectionType.Individual)
|
||||
UpdateIdentifiersInternal();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,18 +140,18 @@ public class FileDialogService : IDisposable, IUiService
|
|||
}
|
||||
|
||||
/// <summary> Update the Root Directory link on changes. </summary>
|
||||
private void OnModDirectoryChange(string directory, bool valid)
|
||||
private void OnModDirectoryChange(in ModDirectoryChanged.Arguments arguments)
|
||||
{
|
||||
var idx = _manager.CustomSideBarItems.IndexOf(t => t.Name == "Root Directory");
|
||||
if (idx >= 0)
|
||||
_manager.CustomSideBarItems.RemoveAt(idx);
|
||||
|
||||
if (!valid)
|
||||
if (!arguments.Valid)
|
||||
return;
|
||||
|
||||
if (idx >= 0)
|
||||
_manager.CustomSideBarItems.Insert(idx, ("Root Directory", directory, FontAwesomeIcon.Gamepad, 0));
|
||||
_manager.CustomSideBarItems.Insert(idx, ("Root Directory", arguments.Directory, FontAwesomeIcon.Gamepad, 0));
|
||||
else
|
||||
_manager.CustomSideBarItems.Add(("Root Directory", directory, FontAwesomeIcon.Gamepad, 0));
|
||||
_manager.CustomSideBarItems.Add(("Root Directory", arguments.Directory, FontAwesomeIcon.Gamepad, 0));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using OtterGui.FileSystem.Selector;
|
|||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Text.Widget;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
|
|
@ -23,7 +22,7 @@ using MessageService = Penumbra.Services.MessageService;
|
|||
|
||||
namespace Penumbra.UI.ModsTab;
|
||||
|
||||
public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSystemSelector.ModState>, Luna.IUiService
|
||||
public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSystemSelector.ModState>, IUiService
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly Configuration _config;
|
||||
|
|
@ -507,13 +506,13 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
|
||||
#region Automatic cache update functions.
|
||||
|
||||
private void OnSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, Setting oldValue, int groupIdx, bool inherited)
|
||||
private void OnSettingChange(in ModSettingChanged.Arguments arguments)
|
||||
{
|
||||
if (collection == _collectionManager.Active.Current)
|
||||
if (arguments.Collection == _collectionManager.Active.Current)
|
||||
SetFilterDirty();
|
||||
}
|
||||
|
||||
private void OnModDataChange(ModDataChangeType type, Mod mod, string? oldName)
|
||||
private void OnModDataChange(in ModDataChanged.Arguments arguments)
|
||||
{
|
||||
const ModDataChangeType relevantFlags =
|
||||
ModDataChangeType.Name
|
||||
|
|
@ -522,19 +521,19 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
| ModDataChangeType.LocalTags
|
||||
| ModDataChangeType.Favorite
|
||||
| ModDataChangeType.ImportDate;
|
||||
if ((type & relevantFlags) != 0)
|
||||
if ((arguments.Type & relevantFlags) is not 0)
|
||||
SetFilterDirty();
|
||||
}
|
||||
|
||||
private void OnInheritanceChange(ModCollection collection, bool _)
|
||||
private void OnInheritanceChange(in CollectionInheritanceChanged.Arguments arguments)
|
||||
{
|
||||
if (collection == _collectionManager.Active.Current)
|
||||
if (arguments.Collection == _collectionManager.Active.Current)
|
||||
SetFilterDirty();
|
||||
}
|
||||
|
||||
private void OnCollectionChange(CollectionType collectionType, ModCollection? oldCollection, ModCollection? newCollection, string _)
|
||||
private void OnCollectionChange(in CollectionChange.Arguments arguments)
|
||||
{
|
||||
if (collectionType is CollectionType.Current && oldCollection != newCollection)
|
||||
if (arguments.Type is CollectionType.Current && arguments.OldCollection != arguments.NewCollection)
|
||||
SetFilterDirty();
|
||||
}
|
||||
|
||||
|
|
@ -636,7 +635,7 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
}
|
||||
|
||||
/// <summary> Apply the string filters. </summary>
|
||||
private bool ApplyStringFilters(ModFileSystem.Leaf leaf, Mod mod)
|
||||
private bool ApplyStringFilters(ModFileSystem.Leaf leaf, Mod _)
|
||||
=> !_filter.IsVisible(leaf);
|
||||
|
||||
/// <summary> Only get the text color for a mod if no filters are set. </summary>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public class ModPanel : IDisposable, Luna.IUiService
|
|||
_multiModPanel = multiModPanel;
|
||||
_header = new ModPanelHeader(pi, communicator);
|
||||
_selection.Subscribe(OnSelectionChange, ModSelection.Priority.ModPanel);
|
||||
OnSelectionChange(null, _selection.Mod);
|
||||
OnSelectionChange(new ModSelection.Arguments(null, _selection.Mod));
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
|
|
@ -59,10 +59,10 @@ public class ModPanel : IDisposable, Luna.IUiService
|
|||
private bool _valid;
|
||||
private Mod _mod = null!;
|
||||
|
||||
private void OnSelectionChange(Mod? old, Mod? mod)
|
||||
private void OnSelectionChange(in ModSelection.Arguments arguments)
|
||||
{
|
||||
_resetCursor = true;
|
||||
if (mod == null || _selection.Mod == null)
|
||||
if (arguments.NewSelection is null || _selection.Mod is null)
|
||||
{
|
||||
_editWindow.IsOpen = false;
|
||||
_valid = false;
|
||||
|
|
@ -70,9 +70,9 @@ public class ModPanel : IDisposable, Luna.IUiService
|
|||
else
|
||||
{
|
||||
if (_editWindow.IsOpen)
|
||||
_editWindow.ChangeMod(mod);
|
||||
_editWindow.ChangeMod(arguments.NewSelection);
|
||||
_valid = true;
|
||||
_mod = mod;
|
||||
_mod = arguments.NewSelection;
|
||||
_header.ChangeMod(_mod);
|
||||
_tabs.Settings.Reset();
|
||||
_tabs.Edit.Reset();
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public class ModPanelHeader : IDisposable
|
|||
DrawSecondRow(offset);
|
||||
}
|
||||
|
||||
_communicator.PreSettingsTabBarDraw.Invoke(_mod.Identifier, ImGui.GetItemRectSize().X, _nameWidth);
|
||||
_communicator.PreSettingsTabBarDraw.Invoke(new PreSettingsTabBarDraw.Arguments(_mod, ImGui.GetItemRectSize().X, _nameWidth));
|
||||
_lastPreSettingsHeight = ImGui.GetCursorPosY();
|
||||
}
|
||||
|
||||
|
|
@ -260,10 +260,10 @@ public class ModPanelHeader : IDisposable
|
|||
}
|
||||
|
||||
/// <summary> Just update the data when any relevant field changes. </summary>
|
||||
private void OnModDataChange(ModDataChangeType changeType, Mod mod, string? _2)
|
||||
private void OnModDataChange(in ModDataChanged.Arguments arguments)
|
||||
{
|
||||
const ModDataChangeType relevantChanges =
|
||||
ModDataChangeType.Author | ModDataChangeType.Name | ModDataChangeType.Website | ModDataChangeType.Version;
|
||||
_dirty = (changeType & relevantChanges) != 0;
|
||||
_dirty = (arguments.Type & relevantChanges) is not 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using OtterGui.Text;
|
|||
using OtterGui.Widgets;
|
||||
using Penumbra.UI.Classes;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -51,7 +52,7 @@ public class ModPanelSettingsTab(
|
|||
DrawTemporaryWarning();
|
||||
DrawInheritedWarning();
|
||||
ImGui.Dummy(Vector2.Zero);
|
||||
communicator.PreSettingsPanelDraw.Invoke(selection.Mod!.Identifier);
|
||||
communicator.PreSettingsPanelDraw.Invoke(new PreSettingsPanelDraw.Arguments(selection.Mod!));
|
||||
DrawEnabledInput();
|
||||
tutorial.OpenTutorial(BasicTutorialSteps.EnablingMods);
|
||||
ImGui.SameLine();
|
||||
|
|
@ -60,11 +61,11 @@ public class ModPanelSettingsTab(
|
|||
DrawRemoveSettings();
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
communicator.PostEnabledDraw.Invoke(selection.Mod!.Identifier);
|
||||
communicator.PostEnabledDraw.Invoke(new PostEnabledDraw.Arguments(selection.Mod!));
|
||||
|
||||
modGroupDrawer.Draw(selection.Mod!, selection.Settings, selection.TemporarySettings);
|
||||
UiHelpers.DefaultLineSpace();
|
||||
communicator.PostSettingsPanelDraw.Invoke(selection.Mod!.Identifier);
|
||||
communicator.PostSettingsPanelDraw.Invoke(new PostSettingsPanelDraw.Arguments(selection.Mod!));
|
||||
}
|
||||
|
||||
/// <summary> Draw a big tinted bar if the current setting is temporary. </summary>
|
||||
|
|
@ -195,7 +196,7 @@ public class ModPanelSettingsTab(
|
|||
{
|
||||
(true, false) => ImUtf8.ButtonEx("Inherit Settings"u8,
|
||||
"Remove current settings from this collection so that it can inherit them.\n"u8
|
||||
+ "If no inherited collection has settings for this mod, it will be disabled."u8, default, false),
|
||||
+ "If no inherited collection has settings for this mod, it will be disabled."u8),
|
||||
(false, false) => ImUtf8.ButtonEx("Inherit Settings"u8,
|
||||
$"Remove current settings from this collection so that it can inherit them.\nHold {config.DeleteModModifier} to inherit.",
|
||||
default, true),
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue