Move a lot of things over to Luna.
Some checks failed
.NET Build / build (push) Has been cancelled

This commit is contained in:
Ottermandias 2025-10-24 22:47:14 +02:00
parent d79e687162
commit 6b475ee229
66 changed files with 666 additions and 705 deletions

2
Luna

@ -1 +1 @@
Subproject commit c764db88097c88cd49f2bed4f60268d617f97fdb Subproject commit 2870892f30f7b92bd74110c7da366779eae85ce7

@ -1 +1 @@
Subproject commit cf3d868eeeb4ea3ea728ae15a8d09ec127ce80e9 Subproject commit 3a5a03ff24e24151f80584cd4a8d45b36d94db36

View file

@ -1,57 +1,52 @@
using Dalamud.Bindings.ImGui; using ImSharp;
using OtterGui.Text; using Luna.Generators;
namespace Penumbra; namespace Penumbra;
[NamedEnum(Unknown: "Error")]
[TooltipEnum]
public enum ChangedItemMode public enum ChangedItemMode
{ {
[Name("Grouped (Collapsed)")]
[Tooltip(
"Display items as groups by their model and slot. Collapse those groups to a single item by default. Prefers items with more changes affecting them or configured items as the main item.")]
GroupedCollapsed, GroupedCollapsed,
[Name("Grouped (Expanded)")]
[Tooltip(
"Display items as groups by their model and slot. Expand those groups showing all items by default. Prefers items with more changes affecting them or configured items as the main item.")]
GroupedExpanded, GroupedExpanded,
[Name("Alphabetical")]
[Tooltip("Display all changed items in a single list sorted alphabetically.")]
Alphabetical, Alphabetical,
} }
public static class ChangedItemModeExtensions public static partial class ChangedItemModeExtensions
{ {
public static ReadOnlySpan<byte> ToName(this ChangedItemMode mode) private static readonly ChangedItemModeCombo Combo = new();
=> mode switch
{
ChangedItemMode.GroupedCollapsed => "Grouped (Collapsed)"u8,
ChangedItemMode.GroupedExpanded => "Grouped (Expanded)"u8,
ChangedItemMode.Alphabetical => "Alphabetical"u8,
_ => "Error"u8,
};
public static ReadOnlySpan<byte> ToTooltip(this ChangedItemMode mode) private sealed class ChangedItemModeCombo() : SimpleFilterCombo<ChangedItemMode>(SimpleFilterType.Text)
=> mode switch {
{ public override StringU8 DisplayString(in ChangedItemMode value)
ChangedItemMode.GroupedCollapsed => => new(value.ToNameU8());
"Display items as groups by their model and slot. Collapse those groups to a single item by default. Prefers items with more changes affecting them or configured items as the main item."u8,
ChangedItemMode.GroupedExpanded => public override string FilterString(in ChangedItemMode value)
"Display items as groups by their model and slot. Expand those groups showing all items by default. Prefers items with more changes affecting them or configured items as the main item."u8, => value.ToName();
ChangedItemMode.Alphabetical => "Display all changed items in a single list sorted alphabetically."u8,
_ => ""u8, public override StringU8 Tooltip(in ChangedItemMode value)
}; => new(value.Tooltip());
public override IEnumerable<ChangedItemMode> GetBaseItems()
=> Enum.GetValues<ChangedItemMode>();
}
public static bool DrawCombo(ReadOnlySpan<byte> label, ChangedItemMode value, float width, Action<ChangedItemMode> setter) public static bool DrawCombo(ReadOnlySpan<byte> label, ChangedItemMode value, float width, Action<ChangedItemMode> setter)
{ {
ImGui.SetNextItemWidth(width); if (!Combo.Draw(label, ref value, StringU8.Empty, width))
using var combo = ImUtf8.Combo(label, value.ToName());
if (!combo)
return false; return false;
var ret = false; setter(value);
foreach (var newValue in Enum.GetValues<ChangedItemMode>()) return true;
{
var selected = ImUtf8.Selectable(newValue.ToName(), newValue == value);
if (selected)
{
ret = true;
setter(newValue);
}
ImUtf8.HoverTooltip(newValue.ToTooltip());
}
return ret;
} }
} }

View file

@ -1,7 +1,6 @@
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Lumina.Data.Parsing; using Lumina.Data.Parsing;
using Luna; using Luna;
using OtterGui.Tasks;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;

View file

@ -1,7 +1,4 @@
using Dalamud.Bindings.ImGui;
using ImSharp; using ImSharp;
using OtterGui;
using OtterGui.Raii;
using Penumbra.Import.Structs; using Penumbra.Import.Structs;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
@ -23,9 +20,9 @@ public partial class TexToolsImporter
public bool DrawProgressInfo(Vector2 size) public bool DrawProgressInfo(Vector2 size)
{ {
if (_modPackCount == 0) if (_modPackCount is 0)
{ {
ImGuiUtil.Center("Nothing to extract."); ImEx.TextCentered("Nothing to extract."u8);
return true; return true;
} }
@ -35,40 +32,40 @@ public partial class TexToolsImporter
return true; return true;
} }
ImGui.NewLine(); Im.Line.New();
var percentage = (float)_currentModPackIdx / _modPackCount; var percentage = (float)_currentModPackIdx / _modPackCount;
ImGui.ProgressBar(percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}"); Im.ProgressBar(percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}");
ImGui.NewLine(); Im.Line.New();
ImGui.TextUnformatted(State == ImporterState.DeduplicatingFiles Im.Text(State is ImporterState.DeduplicatingFiles
? $"Deduplicating {_currentModName}..." ? $"Deduplicating {_currentModName}..."
: $"Extracting {_currentModName}..."); : $"Extracting {_currentModName}...");
if (_currentNumOptions > 1) if (_currentNumOptions > 1)
{ {
ImGui.NewLine(); Im.Line.New();
ImGui.NewLine(); Im.Line.New();
if (_currentOptionIdx >= _currentNumOptions) if (_currentOptionIdx >= _currentNumOptions)
ImGui.ProgressBar(1f, size, $"Extracted {_currentNumOptions} Options"); Im.ProgressBar(1f, size, $"Extracted {_currentNumOptions} Options");
else else
ImGui.ProgressBar(_currentOptionIdx / (float)_currentNumOptions, size, Im.ProgressBar(_currentOptionIdx / (float)_currentNumOptions, size,
$"Extracting Option {_currentOptionIdx + 1} / {_currentNumOptions}..."); $"Extracting Option {_currentOptionIdx + 1} / {_currentNumOptions}...");
ImGui.NewLine(); Im.Line.New();
if (State != ImporterState.DeduplicatingFiles) if (State is not ImporterState.DeduplicatingFiles)
ImGui.TextUnformatted( Im.Text(
$"Extracting Option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}..."); $"Extracting Option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}...");
} }
ImGui.NewLine(); Im.Line.New();
ImGui.NewLine(); Im.Line.New();
if (_currentFileIdx >= _currentNumFiles) if (_currentFileIdx >= _currentNumFiles)
ImGui.ProgressBar(1f, size, $"Extracted {_currentNumFiles} Files"); Im.ProgressBar(1f, size, $"Extracted {_currentNumFiles} Files");
else else
ImGui.ProgressBar(_currentFileIdx / (float)_currentNumFiles, size, $"Extracting File {_currentFileIdx + 1} / {_currentNumFiles}..."); Im.ProgressBar(_currentFileIdx / (float)_currentNumFiles, size, $"Extracting File {_currentFileIdx + 1} / {_currentNumFiles}...");
ImGui.NewLine(); Im.Line.New();
if (State != ImporterState.DeduplicatingFiles) if (State is not ImporterState.DeduplicatingFiles)
ImGui.TextUnformatted($"Extracting File {_currentFileName}..."); Im.Text($"Extracting File {_currentFileName}...");
return false; return false;
} }
@ -77,31 +74,33 @@ public partial class TexToolsImporter
{ {
var success = ExtractedMods.Count(t => t.Error == null); var success = ExtractedMods.Count(t => t.Error == null);
ImGui.TextUnformatted($"Successfully extracted {success} / {ExtractedMods.Count} files."); Im.Text($"Successfully extracted {success} / {ExtractedMods.Count} files.");
ImGui.NewLine(); Im.Line.New();
using var table = ImRaii.Table("##files", 2); using var table = Im.Table.Begin("##files"u8, 2);
if (!table) if (!table)
return; return;
foreach (var (file, dir, ex) in ExtractedMods) foreach (var (file, dir, ex) in ExtractedMods)
{ {
ImGui.TableNextColumn(); table.DrawColumn(file.Name);
ImGui.TextUnformatted(file.Name); table.NextColumn();
ImGui.TableNextColumn(); if (ex is null)
if (ex == null)
{ {
using var color = ImGuiColor.Text.Push(ColorId.FolderExpanded.Value()); using var color = ImGuiColor.Text.Push(ColorId.FolderExpanded.Value());
ImGui.TextUnformatted(dir?.FullName[(_baseDirectory.FullName.Length + 1)..] ?? "Unknown Directory"); if (dir is null)
Im.Text("Unknown Directory"u8);
else
Im.Text(dir.FullName.AsSpan(_baseDirectory.FullName.Length + 1));
} }
else else
{ {
using var color = ImGuiColor.Text.Push(ColorId.ConflictingMod.Value()); using var color = ImGuiColor.Text.Push(ColorId.ConflictingMod.Value());
ImGui.TextUnformatted(ex.Message); Im.Text(ex.Message);
ImGuiUtil.HoverTooltip(ex.ToString()); Im.Tooltip.OnHover($"{ex}");
} }
} }
} }
public bool DrawCancelButton(Vector2 size) public bool DrawCancelButton(Vector2 size)
=> ImGuiUtil.DrawDisabledButton("Cancel", size, string.Empty, _token.IsCancellationRequested); => ImEx.Button("Cancel"u8, size, StringU8.Empty, _token.IsCancellationRequested);
} }

View file

@ -1,5 +1,4 @@
using ImSharp; using ImSharp;
using OtterGui.Text;
using Rgba32 = SixLabors.ImageSharp.PixelFormats.Rgba32; using Rgba32 = SixLabors.ImageSharp.PixelFormats.Rgba32;
namespace Penumbra.Import.Textures; namespace Penumbra.Import.Textures;

View file

@ -3,8 +3,7 @@ using Dalamud.Interface.Textures;
using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Textures.TextureWraps;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Lumina.Data.Files; using Lumina.Data.Files;
using OtterGui.Log; using Luna;
using OtterGui.Tasks;
using OtterTex; using OtterTex;
using SharpDX.Direct3D11; using SharpDX.Direct3D11;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
@ -17,7 +16,7 @@ using Image = SixLabors.ImageSharp.Image;
namespace Penumbra.Import.Textures; namespace Penumbra.Import.Textures;
public sealed class TextureManager(IDataManager gameData, Logger logger, ITextureProvider textureProvider, IUiBuilder uiBuilder) public sealed class TextureManager(IDataManager gameData, Logger logger, ITextureProvider textureProvider, IUiBuilder uiBuilder)
: SingleTaskQueue, IDisposable, Luna.IService : SingleTaskQueue, IDisposable, IService
{ {
private readonly Logger _logger = logger; private readonly Logger _logger = logger;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.CrashHandler.Buffers; using Penumbra.CrashHandler.Buffers;
using Penumbra.GameData; using Penumbra.GameData;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.CrashHandler.Buffers; using Penumbra.CrashHandler.Buffers;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource; using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
using JetBrains.Annotations; using JetBrains.Annotations;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using Penumbra.String; using Penumbra.String;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource; using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Resource;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.Services; using Penumbra.Interop.Services;
using Penumbra.String; using Penumbra.String;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using OtterGui.Services; using Luna;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.CrashHandler.Buffers; using Penumbra.CrashHandler.Buffers;
using Penumbra.GameData; using Penumbra.GameData;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using OtterGui.Services; using Luna;
using Penumbra.CrashHandler.Buffers; using Penumbra.CrashHandler.Buffers;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
using Penumbra.Services; using Penumbra.Services;

View file

@ -1,8 +1,7 @@
using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Base; using FFXIVClientStructs.FFXIV.Client.System.Scheduler.Base;
using OtterGui.Services; using Luna;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Interop; using Penumbra.GameData.Interop;

View file

@ -1,4 +1,4 @@
using OtterGui.Services; using Luna;
using Penumbra.CrashHandler.Buffers; using Penumbra.CrashHandler.Buffers;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Interop; using Penumbra.GameData.Interop;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using OtterGui.Services; using Luna;
using Penumbra.CrashHandler.Buffers; using Penumbra.CrashHandler.Buffers;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,4 +1,4 @@
using OtterGui.Services; using Luna;
using Penumbra.CrashHandler.Buffers; using Penumbra.CrashHandler.Buffers;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Interop; using Penumbra.GameData.Interop;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Interop; using Penumbra.GameData.Interop;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
@ -20,7 +20,7 @@ public unsafe class AtchCallerHook1 : FastHook<AtchCallerHook1.Delegate>, IDispo
Task = hooks.CreateHook<Delegate>("AtchCaller1", Sigs.AtchCaller1, Detour, Task = hooks.CreateHook<Delegate>("AtchCaller1", Sigs.AtchCaller1, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.AtchCaller1); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.AtchCaller1);
if (!HookOverrides.Instance.Meta.AtchCaller1) if (!HookOverrides.Instance.Meta.AtchCaller1)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private void Detour(DrawObjectData* data, uint slot, nint unk, Model playerModel) private void Detour(DrawObjectData* data, uint slot, nint unk, Model playerModel)
@ -34,5 +34,5 @@ public unsafe class AtchCallerHook1 : FastHook<AtchCallerHook1.Delegate>, IDispo
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Interop; using Penumbra.GameData.Interop;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
@ -20,7 +20,7 @@ public unsafe class AtchCallerHook2 : FastHook<AtchCallerHook2.Delegate>, IDispo
Task = hooks.CreateHook<Delegate>("AtchCaller2", Sigs.AtchCaller2, Detour, Task = hooks.CreateHook<Delegate>("AtchCaller2", Sigs.AtchCaller2, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.AtchCaller2); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.AtchCaller2);
if (!HookOverrides.Instance.Meta.AtchCaller2) if (!HookOverrides.Instance.Meta.AtchCaller2)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private void Detour(DrawObjectData* data, uint slot, nint unk, Model playerModel, uint unk2) private void Detour(DrawObjectData* data, uint slot, nint unk, Model playerModel, uint unk2)
@ -34,5 +34,5 @@ public unsafe class AtchCallerHook2 : FastHook<AtchCallerHook2.Delegate>, IDispo
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using OtterGui.Services; using Luna;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
namespace Penumbra.Interop.Hooks.Meta; namespace Penumbra.Interop.Hooks.Meta;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
@ -19,7 +19,7 @@ public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>, ID
Task = hooks.CreateHook<Delegate>("GetEqdpAccessoryEntry", Sigs.GetEqdpAccessoryEntry, Detour, Task = hooks.CreateHook<Delegate>("GetEqdpAccessoryEntry", Sigs.GetEqdpAccessoryEntry, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqdpAccessoryHook); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqdpAccessoryHook);
if (!HookOverrides.Instance.Meta.EqdpAccessoryHook) if (!HookOverrides.Instance.Meta.EqdpAccessoryHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode) private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode)
@ -33,5 +33,5 @@ public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>, ID
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
@ -18,7 +18,7 @@ public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>, IDisposabl
_metaState = metaState; _metaState = metaState;
Task = hooks.CreateHook<Delegate>("GetEqdpEquipEntry", Sigs.GetEqdpEquipEntry, Detour, metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqdpEquipHook); Task = hooks.CreateHook<Delegate>("GetEqdpEquipEntry", Sigs.GetEqdpEquipEntry, Detour, metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqdpEquipHook);
if (!HookOverrides.Instance.Meta.EqdpEquipHook) if (!HookOverrides.Instance.Meta.EqdpEquipHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode) private void Detour(CharacterUtility* utility, EqdpEntry* entry, uint setId, uint raceCode)
@ -32,5 +32,5 @@ public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>, IDisposabl
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
@ -18,7 +18,7 @@ public unsafe class EqpHook : FastHook<EqpHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetEqpFlags", Sigs.GetEqpEntry, Detour, Task = hooks.CreateHook<Delegate>("GetEqpFlags", Sigs.GetEqpEntry, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqpHook); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EqpHook);
if (!HookOverrides.Instance.Meta.EqpHook) if (!HookOverrides.Instance.Meta.EqpHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private void Detour(CharacterUtility* utility, EqpEntry* flags, CharacterArmor* armor) private void Detour(CharacterUtility* utility, EqpEntry* flags, CharacterArmor* armor)
@ -37,5 +37,5 @@ public unsafe class EqpHook : FastHook<EqpHook.Delegate>, IDisposable
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,4 +1,4 @@
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
@ -23,7 +23,7 @@ public unsafe class EstHook : FastHook<EstHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("FindEstEntry", Sigs.FindEstEntry, Detour, Task = hooks.CreateHook<Delegate>("FindEstEntry", Sigs.FindEstEntry, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EstHook); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.EstHook);
if (!HookOverrides.Instance.Meta.EstHook) if (!HookOverrides.Instance.Meta.EstHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private EstEntry Detour(ResourceHandle* estResource, uint genderRace, uint id) private EstEntry Detour(ResourceHandle* estResource, uint genderRace, uint id)
@ -59,5 +59,5 @@ public unsafe class EstHook : FastHook<EstHook.Delegate>, IDisposable
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,9 +1,7 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Lumina.Data.Parsing.Uld; using Luna;
using OtterGui.Services;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
namespace Penumbra.Interop.Hooks.Meta; namespace Penumbra.Interop.Hooks.Meta;
@ -20,7 +18,7 @@ public unsafe class GmpHook : FastHook<GmpHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetGmpEntry", Sigs.GetGmpEntry, Detour, Task = hooks.CreateHook<Delegate>("GetGmpEntry", Sigs.GetGmpEntry, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.GmpHook); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.GmpHook);
if (!HookOverrides.Instance.Meta.GmpHook) if (!HookOverrides.Instance.Meta.GmpHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private ulong Detour(CharacterUtility* characterUtility, ulong* outputEntry, ushort setId) private ulong Detour(CharacterUtility* characterUtility, ulong* outputEntry, ushort setId)
@ -39,5 +37,5 @@ public unsafe class GmpHook : FastHook<GmpHook.Delegate>, IDisposable
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
namespace Penumbra.Interop.Hooks.Meta; namespace Penumbra.Interop.Hooks.Meta;

View file

@ -1,4 +1,4 @@
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
@ -22,7 +22,7 @@ public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetRspBust", Sigs.GetRspBust, Detour, Task = hooks.CreateHook<Delegate>("GetRspBust", Sigs.GetRspBust, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspBustHook); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspBustHook);
if (!HookOverrides.Instance.Meta.RspBustHook) if (!HookOverrides.Instance.Meta.RspBustHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private float* Detour(nint cmpResource, float* storage, SubRace clan, byte gender, byte bodyType, byte bustSize) private float* Detour(nint cmpResource, float* storage, SubRace clan, byte gender, byte bodyType, byte bustSize)
@ -69,5 +69,5 @@ public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>, IDisposable
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,4 +1,4 @@
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
@ -22,7 +22,7 @@ public class RspHeightHook : FastHook<RspHeightHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetRspHeight", Sigs.GetRspHeight, Detour, Task = hooks.CreateHook<Delegate>("GetRspHeight", Sigs.GetRspHeight, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspHeightHook); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspHeightHook);
if (!HookOverrides.Instance.Meta.RspHeightHook) if (!HookOverrides.Instance.Meta.RspHeightHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private unsafe float Detour(nint cmpResource, SubRace clan, byte gender, byte bodyType, byte height) private unsafe float Detour(nint cmpResource, SubRace clan, byte gender, byte bodyType, byte height)
@ -79,5 +79,5 @@ public class RspHeightHook : FastHook<RspHeightHook.Delegate>, IDisposable
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,6 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.Collections;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,4 +1,4 @@
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
@ -22,7 +22,7 @@ public class RspTailHook : FastHook<RspTailHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetRspTail", Sigs.GetRspTail, Detour, Task = hooks.CreateHook<Delegate>("GetRspTail", Sigs.GetRspTail, Detour,
metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspTailHook); metaState.Config.EnableMods && !HookOverrides.Instance.Meta.RspTailHook);
if (!HookOverrides.Instance.Meta.RspTailHook) if (!HookOverrides.Instance.Meta.RspTailHook)
_metaState.Config.ModsEnabled += Toggle; _metaState.Config.ModsEnabled += Set;
} }
private unsafe float Detour(nint cmpResource, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte tailLength) private unsafe float Detour(nint cmpResource, Race race, byte gender, byte isSecondSubRace, byte bodyType, byte tailLength)
@ -73,5 +73,5 @@ public class RspTailHook : FastHook<RspTailHook.Delegate>, IDisposable
} }
public void Dispose() public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle; => _metaState.Config.ModsEnabled -= Set;
} }

View file

@ -1,6 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.Collections;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,6 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.Collections;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
namespace Penumbra.Interop.Hooks.Meta; namespace Penumbra.Interop.Hooks.Meta;

View file

@ -1,6 +1,6 @@
using Dalamud.Hooking; using Dalamud.Hooking;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
namespace Penumbra.Interop.Hooks.Objects; namespace Penumbra.Interop.Hooks.Objects;
@ -9,7 +9,7 @@ namespace Penumbra.Interop.Hooks.Objects;
/// EnableDraw is what creates DrawObjects for gameObjects, /// EnableDraw is what creates DrawObjects for gameObjects,
/// so we always keep track of the current GameObject to be able to link it to the DrawObject. /// so we always keep track of the current GameObject to be able to link it to the DrawObject.
/// </summary> /// </summary>
public sealed unsafe class EnableDraw : Luna.IHookService public sealed unsafe class EnableDraw : IHookService
{ {
private readonly Task<Hook<Delegate>> _task; private readonly Task<Hook<Delegate>> _task;
private readonly GameState _state; private readonly GameState _state;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
namespace Penumbra.Interop.Hooks.Objects; namespace Penumbra.Interop.Hooks.Objects;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services; using Luna;
namespace Penumbra.Interop.Hooks.PostProcessing; namespace Penumbra.Interop.Hooks.PostProcessing;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle; using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
namespace Penumbra.Interop.Hooks.Resources; namespace Penumbra.Interop.Hooks.Resources;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle; using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using OtterGui.Services; using Luna;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Services; using Penumbra.Services;

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle; using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using OtterGui.Services; using Luna;
using Penumbra.GameData; using Penumbra.GameData;
namespace Penumbra.Interop.Hooks.Resources; namespace Penumbra.Interop.Hooks.Resources;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle; using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using OtterGui.Text.HelperObjects; using Luna;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;

View file

@ -3,7 +3,6 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle; using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using FFXIVClientStructs.Interop; using FFXIVClientStructs.Interop;
using Luna; using Luna;
using OtterGui.Text.HelperObjects;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
@ -17,6 +16,7 @@ using Penumbra.String.Classes;
using Penumbra.UI; using Penumbra.UI;
using static Penumbra.Interop.Structs.StructExtensions; using static Penumbra.Interop.Structs.StructExtensions;
using CharaBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase; using CharaBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase;
using SpanTextWriter = Luna.SpanTextWriter;
namespace Penumbra.Interop.ResourceTree; namespace Penumbra.Interop.ResourceTree;

View file

@ -1,4 +1,3 @@
using OtterGui.Tasks;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
namespace Penumbra.Mods.Editor; namespace Penumbra.Mods.Editor;
@ -77,7 +76,7 @@ public class ModBackup
return; return;
CreatingBackup = true; CreatingBackup = true;
await AsyncTask.Run(Create); await Task.Run(Create);
CreatingBackup = false; CreatingBackup = false;
} }

