mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Current State.
This commit is contained in:
parent
282189ef6d
commit
5f9cbe9ab1
14 changed files with 381 additions and 213 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit fdda2054c26a30111ac55984ed6efde7f7214b68
|
Subproject commit 882b778e78bb0806dd7d38e8b3670ff138a84a31
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit dd83f97299ac33cfacb1064bde4f4d1f6a260936
|
Subproject commit 0647fbc5017ef9ced3f3ce1c2496eefd57c5b7a8
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Log;
|
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Api.Helpers;
|
using Penumbra.Api.Helpers;
|
||||||
|
|
@ -25,20 +24,18 @@ public class ModSettingsApi : IPenumbraApiModSettings, IApiService, IDisposable
|
||||||
private readonly CollectionManager _collectionManager;
|
private readonly CollectionManager _collectionManager;
|
||||||
private readonly CollectionEditor _collectionEditor;
|
private readonly CollectionEditor _collectionEditor;
|
||||||
private readonly CommunicatorService _communicator;
|
private readonly CommunicatorService _communicator;
|
||||||
private readonly ApiHelpers _helpers;
|
|
||||||
|
|
||||||
public ModSettingsApi(CollectionResolver collectionResolver,
|
public ModSettingsApi(CollectionResolver collectionResolver,
|
||||||
ModManager modManager,
|
ModManager modManager,
|
||||||
CollectionManager collectionManager,
|
CollectionManager collectionManager,
|
||||||
CollectionEditor collectionEditor,
|
CollectionEditor collectionEditor,
|
||||||
CommunicatorService communicator, ApiHelpers helpers)
|
CommunicatorService communicator)
|
||||||
{
|
{
|
||||||
_collectionResolver = collectionResolver;
|
_collectionResolver = collectionResolver;
|
||||||
_modManager = modManager;
|
_modManager = modManager;
|
||||||
_collectionManager = collectionManager;
|
_collectionManager = collectionManager;
|
||||||
_collectionEditor = collectionEditor;
|
_collectionEditor = collectionEditor;
|
||||||
_communicator = communicator;
|
_communicator = communicator;
|
||||||
_helpers = helpers;
|
|
||||||
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ApiModSettings);
|
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ApiModSettings);
|
||||||
_communicator.ModSettingChanged.Subscribe(OnModSettingChange, Communication.ModSettingChanged.Priority.Api);
|
_communicator.ModSettingChanged.Subscribe(OnModSettingChange, Communication.ModSettingChanged.Priority.Api);
|
||||||
_communicator.ModOptionChanged.Subscribe(OnModOptionEdited, ModOptionChanged.Priority.Api);
|
_communicator.ModOptionChanged.Subscribe(OnModOptionEdited, ModOptionChanged.Priority.Api);
|
||||||
|
|
@ -209,142 +206,6 @@ public class ModSettingsApi : IPenumbraApiModSettings, IApiService, IDisposable
|
||||||
return ApiHelpers.Return(PenumbraApiEc.Success, args);
|
return ApiHelpers.Return(PenumbraApiEc.Success, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PenumbraApiEc SetTemporaryModSetting(Guid collectionId, string modDirectory, string modName, bool enabled, int priority,
|
|
||||||
IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key)
|
|
||||||
{
|
|
||||||
var args = ApiHelpers.Args("CollectionId", collectionId, "ModDirectory", modDirectory, "ModName", modName, "Enabled", enabled,
|
|
||||||
"Priority", priority, "Options", options, "Source", source, "Key", key);
|
|
||||||
if (!_collectionManager.Storage.ById(collectionId, out var collection))
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.CollectionMissing, args);
|
|
||||||
|
|
||||||
return SetTemporaryModSetting(args, collection, modDirectory, modName, enabled, priority, options, source, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PenumbraApiEc TemporaryModSettingsPlayer(int objectIndex, string modDirectory, string modName, bool enabled, int priority,
|
|
||||||
IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key)
|
|
||||||
{
|
|
||||||
return PenumbraApiEc.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PenumbraApiEc SetTemporaryModSetting(in LazyString args, ModCollection collection, string modDirectory, string modName,
|
|
||||||
bool enabled, int priority,
|
|
||||||
IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key)
|
|
||||||
{
|
|
||||||
if (!_modManager.TryGetMod(modDirectory, modName, out var mod))
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.ModMissing, args);
|
|
||||||
|
|
||||||
if (collection.GetTempSettings(mod.Index) is { } settings && settings.Lock != 0 && settings.Lock != key)
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.TemporarySettingDisallowed, args);
|
|
||||||
|
|
||||||
settings = new TemporaryModSettings
|
|
||||||
{
|
|
||||||
Enabled = enabled,
|
|
||||||
Priority = new ModPriority(priority),
|
|
||||||
Lock = key,
|
|
||||||
Source = source,
|
|
||||||
Settings = SettingList.Default(mod),
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var (groupName, optionNames) in options)
|
|
||||||
{
|
|
||||||
var groupIdx = mod.Groups.IndexOf(g => g.Name == groupName);
|
|
||||||
if (groupIdx < 0)
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.OptionGroupMissing, args);
|
|
||||||
|
|
||||||
var setting = Setting.Zero;
|
|
||||||
switch (mod.Groups[groupIdx])
|
|
||||||
{
|
|
||||||
case { Behaviour: GroupDrawBehaviour.SingleSelection } single:
|
|
||||||
{
|
|
||||||
var optionIdx = optionNames.Count == 0 ? -1 : single.Options.IndexOf(o => o.Name == optionNames[^1]);
|
|
||||||
if (optionIdx < 0)
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.OptionMissing, args);
|
|
||||||
|
|
||||||
setting = Setting.Single(optionIdx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case { Behaviour: GroupDrawBehaviour.MultiSelection } multi:
|
|
||||||
{
|
|
||||||
foreach (var name in optionNames)
|
|
||||||
{
|
|
||||||
var optionIdx = multi.Options.IndexOf(o => o.Name == name);
|
|
||||||
if (optionIdx < 0)
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.OptionMissing, args);
|
|
||||||
|
|
||||||
setting |= Setting.Multi(optionIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.Settings[groupIdx] = setting;
|
|
||||||
}
|
|
||||||
|
|
||||||
collection.Settings.SetTemporary(mod.Index, settings);
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.Success, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PenumbraApiEc RemoveTemporaryModSettings(Guid collectionId, string modDirectory, string modName, int key)
|
|
||||||
{
|
|
||||||
var args = ApiHelpers.Args("CollectionId", collectionId, "ModDirectory", modDirectory, "ModName", modName, "Key", key);
|
|
||||||
if (!_collectionManager.Storage.ById(collectionId, out var collection))
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.CollectionMissing, args);
|
|
||||||
|
|
||||||
return RemoveTemporaryModSettings(args, collection, modDirectory, modName, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PenumbraApiEc RemoveTemporaryModSettings(in LazyString args, ModCollection collection, string modDirectory, string modName, int key)
|
|
||||||
{
|
|
||||||
if (!_modManager.TryGetMod(modDirectory, modName, out var mod))
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.ModMissing, args);
|
|
||||||
|
|
||||||
if (collection.GetTempSettings(mod.Index) is not { } settings)
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.NothingChanged, args);
|
|
||||||
|
|
||||||
if (settings.Lock != 0 && settings.Lock != key)
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.TemporarySettingDisallowed, args);
|
|
||||||
|
|
||||||
collection.Settings.SetTemporary(mod.Index, null);
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.Success, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PenumbraApiEc RemoveTemporaryModSettingsPlayer(int objectIndex, string modDirectory, string modName, int key)
|
|
||||||
{
|
|
||||||
return PenumbraApiEc.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PenumbraApiEc RemoveAllTemporaryModSettings(Guid collectionId, int key)
|
|
||||||
{
|
|
||||||
var args = ApiHelpers.Args("CollectionId", collectionId, "Key", key);
|
|
||||||
if (!_collectionManager.Storage.ById(collectionId, out var collection))
|
|
||||||
return ApiHelpers.Return(PenumbraApiEc.CollectionMissing, args);
|
|
||||||
|
|
||||||
return RemoveAllTemporaryModSettings(args, collection, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PenumbraApiEc RemoveAllTemporaryModSettingsPlayer(int objectIndex, int key)
|
|
||||||
{
|
|
||||||
return PenumbraApiEc.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PenumbraApiEc RemoveAllTemporaryModSettings(in LazyString args, ModCollection collection, int key)
|
|
||||||
{
|
|
||||||
var numRemoved = 0;
|
|
||||||
for (var i = 0; i < collection.Settings.Count; ++i)
|
|
||||||
{
|
|
||||||
if (collection.GetTempSettings(i) is { } settings && (settings.Lock == 0 || settings.Lock == key))
|
|
||||||
{
|
|
||||||
collection.Settings.SetTemporary(i, null);
|
|
||||||
++numRemoved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ApiHelpers.Return(numRemoved > 0 ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private void TriggerSettingEdited(Mod mod)
|
private void TriggerSettingEdited(Mod mod)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ public class PenumbraApi(
|
||||||
}
|
}
|
||||||
|
|
||||||
public (int Breaking, int Feature) ApiVersion
|
public (int Breaking, int Feature) ApiVersion
|
||||||
=> (5, 3);
|
=> (5, 4);
|
||||||
|
|
||||||
public bool Valid { get; private set; } = true;
|
public bool Valid { get; private set; } = true;
|
||||||
public IPenumbraApiCollection Collection { get; } = collection;
|
public IPenumbraApiCollection Collection { get; } = collection;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
using OtterGui.Log;
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.Interop;
|
using Penumbra.GameData.Interop;
|
||||||
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.Mods.Settings;
|
using Penumbra.Mods.Settings;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
|
|
||||||
|
|
@ -13,7 +16,9 @@ public class TemporaryApi(
|
||||||
ObjectManager objects,
|
ObjectManager objects,
|
||||||
ActorManager actors,
|
ActorManager actors,
|
||||||
CollectionManager collectionManager,
|
CollectionManager collectionManager,
|
||||||
TempModManager tempMods) : IPenumbraApiTemporary, IApiService
|
TempModManager tempMods,
|
||||||
|
ApiHelpers apiHelpers,
|
||||||
|
ModManager modManager) : IPenumbraApiTemporary, IApiService
|
||||||
{
|
{
|
||||||
public Guid CreateTemporaryCollection(string name)
|
public Guid CreateTemporaryCollection(string name)
|
||||||
=> tempCollections.CreateTemporaryCollection(name);
|
=> tempCollections.CreateTemporaryCollection(name);
|
||||||
|
|
@ -125,6 +130,139 @@ public class TemporaryApi(
|
||||||
return ApiHelpers.Return(ret, args);
|
return ApiHelpers.Return(ret, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public PenumbraApiEc SetTemporaryModSettings(Guid collectionId, string modDirectory, string modName, bool inherit, bool enabled, int priority,
|
||||||
|
IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key)
|
||||||
|
{
|
||||||
|
var args = ApiHelpers.Args("CollectionId", collectionId, "ModDirectory", modDirectory, "ModName", modName, "Inherit", inherit, "Enabled", enabled,
|
||||||
|
"Priority", priority, "Options", options, "Source", source, "Key", key);
|
||||||
|
if (!collectionManager.Storage.ById(collectionId, out var collection))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.CollectionMissing, args);
|
||||||
|
|
||||||
|
return SetTemporaryModSettings(args, collection, modDirectory, modName, inherit, enabled, priority, options, source, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PenumbraApiEc SetTemporaryModSettingsPlayer(int objectIndex, string modDirectory, string modName, bool inherit, bool enabled, int priority,
|
||||||
|
IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key)
|
||||||
|
{
|
||||||
|
var args = ApiHelpers.Args("ObjectIndex", objectIndex, "ModDirectory", modDirectory, "ModName", modName, "Inherit", inherit, "Enabled", enabled,
|
||||||
|
"Priority", priority, "Options", options, "Source", source, "Key", key);
|
||||||
|
if (!apiHelpers.AssociatedCollection(objectIndex, out var collection))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.InvalidArgument, args);
|
||||||
|
|
||||||
|
return SetTemporaryModSettings(args, collection, modDirectory, modName, inherit, enabled, priority, options, source, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PenumbraApiEc SetTemporaryModSettings(in LazyString args, ModCollection collection, string modDirectory, string modName,
|
||||||
|
bool inherit, bool enabled, int priority, IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key)
|
||||||
|
{
|
||||||
|
if (collection.Identity.Index <= 0)
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.TemporarySettingImpossible, args);
|
||||||
|
|
||||||
|
if (!modManager.TryGetMod(modDirectory, modName, out var mod))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.ModMissing, args);
|
||||||
|
|
||||||
|
if (!collectionManager.Editor.CanSetTemporarySettings(collection, mod, key))
|
||||||
|
if (collection.GetTempSettings(mod.Index) is { } oldSettings && oldSettings.Lock != 0 && oldSettings.Lock != key)
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.TemporarySettingDisallowed, args);
|
||||||
|
|
||||||
|
var newSettings = new TemporaryModSettings()
|
||||||
|
{
|
||||||
|
ForceInherit = inherit,
|
||||||
|
Enabled = enabled,
|
||||||
|
Priority = new ModPriority(priority),
|
||||||
|
Lock = key,
|
||||||
|
Source = source,
|
||||||
|
Settings = SettingList.Default(mod),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var (groupName, optionNames) in options)
|
||||||
|
{
|
||||||
|
var ec = ModSettingsApi.ConvertModSetting(mod, groupName, optionNames, out var groupIdx, out var setting);
|
||||||
|
if (ec != PenumbraApiEc.Success)
|
||||||
|
return ApiHelpers.Return(ec, args);
|
||||||
|
|
||||||
|
newSettings.Settings[groupIdx] = setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectionManager.Editor.SetTemporarySettings(collection, mod, newSettings, key))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.Success, args);
|
||||||
|
|
||||||
|
// This should not happen since all error cases had been checked before.
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.UnknownError, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PenumbraApiEc RemoveTemporaryModSettings(Guid collectionId, string modDirectory, string modName, int key)
|
||||||
|
{
|
||||||
|
var args = ApiHelpers.Args("CollectionId", collectionId, "ModDirectory", modDirectory, "ModName", modName, "Key", key);
|
||||||
|
if (!collectionManager.Storage.ById(collectionId, out var collection))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.CollectionMissing, args);
|
||||||
|
|
||||||
|
return RemoveTemporaryModSettings(args, collection, modDirectory, modName, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PenumbraApiEc RemoveTemporaryModSettingsPlayer(int objectIndex, string modDirectory, string modName, int key)
|
||||||
|
{
|
||||||
|
var args = ApiHelpers.Args("ObjectIndex", objectIndex, "ModDirectory", modDirectory, "ModName", modName, "Key", key);
|
||||||
|
if (!apiHelpers.AssociatedCollection(objectIndex, out var collection))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.InvalidArgument, args);
|
||||||
|
|
||||||
|
return RemoveTemporaryModSettings(args, collection, modDirectory, modName, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PenumbraApiEc RemoveTemporaryModSettings(in LazyString args, ModCollection collection, string modDirectory, string modName, int key)
|
||||||
|
{
|
||||||
|
if (collection.Identity.Index <= 0)
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.NothingChanged, args);
|
||||||
|
|
||||||
|
if (!modManager.TryGetMod(modDirectory, modName, out var mod))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.ModMissing, args);
|
||||||
|
|
||||||
|
if (collection.GetTempSettings(mod.Index) is null)
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.NothingChanged, args);
|
||||||
|
|
||||||
|
if (!collectionManager.Editor.SetTemporarySettings(collection, mod, null, key))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.TemporarySettingDisallowed, args);
|
||||||
|
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.Success, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PenumbraApiEc RemoveAllTemporaryModSettings(Guid collectionId, int key)
|
||||||
|
{
|
||||||
|
var args = ApiHelpers.Args("CollectionId", collectionId, "Key", key);
|
||||||
|
if (!collectionManager.Storage.ById(collectionId, out var collection))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.CollectionMissing, args);
|
||||||
|
|
||||||
|
return RemoveAllTemporaryModSettings(args, collection, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PenumbraApiEc RemoveAllTemporaryModSettingsPlayer(int objectIndex, int key)
|
||||||
|
{
|
||||||
|
var args = ApiHelpers.Args("ObjectIndex", objectIndex, "Key", key);
|
||||||
|
if (!apiHelpers.AssociatedCollection(objectIndex, out var collection))
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.InvalidArgument, args);
|
||||||
|
|
||||||
|
return RemoveAllTemporaryModSettings(args, collection, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PenumbraApiEc RemoveAllTemporaryModSettings(in LazyString args, ModCollection collection, int key)
|
||||||
|
{
|
||||||
|
if (collection.Identity.Index <= 0)
|
||||||
|
return ApiHelpers.Return(PenumbraApiEc.NothingChanged, args);
|
||||||
|
|
||||||
|
var numRemoved = 0;
|
||||||
|
for (var i = 0; i < collection.Settings.Count; ++i)
|
||||||
|
{
|
||||||
|
if (collection.GetTempSettings(i) is not null
|
||||||
|
&& collectionManager.Editor.SetTemporarySettings(collection, modManager[i], null, key))
|
||||||
|
++numRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ApiHelpers.Return(numRemoved > 0 ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a dictionary of strings to a dictionary of game paths to full paths.
|
/// Convert a dictionary of strings to a dictionary of game paths to full paths.
|
||||||
/// Only returns true if all paths can successfully be converted and added.
|
/// Only returns true if all paths can successfully be converted and added.
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public sealed class IpcProviders : IDisposable, IApiService
|
||||||
|
|
||||||
IpcSubscribers.ApiVersion.Provider(pi, api),
|
IpcSubscribers.ApiVersion.Provider(pi, api),
|
||||||
new FuncProvider<(int Major, int Minor)>(pi, "Penumbra.ApiVersions", () => api.ApiVersion), // backward compatibility
|
new FuncProvider<(int Major, int Minor)>(pi, "Penumbra.ApiVersions", () => api.ApiVersion), // backward compatibility
|
||||||
new FuncProvider<int>(pi, "Penumbra.ApiVersion", () => api.ApiVersion.Breaking), // backward compatibility
|
new FuncProvider<int>(pi, "Penumbra.ApiVersion", () => api.ApiVersion.Breaking), // backward compatibility
|
||||||
IpcSubscribers.GetModDirectory.Provider(pi, api.PluginState),
|
IpcSubscribers.GetModDirectory.Provider(pi, api.PluginState),
|
||||||
IpcSubscribers.GetConfiguration.Provider(pi, api.PluginState),
|
IpcSubscribers.GetConfiguration.Provider(pi, api.PluginState),
|
||||||
IpcSubscribers.ModDirectoryChanged.Provider(pi, api.PluginState),
|
IpcSubscribers.ModDirectoryChanged.Provider(pi, api.PluginState),
|
||||||
|
|
@ -97,6 +97,12 @@ public sealed class IpcProviders : IDisposable, IApiService
|
||||||
IpcSubscribers.AddTemporaryMod.Provider(pi, api.Temporary),
|
IpcSubscribers.AddTemporaryMod.Provider(pi, api.Temporary),
|
||||||
IpcSubscribers.RemoveTemporaryModAll.Provider(pi, api.Temporary),
|
IpcSubscribers.RemoveTemporaryModAll.Provider(pi, api.Temporary),
|
||||||
IpcSubscribers.RemoveTemporaryMod.Provider(pi, api.Temporary),
|
IpcSubscribers.RemoveTemporaryMod.Provider(pi, api.Temporary),
|
||||||
|
IpcSubscribers.SetTemporaryModSettings.Provider(pi, api.Temporary),
|
||||||
|
IpcSubscribers.SetTemporaryModSettingsPlayer.Provider(pi, api.Temporary),
|
||||||
|
IpcSubscribers.RemoveTemporaryModSettings.Provider(pi, api.Temporary),
|
||||||
|
IpcSubscribers.RemoveTemporaryModSettingsPlayer.Provider(pi, api.Temporary),
|
||||||
|
IpcSubscribers.RemoveAllTemporaryModSettings.Provider(pi, api.Temporary),
|
||||||
|
IpcSubscribers.RemoveAllTemporaryModSettingsPlayer.Provider(pi, api.Temporary),
|
||||||
|
|
||||||
IpcSubscribers.ChangedItemTooltip.Provider(pi, api.Ui),
|
IpcSubscribers.ChangedItemTooltip.Provider(pi, api.Ui),
|
||||||
IpcSubscribers.ChangedItemClicked.Provider(pi, api.Ui),
|
IpcSubscribers.ChangedItemClicked.Provider(pi, api.Ui),
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ public class TemporaryIpcTester(
|
||||||
private string _tempCollectionName = string.Empty;
|
private string _tempCollectionName = string.Empty;
|
||||||
private string _tempCollectionGuidName = string.Empty;
|
private string _tempCollectionGuidName = string.Empty;
|
||||||
private string _tempModName = string.Empty;
|
private string _tempModName = string.Empty;
|
||||||
|
private string _modDirectory = string.Empty;
|
||||||
private string _tempGamePath = "test/game/path.mtrl";
|
private string _tempGamePath = "test/game/path.mtrl";
|
||||||
private string _tempFilePath = "test/success.mtrl";
|
private string _tempFilePath = "test/success.mtrl";
|
||||||
private string _tempManipulation = string.Empty;
|
private string _tempManipulation = string.Empty;
|
||||||
|
|
@ -50,6 +51,7 @@ public class TemporaryIpcTester(
|
||||||
ImGuiUtil.GuidInput("##guid", "Collection GUID...", string.Empty, ref _tempGuid, ref _tempCollectionGuidName);
|
ImGuiUtil.GuidInput("##guid", "Collection GUID...", string.Empty, ref _tempGuid, ref _tempCollectionGuidName);
|
||||||
ImGui.InputInt("##tempActorIndex", ref _tempActorIndex, 0, 0);
|
ImGui.InputInt("##tempActorIndex", ref _tempActorIndex, 0, 0);
|
||||||
ImGui.InputTextWithHint("##tempMod", "Temporary Mod Name...", ref _tempModName, 32);
|
ImGui.InputTextWithHint("##tempMod", "Temporary Mod Name...", ref _tempModName, 32);
|
||||||
|
ImGui.InputTextWithHint("##mod", "Existing Mod Name...", ref _modDirectory, 256);
|
||||||
ImGui.InputTextWithHint("##tempGame", "Game Path...", ref _tempGamePath, 256);
|
ImGui.InputTextWithHint("##tempGame", "Game Path...", ref _tempGamePath, 256);
|
||||||
ImGui.InputTextWithHint("##tempFile", "File Path...", ref _tempFilePath, 256);
|
ImGui.InputTextWithHint("##tempFile", "File Path...", ref _tempFilePath, 256);
|
||||||
ImUtf8.InputText("##tempManip"u8, ref _tempManipulation, "Manipulation Base64 String..."u8);
|
ImUtf8.InputText("##tempManip"u8, ref _tempManipulation, "Manipulation Base64 String..."u8);
|
||||||
|
|
@ -121,6 +123,44 @@ public class TemporaryIpcTester(
|
||||||
IpcTester.DrawIntro(RemoveTemporaryModAll.Label, "Remove Temporary Mod from all Collections");
|
IpcTester.DrawIntro(RemoveTemporaryModAll.Label, "Remove Temporary Mod from all Collections");
|
||||||
if (ImGui.Button("Remove##ModAll"))
|
if (ImGui.Button("Remove##ModAll"))
|
||||||
_lastTempError = new RemoveTemporaryModAll(pi).Invoke(_tempModName, int.MaxValue);
|
_lastTempError = new RemoveTemporaryModAll(pi).Invoke(_tempModName, int.MaxValue);
|
||||||
|
|
||||||
|
IpcTester.DrawIntro(SetTemporaryModSettings.Label, "Set Temporary Mod Settings (to default) in specific Collection");
|
||||||
|
if (ImUtf8.Button("Set##SetTemporary"u8))
|
||||||
|
_lastTempError = new SetTemporaryModSettings(pi).Invoke(guid, _modDirectory, string.Empty, false, true, 1337, new Dictionary<string, IReadOnlyList<string>>(),
|
||||||
|
"IPC Tester", 1337);
|
||||||
|
|
||||||
|
IpcTester.DrawIntro(SetTemporaryModSettingsPlayer.Label, "Set Temporary Mod Settings (to default) in game object collection");
|
||||||
|
if (ImUtf8.Button("Set##SetTemporaryPlayer"u8))
|
||||||
|
_lastTempError = new SetTemporaryModSettingsPlayer(pi).Invoke(_tempActorIndex, _modDirectory, string.Empty, false, true, 1337, new Dictionary<string, IReadOnlyList<string>>(),
|
||||||
|
"IPC Tester", 1337);
|
||||||
|
|
||||||
|
IpcTester.DrawIntro(RemoveTemporaryModSettings.Label, "Remove Temporary Mod Settings from specific Collection");
|
||||||
|
if (ImUtf8.Button("Remove##RemoveTemporary"u8))
|
||||||
|
_lastTempError = new RemoveTemporaryModSettings(pi).Invoke(guid, _modDirectory, string.Empty, 1337);
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImUtf8.Button("Remove (Wrong Key)##RemoveTemporary"u8))
|
||||||
|
_lastTempError = new RemoveTemporaryModSettings(pi).Invoke(guid, _modDirectory, string.Empty, 1338);
|
||||||
|
|
||||||
|
IpcTester.DrawIntro(RemoveTemporaryModSettingsPlayer.Label, "Remove Temporary Mod Settings from game object Collection");
|
||||||
|
if (ImUtf8.Button("Remove##RemoveTemporaryPlayer"u8))
|
||||||
|
_lastTempError = new RemoveTemporaryModSettingsPlayer(pi).Invoke(_tempActorIndex, _modDirectory, string.Empty, 1337);
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImUtf8.Button("Remove (Wrong Key)##RemoveTemporaryPlayer"u8))
|
||||||
|
_lastTempError = new RemoveTemporaryModSettingsPlayer(pi).Invoke(_tempActorIndex, _modDirectory, string.Empty, 1338);
|
||||||
|
|
||||||
|
IpcTester.DrawIntro(RemoveAllTemporaryModSettings.Label, "Remove All Temporary Mod Settings from specific Collection");
|
||||||
|
if (ImUtf8.Button("Remove##RemoveAllTemporary"u8))
|
||||||
|
_lastTempError = new RemoveAllTemporaryModSettings(pi).Invoke(guid, 1337);
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImUtf8.Button("Remove (Wrong Key)##RemoveAllTemporary"u8))
|
||||||
|
_lastTempError = new RemoveAllTemporaryModSettings(pi).Invoke(guid, 1338);
|
||||||
|
|
||||||
|
IpcTester.DrawIntro(RemoveAllTemporaryModSettingsPlayer.Label, "Remove All Temporary Mod Settings from game object Collection");
|
||||||
|
if (ImUtf8.Button("Remove##RemoveAllTemporaryPlayer"u8))
|
||||||
|
_lastTempError = new RemoveAllTemporaryModSettingsPlayer(pi).Invoke(_tempActorIndex, 1337);
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImUtf8.Button("Remove (Wrong Key)##RemoveAllTemporaryPlayer"u8))
|
||||||
|
_lastTempError = new RemoveAllTemporaryModSettingsPlayer(pi).Invoke(_tempActorIndex, 1338);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawCollections()
|
public void DrawCollections()
|
||||||
|
|
|
||||||
|
|
@ -106,8 +106,7 @@ public class CollectionEditor(SaveService saveService, CommunicatorService commu
|
||||||
public bool SetTemporarySettings(ModCollection collection, Mod mod, TemporaryModSettings? settings, int key = 0)
|
public bool SetTemporarySettings(ModCollection collection, Mod mod, TemporaryModSettings? settings, int key = 0)
|
||||||
{
|
{
|
||||||
key = settings?.Lock ?? key;
|
key = settings?.Lock ?? key;
|
||||||
var old = collection.GetTempSettings(mod.Index);
|
if (!CanSetTemporarySettings(collection, mod, key))
|
||||||
if (old != null && old.Lock != 0 && old.Lock != key)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
collection.Settings.SetTemporary(mod.Index, settings);
|
collection.Settings.SetTemporary(mod.Index, settings);
|
||||||
|
|
@ -115,6 +114,12 @@ public class CollectionEditor(SaveService saveService, CommunicatorService commu
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanSetTemporarySettings(ModCollection collection, Mod mod, int key)
|
||||||
|
{
|
||||||
|
var old = collection.GetTempSettings(mod.Index);
|
||||||
|
return old == null || old.Lock == 0 || old.Lock == key;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Copy the settings of an existing (sourceMod != null) or stored (sourceName) mod to another mod, if they exist. </summary>
|
/// <summary> Copy the settings of an existing (sourceMod != null) or stored (sourceName) mod to another mod, if they exist. </summary>
|
||||||
public bool CopyModSettings(ModCollection collection, Mod? sourceMod, string sourceName, Mod? targetMod, string targetName)
|
public bool CopyModSettings(ModCollection collection, Mod? sourceMod, string sourceName, Mod? targetMod, string targetName)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ public unsafe class SchedulerResourceManagementService : IService, IDisposable
|
||||||
if (_actionTmbs.TryGetValue(tmb, out var rowId))
|
if (_actionTmbs.TryGetValue(tmb, out var rowId))
|
||||||
_listedTmbIds[rowId] = tmb;
|
_listedTmbIds[rowId] = tmb;
|
||||||
else
|
else
|
||||||
Penumbra.Log.Debug($"Action TMB {gamePath} encountered with no corresponding row ID.");
|
Penumbra.Log.Verbose($"Action TMB {gamePath} encountered with no corresponding row ID.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Signature(Sigs.SchedulerResourceManagementInstance, ScanType = ScanType.StaticAddress)]
|
[Signature(Sigs.SchedulerResourceManagementInstance, ScanType = ScanType.StaticAddress)]
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,22 @@ public sealed class TemporaryModSettings : ModSettings
|
||||||
Priority = ModPriority.Default,
|
Priority = ModPriority.Default,
|
||||||
Settings = SettingList.Default(mod),
|
Settings = SettingList.Default(mod),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public TemporaryModSettings()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public TemporaryModSettings(ModSettings? clone, string source, int key = 0)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
Lock = key;
|
||||||
|
ForceInherit = clone == null;
|
||||||
|
if (clone != null)
|
||||||
|
{
|
||||||
|
Enabled = clone.Enabled;
|
||||||
|
Priority = clone.Priority;
|
||||||
|
Settings = clone.Settings.Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ModSettingsExtensions
|
public static class ModSettingsExtensions
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,24 @@ public static class Colors
|
||||||
{
|
{
|
||||||
var tintValue = ImGui.ColorConvertU32ToFloat4(tint.Value());
|
var tintValue = ImGui.ColorConvertU32ToFloat4(tint.Value());
|
||||||
var value = ImGui.ColorConvertU32ToFloat4(color.Value());
|
var value = ImGui.ColorConvertU32ToFloat4(color.Value());
|
||||||
var negAlpha = 1 - tintValue.W;
|
return ImGui.ColorConvertFloat4ToU32(TintColor(value, tintValue));
|
||||||
var newAlpha = negAlpha * value.W + tintValue.W;
|
}
|
||||||
var newR = (negAlpha * value.W * value.X + tintValue.W * tintValue.X) / newAlpha;
|
|
||||||
var newG = (negAlpha * value.W * value.Y + tintValue.W * tintValue.Y) / newAlpha;
|
public static unsafe uint Tinted(this ImGuiCol color, ColorId tint)
|
||||||
var newB = (negAlpha * value.W * value.Z + tintValue.W * tintValue.Z) / newAlpha;
|
{
|
||||||
return ImGui.ColorConvertFloat4ToU32(new Vector4(newR, newG, newB, newAlpha));
|
var tintValue = ImGui.ColorConvertU32ToFloat4(tint.Value());
|
||||||
|
ref var value = ref *ImGui.GetStyleColorVec4(color);
|
||||||
|
return ImGui.ColorConvertFloat4ToU32(TintColor(value, tintValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe Vector4 TintColor(in Vector4 color, in Vector4 tint)
|
||||||
|
{
|
||||||
|
var negAlpha = 1 - tint.W;
|
||||||
|
var newAlpha = negAlpha * color.W + tint.W;
|
||||||
|
var newR = (negAlpha * color.W * color.X + tint.W * tint.X) / newAlpha;
|
||||||
|
var newG = (negAlpha * color.W * color.Y + tint.W * tint.Y) / newAlpha;
|
||||||
|
var newB = (negAlpha * color.W * color.Z + tint.W * tint.Z) / newAlpha;
|
||||||
|
return new Vector4(newR, newG, newB, newAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (uint DefaultColor, string Name, string Description) Data(this ColorId color)
|
public static (uint DefaultColor, string Name, string Description) Data(this ColorId color)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
|
|
@ -16,13 +17,19 @@ namespace Penumbra.UI.ModsTab.Groups;
|
||||||
public sealed class ModGroupDrawer(Configuration config, CollectionManager collectionManager) : IUiService
|
public sealed class ModGroupDrawer(Configuration config, CollectionManager collectionManager) : IUiService
|
||||||
{
|
{
|
||||||
private readonly List<(IModGroup, int)> _blockGroupCache = [];
|
private readonly List<(IModGroup, int)> _blockGroupCache = [];
|
||||||
|
private bool _temporary;
|
||||||
|
private bool _locked;
|
||||||
|
private TemporaryModSettings? _tempSettings;
|
||||||
|
|
||||||
public void Draw(Mod mod, ModSettings settings)
|
public void Draw(Mod mod, ModSettings settings, TemporaryModSettings? tempSettings)
|
||||||
{
|
{
|
||||||
if (mod.Groups.Count <= 0)
|
if (mod.Groups.Count <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_blockGroupCache.Clear();
|
_blockGroupCache.Clear();
|
||||||
|
_tempSettings = tempSettings;
|
||||||
|
_temporary = tempSettings != null;
|
||||||
|
_locked = (tempSettings?.Lock ?? 0) != 0;
|
||||||
var useDummy = true;
|
var useDummy = true;
|
||||||
foreach (var (group, idx) in mod.Groups.WithIndex())
|
foreach (var (group, idx) in mod.Groups.WithIndex())
|
||||||
{
|
{
|
||||||
|
|
@ -63,22 +70,23 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void DrawSingleGroupCombo(IModGroup group, int groupIdx, Setting setting)
|
private void DrawSingleGroupCombo(IModGroup group, int groupIdx, Setting setting)
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId(groupIdx);
|
using var id = ImUtf8.PushId(groupIdx);
|
||||||
var selectedOption = setting.AsIndex;
|
var selectedOption = setting.AsIndex;
|
||||||
|
using var disabled = ImRaii.Disabled(_locked);
|
||||||
ImGui.SetNextItemWidth(UiHelpers.InputTextWidth.X * 3 / 4);
|
ImGui.SetNextItemWidth(UiHelpers.InputTextWidth.X * 3 / 4);
|
||||||
var options = group.Options;
|
var options = group.Options;
|
||||||
using (var combo = ImRaii.Combo(string.Empty, options[selectedOption].Name))
|
using (var combo = ImUtf8.Combo(""u8, options[selectedOption].Name))
|
||||||
{
|
{
|
||||||
if (combo)
|
if (combo)
|
||||||
for (var idx2 = 0; idx2 < options.Count; ++idx2)
|
for (var idx2 = 0; idx2 < options.Count; ++idx2)
|
||||||
{
|
{
|
||||||
id.Push(idx2);
|
id.Push(idx2);
|
||||||
var option = options[idx2];
|
var option = options[idx2];
|
||||||
if (ImGui.Selectable(option.Name, idx2 == selectedOption))
|
if (ImUtf8.Selectable(option.Name, idx2 == selectedOption))
|
||||||
SetModSetting(group, groupIdx, Setting.Single(idx2));
|
SetModSetting(group, groupIdx, Setting.Single(idx2));
|
||||||
|
|
||||||
if (option.Description.Length > 0)
|
if (option.Description.Length > 0)
|
||||||
ImGuiUtil.SelectableHelpMarker(option.Description);
|
ImUtf8.SelectableHelpMarker(option.Description);
|
||||||
|
|
||||||
id.Pop();
|
id.Pop();
|
||||||
}
|
}
|
||||||
|
|
@ -86,9 +94,9 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (group.Description.Length > 0)
|
if (group.Description.Length > 0)
|
||||||
ImGuiUtil.LabeledHelpMarker(group.Name, group.Description);
|
ImUtf8.LabeledHelpMarker(group.Name, group.Description);
|
||||||
else
|
else
|
||||||
ImGui.TextUnformatted(group.Name);
|
ImUtf8.Text(group.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -97,10 +105,10 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void DrawSingleGroupRadio(IModGroup group, int groupIdx, Setting setting)
|
private void DrawSingleGroupRadio(IModGroup group, int groupIdx, Setting setting)
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId(groupIdx);
|
using var id = ImUtf8.PushId(groupIdx);
|
||||||
var selectedOption = setting.AsIndex;
|
var selectedOption = setting.AsIndex;
|
||||||
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
||||||
var options = group.Options;
|
var options = group.Options;
|
||||||
DrawCollapseHandling(options, minWidth, DrawOptions);
|
DrawCollapseHandling(options, minWidth, DrawOptions);
|
||||||
|
|
||||||
Widget.EndFramedGroup();
|
Widget.EndFramedGroup();
|
||||||
|
|
@ -108,11 +116,12 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
|
|
||||||
void DrawOptions()
|
void DrawOptions()
|
||||||
{
|
{
|
||||||
|
using var disabled = ImRaii.Disabled(_locked);
|
||||||
for (var idx = 0; idx < group.Options.Count; ++idx)
|
for (var idx = 0; idx < group.Options.Count; ++idx)
|
||||||
{
|
{
|
||||||
using var i = ImRaii.PushId(idx);
|
using var i = ImUtf8.PushId(idx);
|
||||||
var option = options[idx];
|
var option = options[idx];
|
||||||
if (ImGui.RadioButton(option.Name, selectedOption == idx))
|
if (ImUtf8.RadioButton(option.Name, selectedOption == idx))
|
||||||
SetModSetting(group, groupIdx, Setting.Single(idx));
|
SetModSetting(group, groupIdx, Setting.Single(idx));
|
||||||
|
|
||||||
if (option.Description.Length <= 0)
|
if (option.Description.Length <= 0)
|
||||||
|
|
@ -130,28 +139,29 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void DrawMultiGroup(IModGroup group, int groupIdx, Setting setting)
|
private void DrawMultiGroup(IModGroup group, int groupIdx, Setting setting)
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId(groupIdx);
|
using var id = ImUtf8.PushId(groupIdx);
|
||||||
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
||||||
var options = group.Options;
|
var options = group.Options;
|
||||||
DrawCollapseHandling(options, minWidth, DrawOptions);
|
DrawCollapseHandling(options, minWidth, DrawOptions);
|
||||||
|
|
||||||
Widget.EndFramedGroup();
|
Widget.EndFramedGroup();
|
||||||
var label = $"##multi{groupIdx}";
|
var label = $"##multi{groupIdx}";
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||||
ImGui.OpenPopup($"##multi{groupIdx}");
|
ImUtf8.OpenPopup($"##multi{groupIdx}");
|
||||||
|
|
||||||
DrawMultiPopup(group, groupIdx, label);
|
DrawMultiPopup(group, groupIdx, label);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void DrawOptions()
|
void DrawOptions()
|
||||||
{
|
{
|
||||||
|
using var disabled = ImRaii.Disabled(_locked);
|
||||||
for (var idx = 0; idx < options.Count; ++idx)
|
for (var idx = 0; idx < options.Count; ++idx)
|
||||||
{
|
{
|
||||||
using var i = ImRaii.PushId(idx);
|
using var i = ImUtf8.PushId(idx);
|
||||||
var option = options[idx];
|
var option = options[idx];
|
||||||
var enabled = setting.HasFlag(idx);
|
var enabled = setting.HasFlag(idx);
|
||||||
|
|
||||||
if (ImGui.Checkbox(option.Name, ref enabled))
|
if (ImUtf8.Checkbox(option.Name, ref enabled))
|
||||||
SetModSetting(group, groupIdx, setting.SetBit(idx, enabled));
|
SetModSetting(group, groupIdx, setting.SetBit(idx, enabled));
|
||||||
|
|
||||||
if (option.Description.Length > 0)
|
if (option.Description.Length > 0)
|
||||||
|
|
@ -171,11 +181,12 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui.TextUnformatted(group.Name);
|
ImGui.TextUnformatted(group.Name);
|
||||||
|
using var disabled = ImRaii.Disabled(_locked);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
if (ImGui.Selectable("Enable All"))
|
if (ImUtf8.Selectable("Enable All"u8))
|
||||||
SetModSetting(group, groupIdx, Setting.AllBits(group.Options.Count));
|
SetModSetting(group, groupIdx, Setting.AllBits(group.Options.Count));
|
||||||
|
|
||||||
if (ImGui.Selectable("Disable All"))
|
if (ImUtf8.Selectable("Disable All"u8))
|
||||||
SetModSetting(group, groupIdx, Setting.Zero);
|
SetModSetting(group, groupIdx, Setting.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,11 +198,11 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var collapseId = ImGui.GetID("Collapse");
|
var collapseId = ImUtf8.GetId("Collapse");
|
||||||
var shown = ImGui.GetStateStorage().GetBool(collapseId, true);
|
var shown = ImGui.GetStateStorage().GetBool(collapseId, true);
|
||||||
var buttonTextShow = $"Show {options.Count} Options";
|
var buttonTextShow = $"Show {options.Count} Options";
|
||||||
var buttonTextHide = $"Hide {options.Count} Options";
|
var buttonTextHide = $"Hide {options.Count} Options";
|
||||||
var buttonWidth = Math.Max(ImGui.CalcTextSize(buttonTextShow).X, ImGui.CalcTextSize(buttonTextHide).X)
|
var buttonWidth = Math.Max(ImUtf8.CalcTextSize(buttonTextShow).X, ImUtf8.CalcTextSize(buttonTextHide).X)
|
||||||
+ 2 * ImGui.GetStyle().FramePadding.X;
|
+ 2 * ImGui.GetStyle().FramePadding.X;
|
||||||
minWidth = Math.Max(buttonWidth, minWidth);
|
minWidth = Math.Max(buttonWidth, minWidth);
|
||||||
if (shown)
|
if (shown)
|
||||||
|
|
@ -204,22 +215,22 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var width = Math.Max(ImGui.GetItemRectSize().X, minWidth);
|
var width = Math.Max(ImGui.GetItemRectSize().X, minWidth);
|
||||||
var endPos = ImGui.GetCursorPos();
|
var endPos = ImGui.GetCursorPos();
|
||||||
ImGui.SetCursorPos(pos);
|
ImGui.SetCursorPos(pos);
|
||||||
if (ImGui.Button(buttonTextHide, new Vector2(width, 0)))
|
if (ImUtf8.Button(buttonTextHide, new Vector2(width, 0)))
|
||||||
ImGui.GetStateStorage().SetBool(collapseId, !shown);
|
ImGui.GetStateStorage().SetBool(collapseId, !shown);
|
||||||
|
|
||||||
ImGui.SetCursorPos(endPos);
|
ImGui.SetCursorPos(endPos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var optionWidth = options.Max(o => ImGui.CalcTextSize(o.Name).X)
|
var optionWidth = options.Max(o => ImUtf8.CalcTextSize(o.Name).X)
|
||||||
+ ImGui.GetStyle().ItemInnerSpacing.X
|
+ ImGui.GetStyle().ItemInnerSpacing.X
|
||||||
+ ImGui.GetFrameHeight()
|
+ ImGui.GetFrameHeight()
|
||||||
+ ImGui.GetStyle().FramePadding.X;
|
+ ImGui.GetStyle().FramePadding.X;
|
||||||
var width = Math.Max(optionWidth, minWidth);
|
var width = Math.Max(optionWidth, minWidth);
|
||||||
if (ImGui.Button(buttonTextShow, new Vector2(width, 0)))
|
if (ImUtf8.Button(buttonTextShow, new Vector2(width, 0)))
|
||||||
ImGui.GetStateStorage().SetBool(collapseId, !shown);
|
ImGui.GetStateStorage().SetBool(collapseId, !shown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -228,6 +239,18 @@ public sealed class ModGroupDrawer(Configuration config, CollectionManager colle
|
||||||
private ModCollection Current
|
private ModCollection Current
|
||||||
=> collectionManager.Active.Current;
|
=> collectionManager.Active.Current;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private void SetModSetting(IModGroup group, int groupIdx, Setting setting)
|
private void SetModSetting(IModGroup group, int groupIdx, Setting setting)
|
||||||
=> collectionManager.Editor.SetModSetting(Current, group.Mod, groupIdx, setting);
|
{
|
||||||
|
if (_temporary)
|
||||||
|
{
|
||||||
|
_tempSettings!.ForceInherit = false;
|
||||||
|
_tempSettings!.Settings[groupIdx] = setting;
|
||||||
|
collectionManager.Editor.SetTemporarySettings(Current, group.Mod, _tempSettings);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collectionManager.Editor.SetModSetting(Current, group.Mod, groupIdx, setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui;
|
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
|
|
@ -24,6 +23,8 @@ public class ModPanelSettingsTab(
|
||||||
: ITab, IUiService
|
: ITab, IUiService
|
||||||
{
|
{
|
||||||
private bool _inherited;
|
private bool _inherited;
|
||||||
|
private bool _temporary;
|
||||||
|
private bool _locked;
|
||||||
private int? _currentPriority;
|
private int? _currentPriority;
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
|
|
@ -37,11 +38,14 @@ public class ModPanelSettingsTab(
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
{
|
{
|
||||||
using var child = ImRaii.Child("##settings");
|
using var child = ImUtf8.Child("##settings"u8, default);
|
||||||
if (!child)
|
if (!child)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_inherited = selection.Collection != collectionManager.Active.Current;
|
_inherited = selection.Collection != collectionManager.Active.Current;
|
||||||
|
_temporary = selection.TemporarySettings != null;
|
||||||
|
_locked = (selection.TemporarySettings?.Lock ?? 0) != 0;
|
||||||
|
DrawTemporaryWarning();
|
||||||
DrawInheritedWarning();
|
DrawInheritedWarning();
|
||||||
UiHelpers.DefaultLineSpace();
|
UiHelpers.DefaultLineSpace();
|
||||||
communicator.PreSettingsPanelDraw.Invoke(selection.Mod!.Identifier);
|
communicator.PreSettingsPanelDraw.Invoke(selection.Mod!.Identifier);
|
||||||
|
|
@ -54,11 +58,27 @@ public class ModPanelSettingsTab(
|
||||||
|
|
||||||
communicator.PostEnabledDraw.Invoke(selection.Mod!.Identifier);
|
communicator.PostEnabledDraw.Invoke(selection.Mod!.Identifier);
|
||||||
|
|
||||||
modGroupDrawer.Draw(selection.Mod!, selection.Settings);
|
modGroupDrawer.Draw(selection.Mod!, selection.Settings, selection.TemporarySettings);
|
||||||
UiHelpers.DefaultLineSpace();
|
UiHelpers.DefaultLineSpace();
|
||||||
communicator.PostSettingsPanelDraw.Invoke(selection.Mod!.Identifier);
|
communicator.PostSettingsPanelDraw.Invoke(selection.Mod!.Identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Draw a big tinted bar if the current setting is temporary. </summary>
|
||||||
|
private void DrawTemporaryWarning()
|
||||||
|
{
|
||||||
|
if (!_temporary)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.Button, ImGuiCol.Button.Tinted(ColorId.TemporaryModSettingsTint));
|
||||||
|
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
||||||
|
if (ImUtf8.ButtonEx($"These settings are temporary from {selection.TemporarySettings!.Source}{(_locked ? " and locked." : ".")}", width,
|
||||||
|
_locked))
|
||||||
|
collectionManager.Editor.SetTemporarySettings(collectionManager.Active.Current, selection.Mod!, null);
|
||||||
|
|
||||||
|
ImUtf8.HoverTooltip("Changing settings in temporary settings will not save them across sessions.\n"u8
|
||||||
|
+ "You can click this button to remove the temporary settings and return to your normal settings."u8);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Draw a big red bar if the current setting is inherited. </summary>
|
/// <summary> Draw a big red bar if the current setting is inherited. </summary>
|
||||||
private void DrawInheritedWarning()
|
private void DrawInheritedWarning()
|
||||||
{
|
{
|
||||||
|
|
@ -67,22 +87,42 @@ public class ModPanelSettingsTab(
|
||||||
|
|
||||||
using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.PressEnterWarningBg);
|
using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.PressEnterWarningBg);
|
||||||
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
||||||
if (ImGui.Button($"These settings are inherited from {selection.Collection.Identity.Name}.", width))
|
if (ImUtf8.ButtonEx($"These settings are inherited from {selection.Collection.Identity.Name}.", width, _locked))
|
||||||
collectionManager.Editor.SetModInheritance(collectionManager.Active.Current, selection.Mod!, false);
|
{
|
||||||
|
if (_temporary)
|
||||||
|
{
|
||||||
|
selection.TemporarySettings!.ForceInherit = false;
|
||||||
|
collectionManager.Editor.SetTemporarySettings(collectionManager.Active.Current, selection.Mod!, selection.TemporarySettings);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collectionManager.Editor.SetModInheritance(collectionManager.Active.Current, selection.Mod!, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGuiUtil.HoverTooltip("You can click this button to copy the current settings to the current selection.\n"
|
ImUtf8.HoverTooltip("You can click this button to copy the current settings to the current selection.\n"u8
|
||||||
+ "You can also just change any setting, which will copy the settings with the single setting changed to the current selection.");
|
+ "You can also just change any setting, which will copy the settings with the single setting changed to the current selection."u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Draw a checkbox for the enabled status of the mod. </summary>
|
/// <summary> Draw a checkbox for the enabled status of the mod. </summary>
|
||||||
private void DrawEnabledInput()
|
private void DrawEnabledInput()
|
||||||
{
|
{
|
||||||
var enabled = selection.Settings.Enabled;
|
var enabled = selection.Settings.Enabled;
|
||||||
if (!ImGui.Checkbox("Enabled", ref enabled))
|
using var disabled = ImRaii.Disabled(_locked);
|
||||||
|
if (!ImUtf8.Checkbox("Enabled"u8, ref enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
modManager.SetKnown(selection.Mod!);
|
modManager.SetKnown(selection.Mod!);
|
||||||
collectionManager.Editor.SetModState(collectionManager.Active.Current, selection.Mod!, enabled);
|
if (_temporary)
|
||||||
|
{
|
||||||
|
selection.TemporarySettings!.ForceInherit = false;
|
||||||
|
selection.TemporarySettings!.Enabled = enabled;
|
||||||
|
collectionManager.Editor.SetTemporarySettings(collectionManager.Active.Current, selection.Mod!, selection.TemporarySettings);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collectionManager.Editor.SetModState(collectionManager.Active.Current, selection.Mod!, enabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -91,45 +131,66 @@ public class ModPanelSettingsTab(
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void DrawPriorityInput()
|
private void DrawPriorityInput()
|
||||||
{
|
{
|
||||||
using var group = ImRaii.Group();
|
using var group = ImUtf8.Group();
|
||||||
var settings = selection.Settings;
|
var settings = selection.Settings;
|
||||||
var priority = _currentPriority ?? settings.Priority.Value;
|
var priority = _currentPriority ?? settings.Priority.Value;
|
||||||
ImGui.SetNextItemWidth(50 * UiHelpers.Scale);
|
ImGui.SetNextItemWidth(50 * UiHelpers.Scale);
|
||||||
if (ImGui.InputInt("##Priority", ref priority, 0, 0))
|
using var disabled = ImRaii.Disabled(_locked);
|
||||||
|
if (ImUtf8.InputScalar("##Priority"u8, ref priority))
|
||||||
_currentPriority = priority;
|
_currentPriority = priority;
|
||||||
if (new ModPriority(priority).IsHidden)
|
if (new ModPriority(priority).IsHidden)
|
||||||
ImUtf8.HoverTooltip($"This priority is special-cased to hide this mod in conflict tabs ({ModPriority.HiddenMin}, {ModPriority.HiddenMax}).");
|
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled,
|
||||||
|
$"This priority is special-cased to hide this mod in conflict tabs ({ModPriority.HiddenMin}, {ModPriority.HiddenMax}).");
|
||||||
|
|
||||||
|
|
||||||
if (ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue)
|
if (ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue)
|
||||||
{
|
{
|
||||||
if (_currentPriority != settings.Priority.Value)
|
if (_currentPriority != settings.Priority.Value)
|
||||||
collectionManager.Editor.SetModPriority(collectionManager.Active.Current, selection.Mod!,
|
{
|
||||||
new ModPriority(_currentPriority.Value));
|
if (_temporary)
|
||||||
|
{
|
||||||
|
selection.TemporarySettings!.ForceInherit = false;
|
||||||
|
selection.TemporarySettings!.Priority = new ModPriority(_currentPriority.Value);
|
||||||
|
collectionManager.Editor.SetTemporarySettings(collectionManager.Active.Current, selection.Mod!,
|
||||||
|
selection.TemporarySettings);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collectionManager.Editor.SetModPriority(collectionManager.Active.Current, selection.Mod!,
|
||||||
|
new ModPriority(_currentPriority.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_currentPriority = null;
|
_currentPriority = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiUtil.LabeledHelpMarker("Priority", "Mods with a higher number here take precedence before Mods with a lower number.\n"
|
ImUtf8.LabeledHelpMarker("Priority"u8, "Mods with a higher number here take precedence before Mods with a lower number.\n"u8
|
||||||
+ "That means, if Mod A should overwrite changes from Mod B, Mod A should have a higher priority number than Mod B.");
|
+ "That means, if Mod A should overwrite changes from Mod B, Mod A should have a higher priority number than Mod B."u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draw a button to remove the current settings and inherit them instead
|
/// Draw a button to remove the current settings and inherit them instead
|
||||||
/// on the top-right corner of the window/tab.
|
/// in the top-right corner of the window/tab.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void DrawRemoveSettings()
|
private void DrawRemoveSettings()
|
||||||
{
|
{
|
||||||
const string text = "Inherit Settings";
|
|
||||||
if (_inherited || selection.Settings == ModSettings.Empty)
|
if (_inherited || selection.Settings == ModSettings.Empty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var scroll = ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ScrollbarSize : 0;
|
var scroll = ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ScrollbarSize : 0;
|
||||||
ImGui.SameLine(ImGui.GetWindowWidth() - ImGui.CalcTextSize(text).X - ImGui.GetStyle().FramePadding.X * 2 - scroll);
|
ImGui.SameLine(ImGui.GetWindowWidth() - ImUtf8.CalcTextSize("Inherit Settings"u8).X - ImGui.GetStyle().FramePadding.X * 2 - scroll);
|
||||||
if (ImGui.Button(text))
|
if (!ImUtf8.ButtonEx("Inherit Settings"u8, "Remove current settings from this collection so that it can inherit them.\n"u8
|
||||||
collectionManager.Editor.SetModInheritance(collectionManager.Active.Current, selection.Mod!, true);
|
+ "If no inherited collection has settings for this mod, it will be disabled."u8, default, _locked))
|
||||||
|
return;
|
||||||
|
|
||||||
ImGuiUtil.HoverTooltip("Remove current settings from this collection so that it can inherit them.\n"
|
if (_temporary)
|
||||||
+ "If no inherited collection has settings for this mod, it will be disabled.");
|
{
|
||||||
|
selection.TemporarySettings!.ForceInherit = true;
|
||||||
|
collectionManager.Editor.SetTemporarySettings(collectionManager.Active.Current, selection.Mod!, selection.TemporarySettings);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collectionManager.Editor.SetModInheritance(collectionManager.Active.Current, selection.Mod!, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -791,19 +791,25 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
ImGuiClip.DrawEndDummy(dummy, ImGui.GetTextLineHeightWithSpacing());
|
ImGuiClip.DrawEndDummy(dummy, ImGui.GetTextLineHeightWithSpacing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string _tmbKeyFilter = string.Empty;
|
||||||
|
private CiByteString _tmbKeyFilterU8 = CiByteString.Empty;
|
||||||
|
|
||||||
private void DrawActionTmbs()
|
private void DrawActionTmbs()
|
||||||
{
|
{
|
||||||
using var mainTree = TreeNode("Action TMBs");
|
using var mainTree = TreeNode("Action TMBs");
|
||||||
if (!mainTree)
|
if (!mainTree)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ImGui.InputText("Key", ref _tmbKeyFilter, 256))
|
||||||
|
_tmbKeyFilterU8 = CiByteString.FromString(_tmbKeyFilter, out var r, MetaDataComputation.All) ? r : CiByteString.Empty;
|
||||||
using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
|
using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
|
||||||
new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing()));
|
new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing()));
|
||||||
if (!table)
|
if (!table)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||||
var dummy = ImGuiClip.ClippedDraw(_schedulerService.ActionTmbs.OrderBy(r => r.Value), skips,
|
var dummy = ImGuiClip.FilteredClippedDraw(_schedulerService.ActionTmbs.OrderBy(r => r.Value), skips,
|
||||||
|
kvp => kvp.Key.Contains(_tmbKeyFilterU8),
|
||||||
p =>
|
p =>
|
||||||
{
|
{
|
||||||
ImUtf8.DrawTableColumn($"{p.Value}");
|
ImUtf8.DrawTableColumn($"{p.Value}");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue