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 OtterGui.Text;
using ImSharp;
using Luna.Generators;
namespace Penumbra;
[NamedEnum(Unknown: "Error")]
[TooltipEnum]
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,
[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,
[Name("Alphabetical")]
[Tooltip("Display all changed items in a single list sorted alphabetically.")]
Alphabetical,
}
public static class ChangedItemModeExtensions
public static partial class ChangedItemModeExtensions
{
public static ReadOnlySpan<byte> ToName(this ChangedItemMode mode)
=> mode switch
{
ChangedItemMode.GroupedCollapsed => "Grouped (Collapsed)"u8,
ChangedItemMode.GroupedExpanded => "Grouped (Expanded)"u8,
ChangedItemMode.Alphabetical => "Alphabetical"u8,
_ => "Error"u8,
};
private static readonly ChangedItemModeCombo Combo = new();
public static ReadOnlySpan<byte> ToTooltip(this ChangedItemMode mode)
=> mode switch
private sealed class ChangedItemModeCombo() : SimpleFilterCombo<ChangedItemMode>(SimpleFilterType.Text)
{
ChangedItemMode.GroupedCollapsed =>
"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 =>
"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,
ChangedItemMode.Alphabetical => "Display all changed items in a single list sorted alphabetically."u8,
_ => ""u8,
};
public override StringU8 DisplayString(in ChangedItemMode value)
=> new(value.ToNameU8());
public override string FilterString(in ChangedItemMode value)
=> value.ToName();
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)
{
ImGui.SetNextItemWidth(width);
using var combo = ImUtf8.Combo(label, value.ToName());
if (!combo)
if (!Combo.Draw(label, ref value, StringU8.Empty, width))
return false;
var ret = false;
foreach (var newValue in Enum.GetValues<ChangedItemMode>())
{
var selected = ImUtf8.Selectable(newValue.ToName(), newValue == value);
if (selected)
{
ret = true;
setter(newValue);
}
ImUtf8.HoverTooltip(newValue.ToTooltip());
}
return ret;
setter(value);
return true;
}
}

View file

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

View file