View file

@ -59,9 +59,6 @@ public class ModMerger : IDisposable, IService
_communicator.ModPathChanged.Unsubscribe(OnModPathChange); _communicator.ModPathChanged.Unsubscribe(OnModPathChange);
} }
public IEnumerable<Mod> ModsWithoutCurrent
=> _mods.Where(m => m != MergeFromMod);
public bool CanMerge public bool CanMerge
=> MergeToMod != null && MergeToMod != MergeFromMod; => MergeToMod != null && MergeToMod != MergeFromMod;

View file

@ -1,6 +1,5 @@
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Luna; using Luna;
using OtterGui.Tasks;
using Penumbra.Mods.Groups; using Penumbra.Mods.Groups;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.SubMods; using Penumbra.Mods.SubMods;
@ -9,7 +8,7 @@ using Penumbra.String.Classes;
namespace Penumbra.Mods.Editor; namespace Penumbra.Mods.Editor;
public class ModNormalizer(ModManager modManager, Configuration config, SaveService saveService) : Luna.IService public class ModNormalizer(ModManager modManager, Configuration config, SaveService saveService) : IService
{ {
private readonly List<List<Dictionary<Utf8GamePath, FullPath>>> _redirections = []; private readonly List<List<Dictionary<Utf8GamePath, FullPath>>> _redirections = [];
@ -36,7 +35,7 @@ public class ModNormalizer(ModManager modManager, Configuration config, SaveServ
Step = 0; Step = 0;
TotalSteps = mod.TotalFileCount + 5; TotalSteps = mod.TotalFileCount + 5;
Worker = TrackedTask.Run(NormalizeSync); Worker = Task.Run(NormalizeSync);
} }
public void NormalizeUi(DirectoryInfo modDirectory) public void NormalizeUi(DirectoryInfo modDirectory)

View file

@ -1,9 +1,5 @@
using System.Collections.Frozen; using System.Collections.Frozen;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.Utility.Raii;
using ImSharp; using ImSharp;
using OtterGui.Text;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using Notification = Luna.Notification; using Notification = Luna.Notification;
@ -37,9 +33,8 @@ public static class FeatureChecker
if (missingFeatures.Count > 0) if (missingFeatures.Count > 0)
{ {
Penumbra.Messager.AddMessage(new Notification( Penumbra.Messager.AddMessage(new Notification($"Please update Penumbra to use the mod {modName}{(modDirectory != modName ? $" at {modDirectory}" : string.Empty)}!\n\n"
$"Please update Penumbra to use the mod {modName}{(modDirectory != modName ? $" at {modDirectory}" : string.Empty)}!\n\nLoading failed because it requires the unsupported feature{(missingFeatures.Count > 1 ? $"s\n\n\t[{string.Join("], [", missingFeatures)}]." : $" [{missingFeatures.First()}].")}", + $"Loading failed because it requires the unsupported feature{(missingFeatures.Count > 1 ? $"s\n\n\t[{string.Join("], [", missingFeatures)}]." : $" [{missingFeatures.First()}].")}"));
NotificationType.Warning));
return FeatureFlags.Invalid; return FeatureFlags.Invalid;
} }
@ -52,20 +47,20 @@ public static class FeatureChecker
public static void DrawFeatureFlagInput(ModDataEditor editor, Mod mod, float width) public static void DrawFeatureFlagInput(ModDataEditor editor, Mod mod, float width)
{ {
const int numButtons = 5; const int numButtons = 5;
var innerSpacing = ImGui.GetStyle().ItemInnerSpacing; var innerSpacing = Im.Style.ItemInnerSpacing;
var size = new Vector2((width - (numButtons - 1) * innerSpacing.X) / numButtons, 0); var size = new Vector2((width - (numButtons - 1) * innerSpacing.X) / numButtons, 0);
var buttonColor = Im.Style[ImGuiColor.FrameBackground]; var buttonColor = Im.Style[ImGuiColor.FrameBackground];
var textColor = Im.Style[ImGuiColor.TextDisabled]; var textColor = Im.Style[ImGuiColor.TextDisabled];
using (var style = ImStyleBorder.Frame.Push(ColorId.FolderLine.Value(), 0) using (var style = ImStyleBorder.Frame.Push(ColorId.FolderLine.Value(), 0)
.Push(ImStyleDouble.ItemSpacing, innerSpacing) .Push(ImStyleDouble.ItemSpacing, innerSpacing)
.Push(ImGuiColor.Button, buttonColor) .Push(ImGuiColor.Button, buttonColor)
.Push(ImGuiColor.Text, textColor)) .Push(ImGuiColor.Text, textColor))
{ {
foreach (var flag in SupportedFlags.Values) foreach (var flag in SupportedFlags.Values)
{ {
if (mod.RequiredFeatures.HasFlag(flag)) if (mod.RequiredFeatures.HasFlag(flag))
{ {
style.Push(ImStyleSingle.FrameBorderThickness, ImUtf8.GlobalScale); style.Push(ImStyleSingle.FrameBorderThickness, Im.Style.GlobalScale);
style.PopColor(2); style.PopColor(2);
if (Im.Button($"{flag}", size)) if (Im.Button($"{flag}", size))
editor.ChangeRequiredFeatures(mod, mod.RequiredFeatures & ~flag); editor.ChangeRequiredFeatures(mod, mod.RequiredFeatures & ~flag);
@ -82,14 +77,14 @@ public static class FeatureChecker
} }
} }
if (ImUtf8.ButtonEx("Compute"u8, "Compute the required features automatically from the used features."u8, size)) if (ImEx.Button("Compute"u8, size, "Compute the required features automatically from the used features."u8))
editor.ChangeRequiredFeatures(mod, mod.ComputeRequiredFeatures()); editor.ChangeRequiredFeatures(mod, mod.ComputeRequiredFeatures());
Im.Line.Same(); Im.Line.Same();
if (ImUtf8.ButtonEx("Clear"u8, "Clear all required features."u8, size)) if (ImEx.Button("Clear"u8, size, "Clear all required features."u8))
editor.ChangeRequiredFeatures(mod, FeatureFlags.None); editor.ChangeRequiredFeatures(mod, FeatureFlags.None);
Im.Line.Same(); Im.Line.Same();
ImUtf8.Text("Required Features"u8); Im.Text("Required Features"u8);
} }
} }

View file

@ -0,0 +1,25 @@
using ImSharp;
using Luna;
using Penumbra.Mods.Editor;
namespace Penumbra.Mods.Manager;
public class ModCombo(ModStorage modStorage) : SimpleFilterCombo<Mod>(SimpleFilterType.Regex), IUiService
{
protected readonly ModStorage ModStorage = modStorage;
public override StringU8 DisplayString(in Mod value)
=> new(value.Name);
public override string FilterString(in Mod value)
=> value.Name;
public override IEnumerable<Mod> GetBaseItems()
=> ModStorage;
}
public sealed class ModComboWithoutCurrent(ModStorage modStorage, ModMerger modMerger) : ModCombo(modStorage)
{
public override IEnumerable<Mod> GetBaseItems()
=> ModStorage.Where(m => m != modMerger.MergeFromMod);
}

View file

@ -1,3 +1,4 @@
using Luna;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Interop; using Penumbra.Interop;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
@ -228,7 +229,7 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
if (oldName == newName) if (oldName == newName)
return NewDirectoryState.Identical; return NewDirectoryState.Identical;
var fixedNewName = ModCreator.ReplaceBadXivSymbols(newName, _config.ReplaceNonAsciiOnImport); var fixedNewName = newName.ReplaceBadXivSymbols(_config.ReplaceNonAsciiOnImport);
if (fixedNewName != newName) if (fixedNewName != newName)
return NewDirectoryState.ContainsInvalidSymbols; return NewDirectoryState.ContainsInvalidSymbols;

View file

@ -1,17 +1,5 @@
using OtterGui.Classes;
using OtterGui.Widgets;
namespace Penumbra.Mods.Manager; namespace Penumbra.Mods.Manager;
public class ModCombo(Func<IReadOnlyList<Mod>> generator) : FilterComboCache<Mod>(generator, MouseWheelType.None, Penumbra.Log)
{
protected override bool IsVisible(int globalIndex, LowerString filter)
=> Items[globalIndex].Name.Contains(filter);
protected override string ToString(Mod obj)
=> obj.Name;
}
public class ModStorage : IReadOnlyList<Mod> public class ModStorage : IReadOnlyList<Mod>
{ {
/// <summary> The actual list of mods. </summary> /// <summary> The actual list of mods. </summary>

View file

@ -1,5 +1,4 @@
using Luna; using Luna;
using OtterGui.Filesystem;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
@ -137,7 +136,7 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
protected override bool MoveOption(ImcModGroup group, int optionIdxFrom, int optionIdxTo) protected override bool MoveOption(ImcModGroup group, int optionIdxFrom, int optionIdxTo)
{ {
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo)) if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
return false; return false;
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo); group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);

View file

@ -1,6 +1,5 @@
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Luna; using Luna;
using OtterGui.Filesystem;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
@ -40,7 +39,7 @@ public class ModGroupEditor(
CombiningModGroupEditor combiningEditor, CombiningModGroupEditor combiningEditor,
CommunicatorService communicator, CommunicatorService communicator,
SaveService saveService, SaveService saveService,
Configuration config) : Luna.IService Configuration config) : IService
{ {
public SingleModGroupEditor SingleEditor public SingleModGroupEditor SingleEditor
=> singleEditor; => singleEditor;

View file

@ -1,5 +1,4 @@
using Luna; using Luna;
using OtterGui.Filesystem;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Mods.Groups; using Penumbra.Mods.Groups;
using Penumbra.Mods.Settings; using Penumbra.Mods.Settings;
@ -9,7 +8,7 @@ using Penumbra.Services;
namespace Penumbra.Mods.Manager.OptionEditor; namespace Penumbra.Mods.Manager.OptionEditor;
public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveService saveService, Configuration config) public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveService saveService, Configuration config)
: ModOptionEditor<MultiModGroup, MultiSubMod>(communicator, saveService, config), Luna.IService : ModOptionEditor<MultiModGroup, MultiSubMod>(communicator, saveService, config), IService
{ {
public void ChangeToSingle(MultiModGroup group) public void ChangeToSingle(MultiModGroup group)
{ {
@ -75,7 +74,7 @@ public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveSe
protected override bool MoveOption(MultiModGroup group, int optionIdxFrom, int optionIdxTo) protected override bool MoveOption(MultiModGroup group, int optionIdxFrom, int optionIdxTo)
{ {
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo)) if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
return false; return false;
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo); group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);

View file

@ -1,5 +1,4 @@
using Luna; using Luna;
using OtterGui.Filesystem;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Mods.Groups; using Penumbra.Mods.Groups;
using Penumbra.Mods.Settings; using Penumbra.Mods.Settings;
@ -48,7 +47,7 @@ public sealed class SingleModGroupEditor(CommunicatorService communicator, SaveS
protected override bool MoveOption(SingleModGroup group, int optionIdxFrom, int optionIdxTo) protected override bool MoveOption(SingleModGroup group, int optionIdxFrom, int optionIdxTo)
{ {
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo)) if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
return false; return false;
group.DefaultSettings = group.DefaultSettings.MoveSingle(optionIdxFrom, optionIdxTo); group.DefaultSettings = group.DefaultSettings.MoveSingle(optionIdxFrom, optionIdxTo);

View file

@ -2,7 +2,6 @@ using Dalamud.Interface.ImGuiNotification;
using Luna; using Luna;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui.Filesystem;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.Import; using Penumbra.Import;
@ -29,7 +28,8 @@ public partial class ModCreator(
public readonly Configuration Config = config; public readonly Configuration Config = config;
/// <summary> Creates directory and files necessary for a new mod without adding it to the manager. </summary> /// <summary> Creates directory and files necessary for a new mod without adding it to the manager. </summary>
public DirectoryInfo? CreateEmptyMod(DirectoryInfo basePath, string newName, string description = "", string? author = null, params string[] tags) public DirectoryInfo? CreateEmptyMod(DirectoryInfo basePath, string newName, string description = "", string? author = null,
params string[] tags)
{ {
try try
{ {
@ -81,7 +81,7 @@ public partial class ModCreator(
if (incorporateMetaChanges) if (incorporateMetaChanges)
IncorporateAllMetaChanges(mod, true, deleteDefaultMetaChanges); IncorporateAllMetaChanges(mod, true, deleteDefaultMetaChanges);
else if (deleteDefaultMetaChanges) else if (deleteDefaultMetaChanges)
ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, saveService, false); ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, saveService);
return true; return true;
} }
@ -98,7 +98,7 @@ public partial class ModCreator(
{ {
changes = changes changes = changes
|| saveService.FileNames.OptionGroupFile(mod.ModPath.FullName, mod.Groups.Count, group.Name, true) || saveService.FileNames.OptionGroupFile(mod.ModPath.FullName, mod.Groups.Count, group.Name, true)
!= Path.Combine(file.DirectoryName!, ReplaceBadXivSymbols(file.Name, true)); != Path.Combine(file.DirectoryName!, file.Name.ReplaceBadXivSymbols(true));
mod.Groups.Add(group); mod.Groups.Add(group);
} }
else else
@ -167,7 +167,7 @@ public partial class ModCreator(
DeleteDeleteList(deleteList, delete); DeleteDeleteList(deleteList, delete);
if (removeDefaultValues && !Config.KeepDefaultMetaChanges) if (removeDefaultValues && !Config.KeepDefaultMetaChanges)
changes |= ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, null, false); changes |= ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, null);
if (!changes) if (!changes)
return; return;
@ -306,33 +306,10 @@ public partial class ModCreator(
/// <summary> Return the name of a new valid directory based on the base directory and the given name. </summary> /// <summary> Return the name of a new valid directory based on the base directory and the given name. </summary>
public static DirectoryInfo NewOptionDirectory(DirectoryInfo baseDir, string optionName, bool onlyAscii) public static DirectoryInfo NewOptionDirectory(DirectoryInfo baseDir, string optionName, bool onlyAscii)
{ {
var option = ReplaceBadXivSymbols(optionName, onlyAscii); var option = optionName.ReplaceBadXivSymbols(onlyAscii);
return new DirectoryInfo(Path.Combine(baseDir.FullName, option.Length > 0 ? option : "_")); return new DirectoryInfo(Path.Combine(baseDir.FullName, option.Length > 0 ? option : "_"));
} }
/// <summary> Normalize for nicer names, and remove invalid symbols or invalid paths. </summary>
public static string ReplaceBadXivSymbols(string s, bool onlyAscii, string replacement = "_")
{
switch (s)
{
case ".": return replacement;
case "..": return replacement + replacement;
}
StringBuilder sb = new(s.Length);
foreach (var c in s.Normalize(NormalizationForm.FormKC))
{
if (c.IsInvalidInPath())
sb.Append(replacement);
else if (onlyAscii && c.IsInvalidAscii())
sb.Append(replacement);
else
sb.Append(c);
}
return sb.ToString().Trim();
}
public void SplitMultiGroups(DirectoryInfo baseDir) public void SplitMultiGroups(DirectoryInfo baseDir)
{ {
var mod = new Mod(baseDir); var mod = new Mod(baseDir);

View file

@ -1,4 +1,4 @@
using OtterGui.Filesystem; using Luna;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Mods.Groups; using Penumbra.Mods.Groups;

View file

@ -1,5 +1,5 @@
using Luna;
using Newtonsoft.Json; using Newtonsoft.Json;
using OtterGui;
namespace Penumbra.Mods.Settings; namespace Penumbra.Mods.Settings;
@ -27,10 +27,10 @@ public readonly record struct Setting(ulong Value)
=> idx >= 0 && (Value & (1ul << idx)) != 0; => idx >= 0 && (Value & (1ul << idx)) != 0;
public Setting MoveBit(int idx1, int idx2) public Setting MoveBit(int idx1, int idx2)
=> new(Functions.MoveBit(Value, idx1, idx2)); => new(BitFunctions.MoveBit(Value, idx1, idx2));
public Setting RemoveBit(int idx) public Setting RemoveBit(int idx)
=> new(Functions.RemoveBit(Value, idx)); => new(BitFunctions.RemoveBit(Value, idx));
public Setting SetBit(int idx, bool value) public Setting SetBit(int idx, bool value)
=> new(value ? Value | (1ul << idx) : Value & ~(1ul << idx)); => new(value ? Value | (1ul << idx) : Value & ~(1ul << idx));

View file

@ -17,13 +17,11 @@ using Penumbra.Interop.Hooks;
using Penumbra.Interop.Hooks.PostProcessing; using Penumbra.Interop.Hooks.PostProcessing;
using Penumbra.Interop.PathResolving; using Penumbra.Interop.PathResolving;
using Penumbra.Interop.Services; using Penumbra.Interop.Services;
using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI; using Penumbra.UI;
using Penumbra.UI.AdvancedWindow; using Penumbra.UI.AdvancedWindow;
using Penumbra.UI.Tabs; using Penumbra.UI.Tabs;
using static System.Collections.Specialized.BitVector32;
using ChangedItemClick = Penumbra.Communication.ChangedItemClick; using ChangedItemClick = Penumbra.Communication.ChangedItemClick;
using ChangedItemHover = Penumbra.Communication.ChangedItemHover; using ChangedItemHover = Penumbra.Communication.ChangedItemHover;
using DynamisIpc = OtterGui.Services.DynamisIpc; using DynamisIpc = OtterGui.Services.DynamisIpc;

View file

@ -1,9 +1,10 @@
using Luna; using ImSharp;
using Luna;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
namespace Penumbra.Services; namespace Penumbra.Services;
public class FileWatcher : IDisposable, IService public sealed class FileWatcher : IDisposable, IService
{ {
private readonly ConcurrentSet<string> _pending = new(StringComparer.OrdinalIgnoreCase); private readonly ConcurrentSet<string> _pending = new(StringComparer.OrdinalIgnoreCase);
private readonly ModImportManager _modImportManager; private readonly ModImportManager _modImportManager;
@ -47,9 +48,6 @@ public class FileWatcher : IDisposable, IService
} }
} }
internal void PauseConsumer(bool pause)
=> _pausedConsumer = pause;
private void EndFileWatcher() private void EndFileWatcher()
{ {
if (_fsw is null) if (_fsw is null)
@ -206,4 +204,47 @@ public class FileWatcher : IDisposable, IService
EndConsumerTask(); EndConsumerTask();
EndFileWatcher(); EndFileWatcher();
} }
public sealed class FileWatcherDrawer(Configuration config, FileWatcher fileWatcher) : IUiService
{
public void Draw()
{
using var tree = Im.Tree.Node("File Watcher"u8);
if (!tree)
return;
using var table = Im.Table.Begin("table"u8, 2);
if (!table)
return;
table.DrawColumn("Enabled"u8);
table.DrawColumn($"{config.EnableDirectoryWatch}");
table.DrawColumn("Automatic Import"u8);
table.DrawColumn($"{config.EnableAutomaticModImport}");
table.DrawColumn("Watched Directory"u8);
table.DrawColumn(config.WatchDirectory);
table.DrawColumn("File Watcher Path"u8);
table.DrawColumn(fileWatcher._fsw?.Path ?? "<NULL>");
table.DrawColumn("Raising Events"u8);
table.DrawColumn($"{fileWatcher._fsw?.EnableRaisingEvents ?? false}");
table.DrawColumn("File Filters"u8);
table.DrawColumn(StringU8.Join(", ", fileWatcher._fsw?.Filters ?? []));
table.DrawColumn("Consumer Task State"u8);
table.DrawColumn($"{fileWatcher._consumer?.Status.ToString() ?? "<NULL>"}");
table.DrawColumn("Debug Pause Consumer"u8);
table.NextColumn();
if (Im.SmallButton(fileWatcher._pausedConsumer ? "Unpause"u8 : "Pause"u8))
fileWatcher._pausedConsumer = !fileWatcher._pausedConsumer;
table.DrawColumn("Pending Files"u8);
table.DrawColumn(StringU8.Join('\n', fileWatcher._pending));
}
}
} }

View file

@ -64,15 +64,15 @@ public sealed class FilenameService(IDalamudPluginInterface pi) : BaseFilePathPr
public string ModMetaPath(string modDirectory) public string ModMetaPath(string modDirectory)
=> Path.Combine(modDirectory, "meta.json"); => Path.Combine(modDirectory, "meta.json");
/// <summary> Obtain the path of the file describing a given option group by its index and the mod. If the index is < 0, return the path for the default mod file. </summary> /// <summary> Obtain the path of the file describing a given option group by its index and the mod. If the index is less than 0, return the path for the default mod file. </summary>
public string OptionGroupFile(Mod mod, int index, bool onlyAscii) public string OptionGroupFile(Mod mod, int index, bool onlyAscii)
=> OptionGroupFile(mod.ModPath.FullName, index, index >= 0 ? mod.Groups[index].Name : string.Empty, onlyAscii); => OptionGroupFile(mod.ModPath.FullName, index, index >= 0 ? mod.Groups[index].Name : string.Empty, onlyAscii);
/// <summary> Obtain the path of the file describing a given option group by its index, name and basepath. If the index is < 0, return the path for the default mod file. </summary> /// <summary> Obtain the path of the file describing a given option group by its index, name and basepath. If the index is less than 0, return the path for the default mod file. </summary>
public string OptionGroupFile(string basePath, int index, string name, bool onlyAscii) public string OptionGroupFile(string basePath, int index, string name, bool onlyAscii)
{ {
var fileName = index >= 0 var fileName = index >= 0
? $"group_{index + 1:D3}_{ModCreator.ReplaceBadXivSymbols(name.ToLowerInvariant(), onlyAscii)}.json" ? $"group_{index + 1:D3}_{name.ToLowerInvariant().ReplaceBadXivSymbols(onlyAscii)}.json"
: "default_mod.json"; : "default_mod.json";
return Path.Combine(basePath, fileName); return Path.Combine(basePath, fileName);
} }

View file

@ -1,91 +0,0 @@
using OtterGui.Tasks;
namespace Penumbra.Services;
public abstract class SyncServiceWrapper<T> : IDisposable
{
public string Name { get; }
public T Service { get; }
private bool _isDisposed;
public bool Valid
=> !_isDisposed;
protected SyncServiceWrapper(string name, Func<T> factory)
{
Name = name;
Service = factory();
Penumbra.Log.Verbose($"[{Name}] Created.");
}
public void Dispose()
{
if (_isDisposed)
return;
_isDisposed = true;
if (Service is IDisposable d)
d.Dispose();
Penumbra.Log.Verbose($"[{Name}] Disposed.");
}
}
public abstract class AsyncServiceWrapper<T> : IDisposable
{
public string Name { get; }
public T? Service { get; private set; }
public T AwaitedService
{
get
{
_task?.Wait();
return Service!;
}
}
public bool Valid
=> Service != null && !_isDisposed;
public event Action? FinishedCreation;
private Task? _task;
private bool _isDisposed;
protected AsyncServiceWrapper(string name, Func<T> factory)
{
Name = name;
_task = TrackedTask.Run(() =>
{
var service = factory();
if (_isDisposed)
{
if (service is IDisposable d)
d.Dispose();
}
else
{
Service = service;
Penumbra.Log.Verbose($"[{Name}] Created.");
_task = null;
}
});
_task.ContinueWith((t, x) =>
{
if (!_isDisposed)
FinishedCreation?.Invoke();
}, TaskScheduler.Default);
}
public void Dispose()
{
if (_isDisposed)
return;
_isDisposed = true;
_task = null;
if (Service is IDisposable d)
d.Dispose();
Penumbra.Log.Verbose($"[{Name}] Disposed.");
}
}

View file

@ -1,6 +1,4 @@
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using ImSharp; using ImSharp;
using OtterGui.Widgets; using OtterGui.Widgets;
@ -14,6 +12,55 @@ using MouseWheelType = OtterGui.Widgets.MouseWheelType;
namespace Penumbra.Services; namespace Penumbra.Services;
// TODO
//public sealed class StainTemplateCombo<TDyePack>(FilterComboColors[] stainCombos, StmFile<TDyePack> stmFile) : SimpleFilterCombo<StmKeyType>(SimpleFilterType.Text)
// where TDyePack : unmanaged, IDyePack
//{
// public override StringU8 DisplayString(in StmKeyType value)
// => new($"{value,4}");
//
// public override string FilterString(in StmKeyType value)
// => $"{value,4}";
//
// public override IEnumerable<StmKeyType> GetBaseItems()
// => throw new NotImplementedException();
//
// protected override bool DrawFilter(float width, FilterComboBaseCache<SimpleCacheItem<StmKeyType>> cache)
// {
// using var font = Im.Font.PushDefault();
// return base.DrawFilter(width, cache);
// }
//
// public bool Draw(Utf8StringHandler<LabelStringHandlerBuffer> label, Utf8StringHandler<HintStringHandlerBuffer> preview, Utf8StringHandler<TextStringHandlerBuffer> tooltip, ref int currentSelection, float previewWidth, float itemHeight,
// ComboFlags flags = ComboFlags.None)
// {
// using var font = Im.Font.PushMono();
// using var style = ImStyleDouble.ButtonTextAlign.Push(new Vector2(1, 0.5f))
// .PushX(ImStyleDouble.ItemSpacing, Im.Style.ItemInnerSpacing.X);
// var spaceSize = Im.Font.Mono.GetCharacterAdvance(' ');
// var spaces = (int)(previewWidth / spaceSize) - 1;
// return base.Draw(label, preview.PadLeft(spaces), tooltip, ref currentSelection, previewWidth, itemHeight, flags);
// }
//
// protected override bool DrawSelectable(int globalIdx, bool selected)
// {
// var ret = base.DrawSelectable(globalIdx, selected);
// var selection = stainCombos[CurrentDyeChannel].CurrentSelection.Key;
// if (selection == 0 || !stmFile.TryGetValue(Items[globalIdx], selection, out var colors))
// return ret;
//
// Im.Line.Same();
//
// var frame = new Vector2(Im.Style.TextHeight);
// Im.Color.Button("D"u8, new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.DiffuseColor), 1), 0, frame);
// Im.Line.Same();
// Im.Color.Button("S"u8, new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.SpecularColor), 1), 0, frame);
// Im.Line.Same();
// Im.Color.Button("E"u8, new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.EmissiveColor), 1), 0, frame);
// return ret;
// }
//}
public class StainService : Luna.IService public class StainService : Luna.IService
{ {
public sealed class StainTemplateCombo<TDyePack>(FilterComboColors[] stainCombos, StmFile<TDyePack> stmFile) public sealed class StainTemplateCombo<TDyePack>(FilterComboColors[] stainCombos, StmFile<TDyePack> stmFile)
@ -25,11 +72,11 @@ public class StainService : Luna.IService
protected override float GetFilterWidth() protected override float GetFilterWidth()
{ {
var baseSize = ImGui.CalcTextSize("0000").X + ImGui.GetStyle().ScrollbarSize + ImGui.GetStyle().ItemInnerSpacing.X; var baseSize = Im.Font.CalculateSize("0000"u8).X + Im.Style.ScrollbarSize + Im.Style.ItemInnerSpacing.X;
if (stainCombos[CurrentDyeChannel].CurrentSelection.Key == 0) if (stainCombos[CurrentDyeChannel].CurrentSelection.Key == 0)
return baseSize; return baseSize;
return baseSize + ImGui.GetTextLineHeight() * 3 + ImGui.GetStyle().ItemInnerSpacing.X * 3; return baseSize + Im.Style.TextHeight * 3 + Im.Style.ItemInnerSpacing.X * 3;
} }
protected override string ToString(StmKeyType obj) protected override string ToString(StmKeyType obj)
@ -37,17 +84,17 @@ public class StainService : Luna.IService
protected override void DrawFilter(int currentSelected, float width) protected override void DrawFilter(int currentSelected, float width)
{ {
using var font = ImRaii.PushFont(UiBuilder.DefaultFont); using var font = Im.Font.PushDefault();
base.DrawFilter(currentSelected, width); base.DrawFilter(currentSelected, width);
} }
public override bool Draw(string label, string preview, string tooltip, ref int currentSelection, float previewWidth, float itemHeight, public override bool Draw(string label, string preview, string tooltip, ref int currentSelection, float previewWidth, float itemHeight,
ImGuiComboFlags flags = ImGuiComboFlags.None) ImGuiComboFlags flags = ImGuiComboFlags.None)
{ {
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = Im.Font.PushMono();
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(1, 0.5f)) using var style = ImStyleDouble.ButtonTextAlign.Push(new Vector2(1, 0.5f))
.Push(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemInnerSpacing.X }); .PushX(ImStyleDouble.ItemSpacing, Im.Style.ItemInnerSpacing.X);
var spaceSize = ImGui.CalcTextSize(" ").X; var spaceSize = Im.Font.Mono.GetCharacterAdvance(' ');
var spaces = (int)(previewWidth / spaceSize) - 1; var spaces = (int)(previewWidth / spaceSize) - 1;
return base.Draw(label, preview.PadLeft(spaces), tooltip, ref currentSelection, previewWidth, itemHeight, flags); return base.Draw(label, preview.PadLeft(spaces), tooltip, ref currentSelection, previewWidth, itemHeight, flags);
} }
@ -60,12 +107,13 @@ public class StainService : Luna.IService
return ret; return ret;
Im.Line.Same(); Im.Line.Same();
var frame = new Vector2(ImGui.GetTextLineHeight());
ImGui.ColorButton("D", new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.DiffuseColor), 1), 0, frame); var frame = new Vector2(Im.Style.TextHeight);
Im.Color.Button("D"u8, new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.DiffuseColor), 1), 0, frame);
Im.Line.Same(); Im.Line.Same();
ImGui.ColorButton("S", new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.SpecularColor), 1), 0, frame); Im.Color.Button("S"u8, new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.SpecularColor), 1), 0, frame);
Im.Line.Same(); Im.Line.Same();
ImGui.ColorButton("E", new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.EmissiveColor), 1), 0, frame); Im.Color.Button("E"u8, new Vector4(MtrlTab.PseudoSqrtRgb((Vector3)colors.EmissiveColor), 1), 0, frame);
return ret; return ret;
} }
} }