@ -1,7 +1,4 @@
using Dalamud.Bindings.ImGui;
using ImSharp;
using OtterGui;
using OtterGui.Raii;
using Penumbra.Import.Structs;
using Penumbra.UI.Classes;
@ -23,9 +20,9 @@ public partial class TexToolsImporter
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;
}
@ -35,40 +32,40 @@ public partial class TexToolsImporter
return true;
}
ImGui.NewLine();
Im.Line.New();
var percentage = (float)_currentModPackIdx / _modPackCount;
ImGui.ProgressBar(percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}");
ImGui.NewLine();
ImGui.TextUnformatted(State == ImporterState.DeduplicatingFiles
Im.ProgressBar(percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}");
Im.Line.New();
Im.Text(State is ImporterState.DeduplicatingFiles
? $"Deduplicating {_currentModName}..."
: $"Extracting {_currentModName}...");
if (_currentNumOptions > 1)
{
ImGui.NewLine();
ImGui.NewLine();
Im.Line.New();
Im.Line.New();
if (_currentOptionIdx >= _currentNumOptions)
ImGui.ProgressBar(1f, size, $"Extracted {_currentNumOptions} Options");
Im.ProgressBar(1f, size, $"Extracted {_currentNumOptions} Options");
else
ImGui.ProgressBar(_currentOptionIdx / (float)_currentNumOptions, size,
Im.ProgressBar(_currentOptionIdx / (float)_currentNumOptions, size,
$"Extracting Option {_currentOptionIdx + 1} / {_currentNumOptions}...");
ImGui.NewLine();
if (State != ImporterState.DeduplicatingFiles)
ImGui.TextUnformatted(
Im.Line.New();
if (State is not ImporterState.DeduplicatingFiles)
Im.Text(
$"Extracting Option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}...");
}
ImGui.NewLine();
ImGui.NewLine();
Im.Line.New();
Im.Line.New();
if (_currentFileIdx >= _currentNumFiles)
ImGui.ProgressBar(1f, size, $"Extracted {_currentNumFiles} Files");
Im.ProgressBar(1f, size, $"Extracted {_currentNumFiles} Files");
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();
if (State != ImporterState.DeduplicatingFiles)
ImGui.TextUnformatted($"Extracting File {_currentFileName}...");
Im.Line.New();
if (State is not ImporterState.DeduplicatingFiles)
Im.Text($"Extracting File {_currentFileName}...");
return false;
}
@ -77,31 +74,33 @@ public partial class TexToolsImporter
{
var success = ExtractedMods.Count(t => t.Error == null);
ImGui.TextUnformatted($"Successfully extracted {success} / {ExtractedMods.Count} files.");
ImGui.NewLine();
using var table = ImRaii.Table("##files", 2);
Im.Text($"Successfully extracted {success} / {ExtractedMods.Count} files.");
Im.Line.New();
using var table = Im.Table.Begin("##files"u8, 2);
if (!table)
return;
foreach (var (file, dir, ex) in ExtractedMods)
{
ImGui.TableNextColumn();
ImGui.TextUnformatted(file.Name);
ImGui.TableNextColumn();
if (ex == null)
table.DrawColumn(file.Name);
table.NextColumn();
if (ex is null)
{
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
{
using var color = ImGuiColor.Text.Push(ColorId.ConflictingMod.Value());
ImGui.TextUnformatted(ex.Message);
ImGuiUtil.HoverTooltip(ex.ToString());
Im.Text(ex.Message);
Im.Tooltip.OnHover($"{ex}");
}
}
}
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 OtterGui.Text;
using Rgba32 = SixLabors.ImageSharp.PixelFormats.Rgba32;
namespace Penumbra.Import.Textures;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.GameData.Interop;
using Penumbra.Interop.PathResolving;
@ -20,7 +20,7 @@ public unsafe class AtchCallerHook1 : FastHook<AtchCallerHook1.Delegate>, IDispo
Task = hooks.CreateHook<Delegate>("AtchCaller1", Sigs.AtchCaller1, Detour,
metaState.Config.EnableMods && !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)
@ -34,5 +34,5 @@ public unsafe class AtchCallerHook1 : FastHook<AtchCallerHook1.Delegate>, IDispo
}
public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle;
=> _metaState.Config.ModsEnabled -= Set;
}

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.GameData.Interop;
using Penumbra.Interop.PathResolving;
@ -20,7 +20,7 @@ public unsafe class AtchCallerHook2 : FastHook<AtchCallerHook2.Delegate>, IDispo
Task = hooks.CreateHook<Delegate>("AtchCaller2", Sigs.AtchCaller2, Detour,
metaState.Config.EnableMods && !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)
@ -34,5 +34,5 @@ public unsafe class AtchCallerHook2 : FastHook<AtchCallerHook2.Delegate>, IDispo
}
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.Object;
using OtterGui.Services;
using Luna;
using Penumbra.Interop.PathResolving;
namespace Penumbra.Interop.Hooks.Meta;

View file

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

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
@ -19,7 +19,7 @@ public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>, ID
Task = hooks.CreateHook<Delegate>("GetEqdpAccessoryEntry", Sigs.GetEqdpAccessoryEntry, Detour,
metaState.Config.EnableMods && !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)
@ -33,5 +33,5 @@ public unsafe class EqdpAccessoryHook : FastHook<EqdpAccessoryHook.Delegate>, ID
}
public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle;
=> _metaState.Config.ModsEnabled -= Set;
}

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
@ -18,7 +18,7 @@ public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>, IDisposabl
_metaState = metaState;
Task = hooks.CreateHook<Delegate>("GetEqdpEquipEntry", Sigs.GetEqdpEquipEntry, Detour, metaState.Config.EnableMods && !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)
@ -32,5 +32,5 @@ public unsafe class EqdpEquipHook : FastHook<EqdpEquipHook.Delegate>, IDisposabl
}
public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle;
=> _metaState.Config.ModsEnabled -= Set;
}

View file