View file

@ -11,10 +11,9 @@ using Penumbra.UI.Classes;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;
public class ModMergeTab(ModMerger modMerger) : Luna.IUiService public class ModMergeTab(ModMerger modMerger, ModComboWithoutCurrent combo) : Luna.IUiService
{ {
private readonly ModCombo _modCombo = new(() => modMerger.ModsWithoutCurrent.ToList()); private string _newModName = string.Empty;
private string _newModName = string.Empty;
public void Draw() public void Draw()
{ {
@ -122,9 +121,9 @@ public class ModMergeTab(ModMerger modMerger) : Luna.IUiService
private void DrawCombo(float width) private void DrawCombo(float width)
{ {
_modCombo.Draw("##ModSelection", _modCombo.CurrentSelection?.Name ?? "Select the target Mod...", string.Empty, width, if (combo.Draw("##ModSelection"u8, modMerger.MergeToMod?.Name ?? "Select the target Mod...", StringU8.Empty, width,
ImGui.GetTextLineHeight()); out var cacheMod))
modMerger.MergeToMod = _modCombo.CurrentSelection; modMerger.MergeToMod = cacheMod.Item;
} }
private void DrawSplitOff(float size) private void DrawSplitOff(float size)

View file

@ -106,6 +106,7 @@ public class DebugTab : Window, ITab
private readonly RenderTargetDrawer _renderTargetDrawer; private readonly RenderTargetDrawer _renderTargetDrawer;
private readonly ModMigratorDebug _modMigratorDebug; private readonly ModMigratorDebug _modMigratorDebug;
private readonly ShapeInspector _shapeInspector; private readonly ShapeInspector _shapeInspector;
private readonly FileWatcher.FileWatcherDrawer _fileWatcherDrawer;
public DebugTab(Configuration config, CollectionManager collectionManager, ObjectManager objects, public DebugTab(Configuration config, CollectionManager collectionManager, ObjectManager objects,
IClientState clientState, IDataManager dataManager, IClientState clientState, IDataManager dataManager,
@ -117,7 +118,7 @@ public class DebugTab : Window, ITab
Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer, Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer,
HookOverrideDrawer hookOverrides, RsfService rsfService, GlobalVariablesDrawer globalVariablesDrawer, HookOverrideDrawer hookOverrides, RsfService rsfService, GlobalVariablesDrawer globalVariablesDrawer,
SchedulerResourceManagementService schedulerService, ObjectIdentification objectIdentification, RenderTargetDrawer renderTargetDrawer, SchedulerResourceManagementService schedulerService, ObjectIdentification objectIdentification, RenderTargetDrawer renderTargetDrawer,
ModMigratorDebug modMigratorDebug, ShapeInspector shapeInspector) ModMigratorDebug modMigratorDebug, ShapeInspector shapeInspector, FileWatcher.FileWatcherDrawer fileWatcherDrawer)
: base("Penumbra Debug Window", WindowFlags.NoCollapse) : base("Penumbra Debug Window", WindowFlags.NoCollapse)
{ {
IsOpen = true; IsOpen = true;
@ -160,6 +161,7 @@ public class DebugTab : Window, ITab
_renderTargetDrawer = renderTargetDrawer; _renderTargetDrawer = renderTargetDrawer;
_modMigratorDebug = modMigratorDebug; _modMigratorDebug = modMigratorDebug;
_shapeInspector = shapeInspector; _shapeInspector = shapeInspector;
_fileWatcherDrawer = fileWatcherDrawer;
_objects = objects; _objects = objects;
_clientState = clientState; _clientState = clientState;
_dataManager = dataManager; _dataManager = dataManager;
@ -486,6 +488,8 @@ public class DebugTab : Window, ITab
} }
} }
} }
_fileWatcherDrawer.Draw();
} }
private void DrawPerformanceTab() private void DrawPerformanceTab()