@ -1,5 +1,5 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.GameData.Structs;
using Penumbra.Interop.PathResolving;
@ -18,7 +18,7 @@ public unsafe class EqpHook : FastHook<EqpHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetEqpFlags", Sigs.GetEqpEntry, Detour,
metaState.Config.EnableMods && !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)
@ -37,5 +37,5 @@ public unsafe class EqpHook : FastHook<EqpHook.Delegate>, IDisposable
}
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.Enums;
using Penumbra.GameData.Structs;
@ -23,7 +23,7 @@ public unsafe class EstHook : FastHook<EstHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("FindEstEntry", Sigs.FindEstEntry, Detour,
metaState.Config.EnableMods && !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)
@ -59,5 +59,5 @@ public unsafe class EstHook : FastHook<EstHook.Delegate>, IDisposable
}
public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle;
=> _metaState.Config.ModsEnabled -= Set;
}

View file

@ -1,9 +1,7 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Lumina.Data.Parsing.Uld;
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.Interop.PathResolving;
using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations;
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,
metaState.Config.EnableMods && !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)
@ -39,5 +37,5 @@ public unsafe class GmpHook : FastHook<GmpHook.Delegate>, IDisposable
}
public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle;
=> _metaState.Config.ModsEnabled -= Set;
}

View file

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

View file

@ -1,4 +1,4 @@
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.GameData.Enums;
using Penumbra.Interop.PathResolving;
@ -22,7 +22,7 @@ public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetRspBust", Sigs.GetRspBust, Detour,
metaState.Config.EnableMods && !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)
@ -69,5 +69,5 @@ public unsafe class RspBustHook : FastHook<RspBustHook.Delegate>, IDisposable
}
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.Enums;
using Penumbra.Interop.PathResolving;
@ -22,7 +22,7 @@ public class RspHeightHook : FastHook<RspHeightHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetRspHeight", Sigs.GetRspHeight, Detour,
metaState.Config.EnableMods && !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)
@ -79,5 +79,5 @@ public class RspHeightHook : FastHook<RspHeightHook.Delegate>, IDisposable
}
public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle;
=> _metaState.Config.ModsEnabled -= Set;
}

View file

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

View file

@ -1,4 +1,4 @@
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
using Penumbra.GameData.Enums;
using Penumbra.Interop.PathResolving;
@ -22,7 +22,7 @@ public class RspTailHook : FastHook<RspTailHook.Delegate>, IDisposable
Task = hooks.CreateHook<Delegate>("GetRspTail", Sigs.GetRspTail, Detour,
metaState.Config.EnableMods && !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)
@ -73,5 +73,5 @@ public class RspTailHook : FastHook<RspTailHook.Delegate>, IDisposable
}
public void Dispose()
=> _metaState.Config.ModsEnabled -= Toggle;
=> _metaState.Config.ModsEnabled -= Set;
}

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
using Dalamud.Hooking;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using OtterGui.Services;
using Luna;
using Penumbra.GameData;
namespace Penumbra.Interop.Hooks.Objects;
@ -9,7 +9,7 @@ namespace Penumbra.Interop.Hooks.Objects;
/// 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.
/// </summary>
public sealed unsafe class EnableDraw : Luna.IHookService
public sealed unsafe class EnableDraw : IHookService
{
private readonly Task<Hook<Delegate>> _task;
private readonly GameState _state;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,5 @@
using Dalamud.Interface.ImGuiNotification;
using Luna;
using OtterGui.Tasks;
using Penumbra.Mods.Groups;
using Penumbra.Mods.Manager;
using Penumbra.Mods.SubMods;
@ -9,7 +8,7 @@ using Penumbra.String.Classes;
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 = [];
@ -36,7 +35,7 @@ public class ModNormalizer(ModManager modManager, Configuration config, SaveServ
Step = 0;
TotalSteps = mod.TotalFileCount + 5;
Worker = TrackedTask.Run(NormalizeSync);
Worker = Task.Run(NormalizeSync);
}
public void NormalizeUi(DirectoryInfo modDirectory)

View file

@ -1,9 +1,5 @@
using System.Collections.Frozen;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.Utility.Raii;
using ImSharp;
using OtterGui.Text;
using Penumbra.Mods.Manager;
using Penumbra.UI.Classes;
using Notification = Luna.Notification;
@ -37,9 +33,8 @@ public static class FeatureChecker
if (missingFeatures.Count > 0)
{
Penumbra.Messager.AddMessage(new Notification(
$"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()}].")}",
NotificationType.Warning));
Penumbra.Messager.AddMessage(new Notification($"Please update Penumbra to use the mod {modName}{(modDirectory != modName ? $" at {modDirectory}" : string.Empty)}!\n\n"
+ $"Loading failed because it requires the unsupported feature{(missingFeatures.Count > 1 ? $"s\n\n\t[{string.Join("], [", missingFeatures)}]." : $" [{missingFeatures.First()}].")}"));
return FeatureFlags.Invalid;
}
@ -52,7 +47,7 @@ public static class FeatureChecker
public static void DrawFeatureFlagInput(ModDataEditor editor, Mod mod, float width)
{
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 buttonColor = Im.Style[ImGuiColor.FrameBackground];
var textColor = Im.Style[ImGuiColor.TextDisabled];
@ -65,7 +60,7 @@ public static class FeatureChecker
{
if (mod.RequiredFeatures.HasFlag(flag))
{
style.Push(ImStyleSingle.FrameBorderThickness, ImUtf8.GlobalScale);
style.Push(ImStyleSingle.FrameBorderThickness, Im.Style.GlobalScale);
style.PopColor(2);
if (Im.Button($"{flag}", size))
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());
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);
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.Interop;
using Penumbra.Mods.Editor;
@ -228,7 +229,7 @@ public sealed class ModManager : ModStorage, IDisposable, Luna.IService
if (oldName == newName)
return NewDirectoryState.Identical;
var fixedNewName = ModCreator.ReplaceBadXivSymbols(newName, _config.ReplaceNonAsciiOnImport);
var fixedNewName = newName.ReplaceBadXivSymbols(_config.ReplaceNonAsciiOnImport);
if (fixedNewName != newName)
return NewDirectoryState.ContainsInvalidSymbols;

View file

@ -1,17 +1,5 @@
using OtterGui.Classes;
using OtterGui.Widgets;
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>
{
/// <summary> The actual list of mods. </summary>

View file

@ -1,5 +1,4 @@
using Luna;
using OtterGui.Filesystem;
using Penumbra.Communication;
using Penumbra.GameData.Structs;
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)
{
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo))
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
return false;
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);

View file

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

View file

@ -1,5 +1,4 @@
using Luna;
using OtterGui.Filesystem;
using Penumbra.Communication;
using Penumbra.Mods.Groups;
using Penumbra.Mods.Settings;
@ -9,7 +8,7 @@ using Penumbra.Services;
namespace Penumbra.Mods.Manager.OptionEditor;
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)
{
@ -75,7 +74,7 @@ public sealed class MultiModGroupEditor(CommunicatorService communicator, SaveSe
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;
group.DefaultSettings = group.DefaultSettings.MoveBit(optionIdxFrom, optionIdxTo);

View file

@ -1,5 +1,4 @@
using Luna;
using OtterGui.Filesystem;
using Penumbra.Communication;
using Penumbra.Mods.Groups;
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)
{
if (!Extensions.Move(group.OptionData, ref optionIdxFrom, ref optionIdxTo))
if (!group.OptionData.Move(ref optionIdxFrom, ref optionIdxTo))
return false;
group.DefaultSettings = group.DefaultSettings.MoveSingle(optionIdxFrom, optionIdxTo);

View file

@ -2,7 +2,6 @@ using Dalamud.Interface.ImGuiNotification;
using Luna;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
using Penumbra.GameData.Data;
using Penumbra.Import;
@ -29,7 +28,8 @@ public partial class ModCreator(
public readonly Configuration Config = config;
/// <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
{
@ -81,7 +81,7 @@ public partial class ModCreator(
if (incorporateMetaChanges)
IncorporateAllMetaChanges(mod, true, deleteDefaultMetaChanges);
else if (deleteDefaultMetaChanges)
ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, saveService, false);
ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, saveService);
return true;
}
@ -98,7 +98,7 @@ public partial class ModCreator(
{
changes = changes
|| 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);
}
else
@ -167,7 +167,7 @@ public partial class ModCreator(
DeleteDeleteList(deleteList, delete);
if (removeDefaultValues && !Config.KeepDefaultMetaChanges)
changes |= ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, null, false);
changes |= ModMetaEditor.DeleteDefaultValues(mod, metaFileManager, null);
if (!changes)
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>
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 : "_"));
}
/// <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)
{
var mod = new Mod(baseDir);

View file

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

View file

@ -1,5 +1,5 @@
using Luna;
using Newtonsoft.Json;
using OtterGui;
namespace Penumbra.Mods.Settings;
@ -27,10 +27,10 @@ public readonly record struct Setting(ulong Value)
=> idx >= 0 && (Value & (1ul << idx)) != 0;
public Setting MoveBit(int idx1, int idx2)
=> new(Functions.MoveBit(Value, idx1, idx2));
=> new(BitFunctions.MoveBit(Value, idx1, idx2));
public Setting RemoveBit(int idx)
=> new(Functions.RemoveBit(Value, idx));
=> new(BitFunctions.RemoveBit(Value, idx));
public Setting SetBit(int idx, bool value)
=> 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.PathResolving;
using Penumbra.Interop.Services;
using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.Services;
using Penumbra.UI;
using Penumbra.UI.AdvancedWindow;
using Penumbra.UI.Tabs;
using static System.Collections.Specialized.BitVector32;
using ChangedItemClick = Penumbra.Communication.ChangedItemClick;
using ChangedItemHover = Penumbra.Communication.ChangedItemHover;
using DynamisIpc = OtterGui.Services.DynamisIpc;

View file

@ -1,9 +1,10 @@
using Luna;
using ImSharp;
using Luna;
using Penumbra.Mods.Manager;
namespace Penumbra.Services;
public class FileWatcher : IDisposable, IService
public sealed class FileWatcher : IDisposable, IService
{
private readonly ConcurrentSet<string> _pending = new(StringComparer.OrdinalIgnoreCase);
private readonly ModImportManager _modImportManager;
@ -47,9 +48,6 @@ public class FileWatcher : IDisposable, IService
}
}
internal void PauseConsumer(bool pause)
=> _pausedConsumer = pause;
private void EndFileWatcher()
{
if (_fsw is null)
@ -206,4 +204,47 @@ public class FileWatcher : IDisposable, IService
EndConsumerTask();
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)
=> 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)
=> 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)
{
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";
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.Interface;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Services;
using ImSharp;
using OtterGui.Widgets;
@ -14,6 +12,55 @@ using MouseWheelType = OtterGui.Widgets.MouseWheelType;
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 sealed class StainTemplateCombo<TDyePack>(FilterComboColors[] stainCombos, StmFile<TDyePack> stmFile)
@ -25,11 +72,11 @@ public class StainService : Luna.IService
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)
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)
@ -37,17 +84,17 @@ public class StainService : Luna.IService
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);
}
public override bool Draw(string label, string preview, string tooltip, ref int currentSelection, float previewWidth, float itemHeight,
ImGuiComboFlags flags = ImGuiComboFlags.None)
{
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(1, 0.5f))
.Push(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemInnerSpacing.X });
var spaceSize = ImGui.CalcTextSize(" ").X;
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);
}
@ -60,12 +107,13 @@ public class StainService : Luna.IService
return ret;
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();
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();
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;
}
}

View file

@ -11,9 +11,8 @@ using Penumbra.UI.Classes;
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;
public void Draw()
@ -122,9 +121,9 @@ public class ModMergeTab(ModMerger modMerger) : Luna.IUiService
private void DrawCombo(float width)
{
_modCombo.Draw("##ModSelection", _modCombo.CurrentSelection?.Name ?? "Select the target Mod...", string.Empty, width,
ImGui.GetTextLineHeight());
modMerger.MergeToMod = _modCombo.CurrentSelection;
if (combo.Draw("##ModSelection"u8, modMerger.MergeToMod?.Name ?? "Select the target Mod...", StringU8.Empty, width,
out var cacheMod))
modMerger.MergeToMod = cacheMod.Item;
}
private void DrawSplitOff(float size)

View file

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