mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
1621 lines
71 KiB
C#
1621 lines
71 KiB
C#
using Dalamud.Interface;
|
|
using Dalamud.Plugin;
|
|
using ImGuiNET;
|
|
using OtterGui;
|
|
using OtterGui.Raii;
|
|
using Penumbra.Mods;
|
|
using System.Globalization;
|
|
using Dalamud.Utility;
|
|
using Penumbra.Api.Enums;
|
|
using Penumbra.Api.Helpers;
|
|
using Penumbra.String;
|
|
using Penumbra.String.Classes;
|
|
using Penumbra.Meta.Manipulations;
|
|
using Penumbra.Mods.Manager;
|
|
using Penumbra.Services;
|
|
using Penumbra.UI;
|
|
using Penumbra.Collections.Manager;
|
|
using Dalamud.Plugin.Services;
|
|
using Penumbra.GameData.Enums;
|
|
|
|
namespace Penumbra.Api;
|
|
|
|
public class IpcTester : IDisposable
|
|
{
|
|
private readonly PenumbraIpcProviders _ipcProviders;
|
|
private bool _subscribed = true;
|
|
|
|
private readonly PluginState _pluginState;
|
|
private readonly IpcConfiguration _ipcConfiguration;
|
|
private readonly Ui _ui;
|
|
private readonly Redrawing _redrawing;
|
|
private readonly GameState _gameState;
|
|
private readonly Resolve _resolve;
|
|
private readonly Collections _collections;
|
|
private readonly Meta _meta;
|
|
private readonly Mods _mods;
|
|
private readonly ModSettings _modSettings;
|
|
private readonly Editing _editing;
|
|
private readonly Temporary _temporary;
|
|
private readonly ResourceTree _resourceTree;
|
|
|
|
public IpcTester(Configuration config, DalamudServices dalamud, PenumbraIpcProviders ipcProviders, ModManager modManager,
|
|
CollectionManager collections, TempModManager tempMods, TempCollectionManager tempCollections, SaveService saveService)
|
|
{
|
|
_ipcProviders = ipcProviders;
|
|
_pluginState = new PluginState(dalamud.PluginInterface);
|
|
_ipcConfiguration = new IpcConfiguration(dalamud.PluginInterface);
|
|
_ui = new Ui(dalamud.PluginInterface);
|
|
_redrawing = new Redrawing(dalamud);
|
|
_gameState = new GameState(dalamud.PluginInterface);
|
|
_resolve = new Resolve(dalamud.PluginInterface);
|
|
_collections = new Collections(dalamud.PluginInterface);
|
|
_meta = new Meta(dalamud.PluginInterface);
|
|
_mods = new Mods(dalamud.PluginInterface);
|
|
_modSettings = new ModSettings(dalamud.PluginInterface);
|
|
_editing = new Editing(dalamud.PluginInterface);
|
|
_temporary = new Temporary(dalamud.PluginInterface, modManager, collections, tempMods, tempCollections, saveService, config);
|
|
_resourceTree = new ResourceTree(dalamud.PluginInterface, dalamud.Objects);
|
|
UnsubscribeEvents();
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
try
|
|
{
|
|
SubscribeEvents();
|
|
ImGui.TextUnformatted($"API Version: {_ipcProviders.Api.ApiVersion.Breaking}.{_ipcProviders.Api.ApiVersion.Feature:D4}");
|
|
_pluginState.Draw();
|
|
_ipcConfiguration.Draw();
|
|
_ui.Draw();
|
|
_redrawing.Draw();
|
|
_gameState.Draw();
|
|
_resolve.Draw();
|
|
_collections.Draw();
|
|
_meta.Draw();
|
|
_mods.Draw();
|
|
_modSettings.Draw();
|
|
_editing.Draw();
|
|
_temporary.Draw();
|
|
_temporary.DrawCollections();
|
|
_temporary.DrawMods();
|
|
_resourceTree.Draw();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Penumbra.Log.Error($"Error during IPC Tests:\n{e}");
|
|
}
|
|
}
|
|
|
|
private void SubscribeEvents()
|
|
{
|
|
if (!_subscribed)
|
|
{
|
|
_pluginState.Initialized.Enable();
|
|
_pluginState.Disposed.Enable();
|
|
_pluginState.EnabledChange.Enable();
|
|
_redrawing.Redrawn.Enable();
|
|
_ui.PreSettingsDraw.Enable();
|
|
_ui.PostSettingsDraw.Enable();
|
|
_modSettings.SettingChanged.Enable();
|
|
_gameState.CharacterBaseCreating.Enable();
|
|
_gameState.CharacterBaseCreated.Enable();
|
|
_ipcConfiguration.ModDirectoryChanged.Enable();
|
|
_gameState.GameObjectResourcePathResolved.Enable();
|
|
_mods.DeleteSubscriber.Enable();
|
|
_mods.AddSubscriber.Enable();
|
|
_mods.MoveSubscriber.Enable();
|
|
_subscribed = true;
|
|
}
|
|
}
|
|
|
|
public void UnsubscribeEvents()
|
|
{
|
|
if (_subscribed)
|
|
{
|
|
_pluginState.Initialized.Disable();
|
|
_pluginState.Disposed.Disable();
|
|
_pluginState.EnabledChange.Disable();
|
|
_redrawing.Redrawn.Disable();
|
|
_ui.PreSettingsDraw.Disable();
|
|
_ui.PostSettingsDraw.Disable();
|
|
_ui.Tooltip.Disable();
|
|
_ui.Click.Disable();
|
|
_modSettings.SettingChanged.Disable();
|
|
_gameState.CharacterBaseCreating.Disable();
|
|
_gameState.CharacterBaseCreated.Disable();
|
|
_ipcConfiguration.ModDirectoryChanged.Disable();
|
|
_gameState.GameObjectResourcePathResolved.Disable();
|
|
_mods.DeleteSubscriber.Disable();
|
|
_mods.AddSubscriber.Disable();
|
|
_mods.MoveSubscriber.Disable();
|
|
_subscribed = false;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_pluginState.Initialized.Dispose();
|
|
_pluginState.Disposed.Dispose();
|
|
_pluginState.EnabledChange.Dispose();
|
|
_redrawing.Redrawn.Dispose();
|
|
_ui.PreSettingsDraw.Dispose();
|
|
_ui.PostSettingsDraw.Dispose();
|
|
_ui.Tooltip.Dispose();
|
|
_ui.Click.Dispose();
|
|
_modSettings.SettingChanged.Dispose();
|
|
_gameState.CharacterBaseCreating.Dispose();
|
|
_gameState.CharacterBaseCreated.Dispose();
|
|
_ipcConfiguration.ModDirectoryChanged.Dispose();
|
|
_gameState.GameObjectResourcePathResolved.Dispose();
|
|
_mods.DeleteSubscriber.Dispose();
|
|
_mods.AddSubscriber.Dispose();
|
|
_mods.MoveSubscriber.Dispose();
|
|
_subscribed = false;
|
|
}
|
|
|
|
private static void DrawIntro(string label, string info)
|
|
{
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(label);
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(info);
|
|
ImGui.TableNextColumn();
|
|
}
|
|
|
|
|
|
private class PluginState
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
public readonly EventSubscriber Initialized;
|
|
public readonly EventSubscriber Disposed;
|
|
public readonly EventSubscriber<bool> EnabledChange;
|
|
|
|
private readonly List<DateTimeOffset> _initializedList = new();
|
|
private readonly List<DateTimeOffset> _disposedList = new();
|
|
|
|
private DateTimeOffset _lastEnabledChange = DateTimeOffset.UnixEpoch;
|
|
private bool? _lastEnabledValue;
|
|
|
|
public PluginState(DalamudPluginInterface pi)
|
|
{
|
|
_pi = pi;
|
|
Initialized = Ipc.Initialized.Subscriber(pi, AddInitialized);
|
|
Disposed = Ipc.Disposed.Subscriber(pi, AddDisposed);
|
|
EnabledChange = Ipc.EnabledChange.Subscriber(pi, SetLastEnabled);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Plugin State");
|
|
if (!_)
|
|
return;
|
|
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
void DrawList(string label, string text, List<DateTimeOffset> list)
|
|
{
|
|
DrawIntro(label, text);
|
|
if (list.Count == 0)
|
|
{
|
|
ImGui.TextUnformatted("Never");
|
|
}
|
|
else
|
|
{
|
|
ImGui.TextUnformatted(list[^1].LocalDateTime.ToString(CultureInfo.CurrentCulture));
|
|
if (list.Count > 1 && ImGui.IsItemHovered())
|
|
ImGui.SetTooltip(string.Join("\n",
|
|
list.SkipLast(1).Select(t => t.LocalDateTime.ToString(CultureInfo.CurrentCulture))));
|
|
}
|
|
}
|
|
|
|
DrawList(Ipc.Initialized.Label, "Last Initialized", _initializedList);
|
|
DrawList(Ipc.Disposed.Label, "Last Disposed", _disposedList);
|
|
DrawIntro(Ipc.ApiVersions.Label, "Current Version");
|
|
var (breaking, features) = Ipc.ApiVersions.Subscriber(_pi).Invoke();
|
|
ImGui.TextUnformatted($"{breaking}.{features:D4}");
|
|
DrawIntro(Ipc.GetEnabledState.Label, "Current State");
|
|
ImGui.TextUnformatted($"{Ipc.GetEnabledState.Subscriber(_pi).Invoke()}");
|
|
DrawIntro(Ipc.EnabledChange.Label, "Last Change");
|
|
ImGui.TextUnformatted(_lastEnabledValue is { } v ? $"{_lastEnabledChange} (to {v})" : "Never");
|
|
}
|
|
|
|
private void AddInitialized()
|
|
=> _initializedList.Add(DateTimeOffset.UtcNow);
|
|
|
|
private void AddDisposed()
|
|
=> _disposedList.Add(DateTimeOffset.UtcNow);
|
|
|
|
private void SetLastEnabled(bool val)
|
|
=> (_lastEnabledChange, _lastEnabledValue) = (DateTimeOffset.Now, val);
|
|
}
|
|
|
|
private class IpcConfiguration
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
public readonly EventSubscriber<string, bool> ModDirectoryChanged;
|
|
|
|
private string _currentConfiguration = string.Empty;
|
|
private string _lastModDirectory = string.Empty;
|
|
private bool _lastModDirectoryValid;
|
|
private DateTimeOffset _lastModDirectoryTime = DateTimeOffset.MinValue;
|
|
|
|
public IpcConfiguration(DalamudPluginInterface pi)
|
|
{
|
|
_pi = pi;
|
|
ModDirectoryChanged = Ipc.ModDirectoryChanged.Subscriber(pi, UpdateModDirectoryChanged);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Configuration");
|
|
if (!_)
|
|
return;
|
|
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.GetModDirectory.Label, "Current Mod Directory");
|
|
ImGui.TextUnformatted(Ipc.GetModDirectory.Subscriber(_pi).Invoke());
|
|
DrawIntro(Ipc.ModDirectoryChanged.Label, "Last Mod Directory Change");
|
|
ImGui.TextUnformatted(_lastModDirectoryTime > DateTimeOffset.MinValue
|
|
? $"{_lastModDirectory} ({(_lastModDirectoryValid ? "Valid" : "Invalid")}) at {_lastModDirectoryTime}"
|
|
: "None");
|
|
DrawIntro(Ipc.GetConfiguration.Label, "Configuration");
|
|
if (ImGui.Button("Get"))
|
|
{
|
|
_currentConfiguration = Ipc.GetConfiguration.Subscriber(_pi).Invoke();
|
|
ImGui.OpenPopup("Config Popup");
|
|
}
|
|
|
|
DrawConfigPopup();
|
|
}
|
|
|
|
private void DrawConfigPopup()
|
|
{
|
|
ImGui.SetNextWindowSize(ImGuiHelpers.ScaledVector2(500, 500));
|
|
using var popup = ImRaii.Popup("Config Popup");
|
|
if (popup)
|
|
{
|
|
using (var font = ImRaii.PushFont(UiBuilder.MonoFont))
|
|
{
|
|
ImGuiUtil.TextWrapped(_currentConfiguration);
|
|
}
|
|
|
|
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
|
|
ImGui.CloseCurrentPopup();
|
|
}
|
|
}
|
|
|
|
private void UpdateModDirectoryChanged(string path, bool valid)
|
|
=> (_lastModDirectory, _lastModDirectoryValid, _lastModDirectoryTime) = (path, valid, DateTimeOffset.Now);
|
|
}
|
|
|
|
private class Ui
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
public readonly EventSubscriber<string> PreSettingsDraw;
|
|
public readonly EventSubscriber<string> PostSettingsDraw;
|
|
public readonly EventSubscriber<ChangedItemType, uint> Tooltip;
|
|
public readonly EventSubscriber<MouseButton, ChangedItemType, uint> Click;
|
|
|
|
private string _lastDrawnMod = string.Empty;
|
|
private DateTimeOffset _lastDrawnModTime = DateTimeOffset.MinValue;
|
|
private bool _subscribedToTooltip = false;
|
|
private bool _subscribedToClick = false;
|
|
private string _lastClicked = string.Empty;
|
|
private string _lastHovered = string.Empty;
|
|
private TabType _selectTab = TabType.None;
|
|
private string _modName = string.Empty;
|
|
private PenumbraApiEc _ec = PenumbraApiEc.Success;
|
|
|
|
public Ui(DalamudPluginInterface pi)
|
|
{
|
|
_pi = pi;
|
|
PreSettingsDraw = Ipc.PreSettingsDraw.Subscriber(pi, UpdateLastDrawnMod);
|
|
PostSettingsDraw = Ipc.PostSettingsDraw.Subscriber(pi, UpdateLastDrawnMod);
|
|
Tooltip = Ipc.ChangedItemTooltip.Subscriber(pi, AddedTooltip);
|
|
Click = Ipc.ChangedItemClick.Subscriber(pi, AddedClick);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("UI");
|
|
if (!_)
|
|
return;
|
|
|
|
using (var combo = ImRaii.Combo("Tab to Open at", _selectTab.ToString()))
|
|
{
|
|
if (combo)
|
|
foreach (var val in Enum.GetValues<TabType>())
|
|
{
|
|
if (ImGui.Selectable(val.ToString(), _selectTab == val))
|
|
_selectTab = val;
|
|
}
|
|
}
|
|
|
|
ImGui.InputTextWithHint("##openMod", "Mod to Open at...", ref _modName, 256);
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.PostSettingsDraw.Label, "Last Drawn Mod");
|
|
ImGui.TextUnformatted(_lastDrawnMod.Length > 0 ? $"{_lastDrawnMod} at {_lastDrawnModTime}" : "None");
|
|
|
|
DrawIntro(Ipc.ChangedItemTooltip.Label, "Add Tooltip");
|
|
if (ImGui.Checkbox("##tooltip", ref _subscribedToTooltip))
|
|
{
|
|
if (_subscribedToTooltip)
|
|
Tooltip.Enable();
|
|
else
|
|
Tooltip.Disable();
|
|
}
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_lastHovered);
|
|
|
|
DrawIntro(Ipc.ChangedItemClick.Label, "Subscribe Click");
|
|
if (ImGui.Checkbox("##click", ref _subscribedToClick))
|
|
{
|
|
if (_subscribedToClick)
|
|
Click.Enable();
|
|
else
|
|
Click.Disable();
|
|
}
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_lastClicked);
|
|
DrawIntro(Ipc.OpenMainWindow.Label, "Open Mod Window");
|
|
if (ImGui.Button("Open##window"))
|
|
_ec = Ipc.OpenMainWindow.Subscriber(_pi).Invoke(_selectTab, _modName, _modName);
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_ec.ToString());
|
|
|
|
DrawIntro(Ipc.CloseMainWindow.Label, "Close Mod Window");
|
|
if (ImGui.Button("Close##window"))
|
|
Ipc.CloseMainWindow.Subscriber(_pi).Invoke();
|
|
}
|
|
|
|
private void UpdateLastDrawnMod(string name)
|
|
=> (_lastDrawnMod, _lastDrawnModTime) = (name, DateTimeOffset.Now);
|
|
|
|
private void AddedTooltip(ChangedItemType type, uint id)
|
|
{
|
|
_lastHovered = $"{type} {id} at {DateTime.UtcNow.ToLocalTime().ToString(CultureInfo.CurrentCulture)}";
|
|
ImGui.TextUnformatted("IPC Test Successful");
|
|
}
|
|
|
|
private void AddedClick(MouseButton button, ChangedItemType type, uint id)
|
|
{
|
|
_lastClicked = $"{button}-click on {type} {id} at {DateTime.UtcNow.ToLocalTime().ToString(CultureInfo.CurrentCulture)}";
|
|
}
|
|
}
|
|
|
|
private class Redrawing
|
|
{
|
|
private readonly DalamudServices _dalamud;
|
|
public readonly EventSubscriber<IntPtr, int> Redrawn;
|
|
|
|
private string _redrawName = string.Empty;
|
|
private int _redrawIndex = 0;
|
|
private string _lastRedrawnString = "None";
|
|
|
|
public Redrawing(DalamudServices dalamud)
|
|
{
|
|
_dalamud = dalamud;
|
|
Redrawn = Ipc.GameObjectRedrawn.Subscriber(_dalamud.PluginInterface, SetLastRedrawn);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Redrawing");
|
|
if (!_)
|
|
return;
|
|
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.RedrawObjectByName.Label, "Redraw by Name");
|
|
ImGui.SetNextItemWidth(100 * UiHelpers.Scale);
|
|
ImGui.InputTextWithHint("##redrawName", "Name...", ref _redrawName, 32);
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Redraw##Name"))
|
|
Ipc.RedrawObjectByName.Subscriber(_dalamud.PluginInterface).Invoke(_redrawName, RedrawType.Redraw);
|
|
|
|
DrawIntro(Ipc.RedrawObject.Label, "Redraw Player Character");
|
|
if (ImGui.Button("Redraw##pc") && _dalamud.ClientState.LocalPlayer != null)
|
|
Ipc.RedrawObject.Subscriber(_dalamud.PluginInterface).Invoke(_dalamud.ClientState.LocalPlayer, RedrawType.Redraw);
|
|
|
|
DrawIntro(Ipc.RedrawObjectByIndex.Label, "Redraw by Index");
|
|
var tmp = _redrawIndex;
|
|
ImGui.SetNextItemWidth(100 * UiHelpers.Scale);
|
|
if (ImGui.DragInt("##redrawIndex", ref tmp, 0.1f, 0, _dalamud.Objects.Length))
|
|
_redrawIndex = Math.Clamp(tmp, 0, _dalamud.Objects.Length);
|
|
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Redraw##Index"))
|
|
Ipc.RedrawObjectByIndex.Subscriber(_dalamud.PluginInterface).Invoke(_redrawIndex, RedrawType.Redraw);
|
|
|
|
DrawIntro(Ipc.RedrawAll.Label, "Redraw All");
|
|
if (ImGui.Button("Redraw##All"))
|
|
Ipc.RedrawAll.Subscriber(_dalamud.PluginInterface).Invoke(RedrawType.Redraw);
|
|
|
|
DrawIntro(Ipc.GameObjectRedrawn.Label, "Last Redrawn Object:");
|
|
ImGui.TextUnformatted(_lastRedrawnString);
|
|
}
|
|
|
|
private void SetLastRedrawn(IntPtr address, int index)
|
|
{
|
|
if (index < 0
|
|
|| index > _dalamud.Objects.Length
|
|
|| address == IntPtr.Zero
|
|
|| _dalamud.Objects[index]?.Address != address)
|
|
_lastRedrawnString = "Invalid";
|
|
|
|
_lastRedrawnString = $"{_dalamud.Objects[index]!.Name} (0x{address:X}, {index})";
|
|
}
|
|
}
|
|
|
|
private class GameState
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
public readonly EventSubscriber<IntPtr, string, IntPtr, IntPtr, IntPtr> CharacterBaseCreating;
|
|
public readonly EventSubscriber<IntPtr, string, IntPtr> CharacterBaseCreated;
|
|
public readonly EventSubscriber<IntPtr, string, string> GameObjectResourcePathResolved;
|
|
|
|
|
|
private string _lastCreatedGameObjectName = string.Empty;
|
|
private IntPtr _lastCreatedDrawObject = IntPtr.Zero;
|
|
private DateTimeOffset _lastCreatedGameObjectTime = DateTimeOffset.MaxValue;
|
|
private string _lastResolvedGamePath = string.Empty;
|
|
private string _lastResolvedFullPath = string.Empty;
|
|
private string _lastResolvedObject = string.Empty;
|
|
private DateTimeOffset _lastResolvedGamePathTime = DateTimeOffset.MaxValue;
|
|
private string _currentDrawObjectString = string.Empty;
|
|
private IntPtr _currentDrawObject = IntPtr.Zero;
|
|
private int _currentCutsceneActor = 0;
|
|
|
|
public GameState(DalamudPluginInterface pi)
|
|
{
|
|
_pi = pi;
|
|
CharacterBaseCreating = Ipc.CreatingCharacterBase.Subscriber(pi, UpdateLastCreated);
|
|
CharacterBaseCreated = Ipc.CreatedCharacterBase.Subscriber(pi, UpdateLastCreated2);
|
|
GameObjectResourcePathResolved = Ipc.GameObjectResourcePathResolved.Subscriber(pi, UpdateGameObjectResourcePath);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Game State");
|
|
if (!_)
|
|
return;
|
|
|
|
if (ImGui.InputTextWithHint("##drawObject", "Draw Object Address..", ref _currentDrawObjectString, 16,
|
|
ImGuiInputTextFlags.CharsHexadecimal))
|
|
_currentDrawObject = IntPtr.TryParse(_currentDrawObjectString, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
|
out var tmp)
|
|
? tmp
|
|
: IntPtr.Zero;
|
|
|
|
ImGui.InputInt("Cutscene Actor", ref _currentCutsceneActor, 0);
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.GetDrawObjectInfo.Label, "Draw Object Info");
|
|
if (_currentDrawObject == IntPtr.Zero)
|
|
{
|
|
ImGui.TextUnformatted("Invalid");
|
|
}
|
|
else
|
|
{
|
|
var (ptr, collection) = Ipc.GetDrawObjectInfo.Subscriber(_pi).Invoke(_currentDrawObject);
|
|
ImGui.TextUnformatted(ptr == IntPtr.Zero ? $"No Actor Associated, {collection}" : $"{ptr:X}, {collection}");
|
|
}
|
|
|
|
DrawIntro(Ipc.GetCutsceneParentIndex.Label, "Cutscene Parent");
|
|
ImGui.TextUnformatted(Ipc.GetCutsceneParentIndex.Subscriber(_pi).Invoke(_currentCutsceneActor).ToString());
|
|
|
|
DrawIntro(Ipc.CreatingCharacterBase.Label, "Last Drawobject created");
|
|
if (_lastCreatedGameObjectTime < DateTimeOffset.Now)
|
|
ImGui.TextUnformatted(_lastCreatedDrawObject != IntPtr.Zero
|
|
? $"0x{_lastCreatedDrawObject:X} for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}"
|
|
: $"NULL for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}");
|
|
|
|
DrawIntro(Ipc.GameObjectResourcePathResolved.Label, "Last GamePath resolved");
|
|
if (_lastResolvedGamePathTime < DateTimeOffset.Now)
|
|
ImGui.TextUnformatted(
|
|
$"{_lastResolvedGamePath} -> {_lastResolvedFullPath} for <{_lastResolvedObject}> at {_lastResolvedGamePathTime}");
|
|
}
|
|
|
|
private void UpdateLastCreated(IntPtr gameObject, string _, IntPtr _2, IntPtr _3, IntPtr _4)
|
|
{
|
|
_lastCreatedGameObjectName = GetObjectName(gameObject);
|
|
_lastCreatedGameObjectTime = DateTimeOffset.Now;
|
|
_lastCreatedDrawObject = IntPtr.Zero;
|
|
}
|
|
|
|
private void UpdateLastCreated2(IntPtr gameObject, string _, IntPtr drawObject)
|
|
{
|
|
_lastCreatedGameObjectName = GetObjectName(gameObject);
|
|
_lastCreatedGameObjectTime = DateTimeOffset.Now;
|
|
_lastCreatedDrawObject = drawObject;
|
|
}
|
|
|
|
private void UpdateGameObjectResourcePath(IntPtr gameObject, string gamePath, string fullPath)
|
|
{
|
|
_lastResolvedObject = GetObjectName(gameObject);
|
|
_lastResolvedGamePath = gamePath;
|
|
_lastResolvedFullPath = fullPath;
|
|
_lastResolvedGamePathTime = DateTimeOffset.Now;
|
|
}
|
|
|
|
private static unsafe string GetObjectName(IntPtr gameObject)
|
|
{
|
|
var obj = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)gameObject;
|
|
var name = obj != null ? obj->Name : null;
|
|
return name != null && *name != 0 ? new ByteString(name).ToString() : "Unknown";
|
|
}
|
|
}
|
|
|
|
private class Resolve
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
|
|
private string _currentResolvePath = string.Empty;
|
|
private string _currentResolveCharacter = string.Empty;
|
|
private string _currentReversePath = string.Empty;
|
|
private int _currentReverseIdx = 0;
|
|
|
|
public Resolve(DalamudPluginInterface pi)
|
|
=> _pi = pi;
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Resolving");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGui.InputTextWithHint("##resolvePath", "Resolve this game path...", ref _currentResolvePath, Utf8GamePath.MaxGamePathLength);
|
|
ImGui.InputTextWithHint("##resolveCharacter", "Character Name (leave blank for default)...", ref _currentResolveCharacter, 32);
|
|
ImGui.InputTextWithHint("##resolveInversePath", "Reverse-resolve this path...", ref _currentReversePath,
|
|
Utf8GamePath.MaxGamePathLength);
|
|
ImGui.InputInt("##resolveIdx", ref _currentReverseIdx, 0, 0);
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.ResolveDefaultPath.Label, "Default Collection Resolve");
|
|
if (_currentResolvePath.Length != 0)
|
|
ImGui.TextUnformatted(Ipc.ResolveDefaultPath.Subscriber(_pi).Invoke(_currentResolvePath));
|
|
|
|
DrawIntro(Ipc.ResolveInterfacePath.Label, "Interface Collection Resolve");
|
|
if (_currentResolvePath.Length != 0)
|
|
ImGui.TextUnformatted(Ipc.ResolveInterfacePath.Subscriber(_pi).Invoke(_currentResolvePath));
|
|
|
|
DrawIntro(Ipc.ResolvePlayerPath.Label, "Player Collection Resolve");
|
|
if (_currentResolvePath.Length != 0)
|
|
ImGui.TextUnformatted(Ipc.ResolvePlayerPath.Subscriber(_pi).Invoke(_currentResolvePath));
|
|
|
|
DrawIntro(Ipc.ResolveCharacterPath.Label, "Character Collection Resolve");
|
|
if (_currentResolvePath.Length != 0 && _currentResolveCharacter.Length != 0)
|
|
ImGui.TextUnformatted(Ipc.ResolveCharacterPath.Subscriber(_pi).Invoke(_currentResolvePath, _currentResolveCharacter));
|
|
|
|
DrawIntro(Ipc.ResolveGameObjectPath.Label, "Game Object Collection Resolve");
|
|
if (_currentResolvePath.Length != 0)
|
|
ImGui.TextUnformatted(Ipc.ResolveGameObjectPath.Subscriber(_pi).Invoke(_currentResolvePath, _currentReverseIdx));
|
|
|
|
DrawIntro(Ipc.ReverseResolvePath.Label, "Reversed Game Paths");
|
|
if (_currentReversePath.Length > 0)
|
|
{
|
|
var list = Ipc.ReverseResolvePath.Subscriber(_pi).Invoke(_currentReversePath, _currentResolveCharacter);
|
|
if (list.Length > 0)
|
|
{
|
|
ImGui.TextUnformatted(list[0]);
|
|
if (list.Length > 1 && ImGui.IsItemHovered())
|
|
ImGui.SetTooltip(string.Join("\n", list.Skip(1)));
|
|
}
|
|
}
|
|
|
|
DrawIntro(Ipc.ReverseResolvePlayerPath.Label, "Reversed Game Paths (Player)");
|
|
if (_currentReversePath.Length > 0)
|
|
{
|
|
var list = Ipc.ReverseResolvePlayerPath.Subscriber(_pi).Invoke(_currentReversePath);
|
|
if (list.Length > 0)
|
|
{
|
|
ImGui.TextUnformatted(list[0]);
|
|
if (list.Length > 1 && ImGui.IsItemHovered())
|
|
ImGui.SetTooltip(string.Join("\n", list.Skip(1)));
|
|
}
|
|
}
|
|
|
|
DrawIntro(Ipc.ReverseResolveGameObjectPath.Label, "Reversed Game Paths (Game Object)");
|
|
if (_currentReversePath.Length > 0)
|
|
{
|
|
var list = Ipc.ReverseResolveGameObjectPath.Subscriber(_pi).Invoke(_currentReversePath, _currentReverseIdx);
|
|
if (list.Length > 0)
|
|
{
|
|
ImGui.TextUnformatted(list[0]);
|
|
if (list.Length > 1 && ImGui.IsItemHovered())
|
|
ImGui.SetTooltip(string.Join("\n", list.Skip(1)));
|
|
}
|
|
}
|
|
|
|
DrawIntro(Ipc.ResolvePlayerPaths.Label, "Resolved Paths (Player)");
|
|
if (_currentResolvePath.Length > 0 || _currentReversePath.Length > 0)
|
|
{
|
|
var forwardArray = _currentResolvePath.Length > 0
|
|
? new[]
|
|
{
|
|
_currentResolvePath,
|
|
}
|
|
: Array.Empty<string>();
|
|
var reverseArray = _currentReversePath.Length > 0
|
|
? new[]
|
|
{
|
|
_currentReversePath,
|
|
}
|
|
: Array.Empty<string>();
|
|
var ret = Ipc.ResolvePlayerPaths.Subscriber(_pi).Invoke(forwardArray, reverseArray);
|
|
var text = string.Empty;
|
|
if (ret.Item1.Length > 0)
|
|
{
|
|
if (ret.Item2.Length > 0)
|
|
text = $"Forward: {ret.Item1[0]} | Reverse: {string.Join("; ", ret.Item2[0])}.";
|
|
else
|
|
text = $"Forward: {ret.Item1[0]}.";
|
|
}
|
|
else if (ret.Item2.Length > 0)
|
|
{
|
|
text = $"Reverse: {string.Join("; ", ret.Item2[0])}.";
|
|
}
|
|
|
|
ImGui.TextUnformatted(text);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class Collections
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
|
|
private int _objectIdx = 0;
|
|
private string _collectionName = string.Empty;
|
|
private bool _allowCreation = true;
|
|
private bool _allowDeletion = true;
|
|
private ApiCollectionType _type = ApiCollectionType.Current;
|
|
|
|
private string _characterCollectionName = string.Empty;
|
|
private IList<string> _collections = new List<string>();
|
|
private string _changedItemCollection = string.Empty;
|
|
private IReadOnlyDictionary<string, object?> _changedItems = new Dictionary<string, object?>();
|
|
private PenumbraApiEc _returnCode = PenumbraApiEc.Success;
|
|
private string? _oldCollection = null;
|
|
|
|
public Collections(DalamudPluginInterface pi)
|
|
=> _pi = pi;
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Collections");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGuiUtil.GenericEnumCombo("Collection Type", 200, _type, out _type, t => ((CollectionType)t).ToName());
|
|
ImGui.InputInt("Object Index##Collections", ref _objectIdx, 0, 0);
|
|
ImGui.InputText("Collection Name##Collections", ref _collectionName, 64);
|
|
ImGui.Checkbox("Allow Assignment Creation", ref _allowCreation);
|
|
ImGui.SameLine();
|
|
ImGui.Checkbox("Allow Assignment Deletion", ref _allowDeletion);
|
|
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro("Last Return Code", _returnCode.ToString());
|
|
if (_oldCollection != null)
|
|
ImGui.TextUnformatted(_oldCollection.Length == 0 ? "Created" : _oldCollection);
|
|
|
|
DrawIntro(Ipc.GetCurrentCollectionName.Label, "Current Collection");
|
|
ImGui.TextUnformatted(Ipc.GetCurrentCollectionName.Subscriber(_pi).Invoke());
|
|
DrawIntro(Ipc.GetDefaultCollectionName.Label, "Default Collection");
|
|
ImGui.TextUnformatted(Ipc.GetDefaultCollectionName.Subscriber(_pi).Invoke());
|
|
DrawIntro(Ipc.GetInterfaceCollectionName.Label, "Interface Collection");
|
|
ImGui.TextUnformatted(Ipc.GetInterfaceCollectionName.Subscriber(_pi).Invoke());
|
|
DrawIntro(Ipc.GetCharacterCollectionName.Label, "Character");
|
|
ImGui.SetNextItemWidth(200 * UiHelpers.Scale);
|
|
ImGui.InputTextWithHint("##characterCollectionName", "Character Name...", ref _characterCollectionName, 64);
|
|
var (c, s) = Ipc.GetCharacterCollectionName.Subscriber(_pi).Invoke(_characterCollectionName);
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted($"{c}, {(s ? "Custom" : "Default")}");
|
|
|
|
DrawIntro(Ipc.GetCollections.Label, "Collections");
|
|
if (ImGui.Button("Get##Collections"))
|
|
{
|
|
_collections = Ipc.GetCollections.Subscriber(_pi).Invoke();
|
|
ImGui.OpenPopup("Collections");
|
|
}
|
|
|
|
DrawIntro(Ipc.GetCollectionForType.Label, "Get Special Collection");
|
|
var name = Ipc.GetCollectionForType.Subscriber(_pi).Invoke(_type);
|
|
ImGui.TextUnformatted(name.Length == 0 ? "Unassigned" : name);
|
|
DrawIntro(Ipc.SetCollectionForType.Label, "Set Special Collection");
|
|
if (ImGui.Button("Set##TypeCollection"))
|
|
(_returnCode, _oldCollection) =
|
|
Ipc.SetCollectionForType.Subscriber(_pi).Invoke(_type, _collectionName, _allowCreation, _allowDeletion);
|
|
|
|
DrawIntro(Ipc.GetCollectionForObject.Label, "Get Object Collection");
|
|
(var valid, var individual, name) = Ipc.GetCollectionForObject.Subscriber(_pi).Invoke(_objectIdx);
|
|
ImGui.TextUnformatted(
|
|
$"{(valid ? "Valid" : "Invalid")} Object, {(name.Length == 0 ? "Unassigned" : name)}{(individual ? " (Individual Assignment)" : string.Empty)}");
|
|
DrawIntro(Ipc.SetCollectionForObject.Label, "Set Object Collection");
|
|
if (ImGui.Button("Set##ObjectCollection"))
|
|
(_returnCode, _oldCollection) = Ipc.SetCollectionForObject.Subscriber(_pi)
|
|
.Invoke(_objectIdx, _collectionName, _allowCreation, _allowDeletion);
|
|
|
|
if (_returnCode == PenumbraApiEc.NothingChanged && _oldCollection.IsNullOrEmpty())
|
|
_oldCollection = null;
|
|
|
|
DrawIntro(Ipc.GetChangedItems.Label, "Changed Item List");
|
|
ImGui.SetNextItemWidth(200 * UiHelpers.Scale);
|
|
ImGui.InputTextWithHint("##changedCollection", "Collection Name...", ref _changedItemCollection, 64);
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Get"))
|
|
{
|
|
_changedItems = Ipc.GetChangedItems.Subscriber(_pi).Invoke(_changedItemCollection);
|
|
ImGui.OpenPopup("Changed Item List");
|
|
}
|
|
|
|
DrawChangedItemPopup();
|
|
DrawCollectionPopup();
|
|
}
|
|
|
|
private void DrawChangedItemPopup()
|
|
{
|
|
ImGui.SetNextWindowSize(ImGuiHelpers.ScaledVector2(500, 500));
|
|
using var p = ImRaii.Popup("Changed Item List");
|
|
if (!p)
|
|
return;
|
|
|
|
foreach (var item in _changedItems)
|
|
ImGui.TextUnformatted(item.Key);
|
|
|
|
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
|
|
ImGui.CloseCurrentPopup();
|
|
}
|
|
|
|
private void DrawCollectionPopup()
|
|
{
|
|
ImGui.SetNextWindowSize(ImGuiHelpers.ScaledVector2(500, 500));
|
|
using var p = ImRaii.Popup("Collections");
|
|
if (!p)
|
|
return;
|
|
|
|
foreach (var collection in _collections)
|
|
ImGui.TextUnformatted(collection);
|
|
|
|
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
|
|
ImGui.CloseCurrentPopup();
|
|
}
|
|
}
|
|
|
|
private class Meta
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
|
|
private string _characterName = string.Empty;
|
|
private int _gameObjectIndex = 0;
|
|
|
|
public Meta(DalamudPluginInterface pi)
|
|
=> _pi = pi;
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Meta");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGui.InputTextWithHint("##characterName", "Character Name...", ref _characterName, 64);
|
|
ImGui.InputInt("##metaIdx", ref _gameObjectIndex, 0, 0);
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.GetMetaManipulations.Label, "Meta Manipulations");
|
|
if (ImGui.Button("Copy to Clipboard"))
|
|
{
|
|
var base64 = Ipc.GetMetaManipulations.Subscriber(_pi).Invoke(_characterName);
|
|
ImGui.SetClipboardText(base64);
|
|
}
|
|
|
|
DrawIntro(Ipc.GetPlayerMetaManipulations.Label, "Player Meta Manipulations");
|
|
if (ImGui.Button("Copy to Clipboard##Player"))
|
|
{
|
|
var base64 = Ipc.GetPlayerMetaManipulations.Subscriber(_pi).Invoke();
|
|
ImGui.SetClipboardText(base64);
|
|
}
|
|
|
|
DrawIntro(Ipc.GetGameObjectMetaManipulations.Label, "Game Object Manipulations");
|
|
if (ImGui.Button("Copy to Clipboard##GameObject"))
|
|
{
|
|
var base64 = Ipc.GetGameObjectMetaManipulations.Subscriber(_pi).Invoke(_gameObjectIndex);
|
|
ImGui.SetClipboardText(base64);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class Mods
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
|
|
private string _modDirectory = string.Empty;
|
|
private string _modName = string.Empty;
|
|
private string _pathInput = string.Empty;
|
|
private string _newInstallPath = string.Empty;
|
|
private PenumbraApiEc _lastReloadEc;
|
|
private PenumbraApiEc _lastAddEc;
|
|
private PenumbraApiEc _lastDeleteEc;
|
|
private PenumbraApiEc _lastSetPathEc;
|
|
private PenumbraApiEc _lastInstallEc;
|
|
private IList<(string, string)> _mods = new List<(string, string)>();
|
|
|
|
public readonly EventSubscriber<string> DeleteSubscriber;
|
|
public readonly EventSubscriber<string> AddSubscriber;
|
|
public readonly EventSubscriber<string, string> MoveSubscriber;
|
|
|
|
private DateTimeOffset _lastDeletedModTime = DateTimeOffset.UnixEpoch;
|
|
private string _lastDeletedMod = string.Empty;
|
|
private DateTimeOffset _lastAddedModTime = DateTimeOffset.UnixEpoch;
|
|
private string _lastAddedMod = string.Empty;
|
|
private DateTimeOffset _lastMovedModTime = DateTimeOffset.UnixEpoch;
|
|
private string _lastMovedModFrom = string.Empty;
|
|
private string _lastMovedModTo = string.Empty;
|
|
|
|
public Mods(DalamudPluginInterface pi)
|
|
{
|
|
_pi = pi;
|
|
DeleteSubscriber = Ipc.ModDeleted.Subscriber(pi, s =>
|
|
{
|
|
_lastDeletedModTime = DateTimeOffset.UtcNow;
|
|
_lastDeletedMod = s;
|
|
});
|
|
AddSubscriber = Ipc.ModAdded.Subscriber(pi, s =>
|
|
{
|
|
_lastAddedModTime = DateTimeOffset.UtcNow;
|
|
_lastAddedMod = s;
|
|
});
|
|
MoveSubscriber = Ipc.ModMoved.Subscriber(pi, (s1, s2) =>
|
|
{
|
|
_lastMovedModTime = DateTimeOffset.UtcNow;
|
|
_lastMovedModFrom = s1;
|
|
_lastMovedModTo = s2;
|
|
});
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Mods");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGui.InputTextWithHint("##install", "Install File Path...", ref _newInstallPath, 100);
|
|
ImGui.InputTextWithHint("##modDir", "Mod Directory Name...", ref _modDirectory, 100);
|
|
ImGui.InputTextWithHint("##modName", "Mod Name...", ref _modName, 100);
|
|
ImGui.InputTextWithHint("##path", "New Path...", ref _pathInput, 100);
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.GetMods.Label, "Mods");
|
|
if (ImGui.Button("Get##Mods"))
|
|
{
|
|
_mods = Ipc.GetMods.Subscriber(_pi).Invoke();
|
|
ImGui.OpenPopup("Mods");
|
|
}
|
|
|
|
DrawIntro(Ipc.ReloadMod.Label, "Reload Mod");
|
|
if (ImGui.Button("Reload"))
|
|
_lastReloadEc = Ipc.ReloadMod.Subscriber(_pi).Invoke(_modDirectory, _modName);
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_lastReloadEc.ToString());
|
|
|
|
DrawIntro(Ipc.InstallMod.Label, "Install Mod");
|
|
if (ImGui.Button("Install"))
|
|
_lastInstallEc = Ipc.InstallMod.Subscriber(_pi).Invoke(_newInstallPath);
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_lastInstallEc.ToString());
|
|
|
|
DrawIntro(Ipc.AddMod.Label, "Add Mod");
|
|
if (ImGui.Button("Add"))
|
|
_lastAddEc = Ipc.AddMod.Subscriber(_pi).Invoke(_modDirectory);
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_lastAddEc.ToString());
|
|
|
|
DrawIntro(Ipc.DeleteMod.Label, "Delete Mod");
|
|
if (ImGui.Button("Delete"))
|
|
_lastDeleteEc = Ipc.DeleteMod.Subscriber(_pi).Invoke(_modDirectory, _modName);
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_lastDeleteEc.ToString());
|
|
|
|
DrawIntro(Ipc.GetModPath.Label, "Current Path");
|
|
var (ec, path, def) = Ipc.GetModPath.Subscriber(_pi).Invoke(_modDirectory, _modName);
|
|
ImGui.TextUnformatted($"{path} ({(def ? "Custom" : "Default")}) [{ec}]");
|
|
|
|
DrawIntro(Ipc.SetModPath.Label, "Set Path");
|
|
if (ImGui.Button("Set"))
|
|
_lastSetPathEc = Ipc.SetModPath.Subscriber(_pi).Invoke(_modDirectory, _modName, _pathInput);
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_lastSetPathEc.ToString());
|
|
|
|
DrawIntro(Ipc.ModDeleted.Label, "Last Mod Deleted");
|
|
if (_lastDeletedModTime > DateTimeOffset.UnixEpoch)
|
|
ImGui.TextUnformatted($"{_lastDeletedMod} at {_lastDeletedModTime}");
|
|
|
|
DrawIntro(Ipc.ModAdded.Label, "Last Mod Added");
|
|
if (_lastAddedModTime > DateTimeOffset.UnixEpoch)
|
|
ImGui.TextUnformatted($"{_lastAddedMod} at {_lastAddedModTime}");
|
|
|
|
DrawIntro(Ipc.ModMoved.Label, "Last Mod Moved");
|
|
if (_lastMovedModTime > DateTimeOffset.UnixEpoch)
|
|
ImGui.TextUnformatted($"{_lastMovedModFrom} -> {_lastMovedModTo} at {_lastMovedModTime}");
|
|
|
|
DrawModsPopup();
|
|
}
|
|
|
|
private void DrawModsPopup()
|
|
{
|
|
ImGui.SetNextWindowSize(ImGuiHelpers.ScaledVector2(500, 500));
|
|
using var p = ImRaii.Popup("Mods");
|
|
if (!p)
|
|
return;
|
|
|
|
foreach (var (modDir, modName) in _mods)
|
|
ImGui.TextUnformatted($"{modDir}: {modName}");
|
|
|
|
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
|
|
ImGui.CloseCurrentPopup();
|
|
}
|
|
}
|
|
|
|
private class ModSettings
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
public readonly EventSubscriber<ModSettingChange, string, string, bool> SettingChanged;
|
|
|
|
private PenumbraApiEc _lastSettingsError = PenumbraApiEc.Success;
|
|
private ModSettingChange _lastSettingChangeType;
|
|
private string _lastSettingChangeCollection = string.Empty;
|
|
private string _lastSettingChangeMod = string.Empty;
|
|
private bool _lastSettingChangeInherited;
|
|
private DateTimeOffset _lastSettingChange;
|
|
|
|
private string _settingsModDirectory = string.Empty;
|
|
private string _settingsModName = string.Empty;
|
|
private string _settingsCollection = string.Empty;
|
|
private bool _settingsAllowInheritance = true;
|
|
private bool _settingsInherit = false;
|
|
private bool _settingsEnabled = false;
|
|
private int _settingsPriority = 0;
|
|
private IDictionary<string, (IList<string>, GroupType)>? _availableSettings;
|
|
private IDictionary<string, IList<string>>? _currentSettings = null;
|
|
|
|
public ModSettings(DalamudPluginInterface pi)
|
|
{
|
|
_pi = pi;
|
|
SettingChanged = Ipc.ModSettingChanged.Subscriber(pi, UpdateLastModSetting);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Mod Settings");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGui.InputTextWithHint("##settingsDir", "Mod Directory Name...", ref _settingsModDirectory, 100);
|
|
ImGui.InputTextWithHint("##settingsName", "Mod Name...", ref _settingsModName, 100);
|
|
ImGui.InputTextWithHint("##settingsCollection", "Collection...", ref _settingsCollection, 100);
|
|
ImGui.Checkbox("Allow Inheritance", ref _settingsAllowInheritance);
|
|
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro("Last Error", _lastSettingsError.ToString());
|
|
DrawIntro(Ipc.ModSettingChanged.Label, "Last Mod Setting Changed");
|
|
ImGui.TextUnformatted(_lastSettingChangeMod.Length > 0
|
|
? $"{_lastSettingChangeType} of {_lastSettingChangeMod} in {_lastSettingChangeCollection}{(_lastSettingChangeInherited ? " (Inherited)" : string.Empty)} at {_lastSettingChange}"
|
|
: "None");
|
|
DrawIntro(Ipc.GetAvailableModSettings.Label, "Get Available Settings");
|
|
if (ImGui.Button("Get##Available"))
|
|
{
|
|
_availableSettings = Ipc.GetAvailableModSettings.Subscriber(_pi).Invoke(_settingsModDirectory, _settingsModName);
|
|
_lastSettingsError = _availableSettings == null ? PenumbraApiEc.ModMissing : PenumbraApiEc.Success;
|
|
}
|
|
|
|
|
|
DrawIntro(Ipc.GetCurrentModSettings.Label, "Get Current Settings");
|
|
if (ImGui.Button("Get##Current"))
|
|
{
|
|
var ret = Ipc.GetCurrentModSettings.Subscriber(_pi)
|
|
.Invoke(_settingsCollection, _settingsModDirectory, _settingsModName, _settingsAllowInheritance);
|
|
_lastSettingsError = ret.Item1;
|
|
if (ret.Item1 == PenumbraApiEc.Success)
|
|
{
|
|
_settingsEnabled = ret.Item2?.Item1 ?? false;
|
|
_settingsInherit = ret.Item2?.Item4 ?? false;
|
|
_settingsPriority = ret.Item2?.Item2 ?? 0;
|
|
_currentSettings = ret.Item2?.Item3;
|
|
}
|
|
else
|
|
{
|
|
_currentSettings = null;
|
|
}
|
|
}
|
|
|
|
DrawIntro(Ipc.TryInheritMod.Label, "Inherit Mod");
|
|
ImGui.Checkbox("##inherit", ref _settingsInherit);
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Set##Inherit"))
|
|
_lastSettingsError = Ipc.TryInheritMod.Subscriber(_pi)
|
|
.Invoke(_settingsCollection, _settingsModDirectory, _settingsModName, _settingsInherit);
|
|
|
|
DrawIntro(Ipc.TrySetMod.Label, "Set Enabled");
|
|
ImGui.Checkbox("##enabled", ref _settingsEnabled);
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Set##Enabled"))
|
|
_lastSettingsError = Ipc.TrySetMod.Subscriber(_pi)
|
|
.Invoke(_settingsCollection, _settingsModDirectory, _settingsModName, _settingsEnabled);
|
|
|
|
DrawIntro(Ipc.TrySetModPriority.Label, "Set Priority");
|
|
ImGui.SetNextItemWidth(200 * UiHelpers.Scale);
|
|
ImGui.DragInt("##Priority", ref _settingsPriority);
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Set##Priority"))
|
|
_lastSettingsError = Ipc.TrySetModPriority.Subscriber(_pi)
|
|
.Invoke(_settingsCollection, _settingsModDirectory, _settingsModName, _settingsPriority);
|
|
|
|
DrawIntro(Ipc.CopyModSettings.Label, "Copy Mod Settings");
|
|
if (ImGui.Button("Copy Settings"))
|
|
_lastSettingsError = Ipc.CopyModSettings.Subscriber(_pi).Invoke(_settingsCollection, _settingsModDirectory, _settingsModName);
|
|
|
|
ImGuiUtil.HoverTooltip("Copy settings from Mod Directory Name to Mod Name (as directory) in collection.");
|
|
|
|
DrawIntro(Ipc.TrySetModSetting.Label, "Set Setting(s)");
|
|
if (_availableSettings == null)
|
|
return;
|
|
|
|
foreach (var (group, (list, type)) in _availableSettings)
|
|
{
|
|
using var id = ImRaii.PushId(group);
|
|
var preview = list.Count > 0 ? list[0] : string.Empty;
|
|
IList<string> current;
|
|
if (_currentSettings != null && _currentSettings.TryGetValue(group, out current!) && current.Count > 0)
|
|
{
|
|
preview = current[0];
|
|
}
|
|
else
|
|
{
|
|
current = new List<string>();
|
|
if (_currentSettings != null)
|
|
_currentSettings[group] = current;
|
|
}
|
|
|
|
ImGui.SetNextItemWidth(200 * UiHelpers.Scale);
|
|
using (var c = ImRaii.Combo("##group", preview))
|
|
{
|
|
if (c)
|
|
foreach (var s in list)
|
|
{
|
|
var contained = current.Contains(s);
|
|
if (ImGui.Checkbox(s, ref contained))
|
|
{
|
|
if (contained)
|
|
current.Add(s);
|
|
else
|
|
current.Remove(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Set##setting"))
|
|
{
|
|
if (type == GroupType.Single)
|
|
_lastSettingsError = Ipc.TrySetModSetting.Subscriber(_pi).Invoke(_settingsCollection,
|
|
_settingsModDirectory, _settingsModName, group, current.Count > 0 ? current[0] : string.Empty);
|
|
else
|
|
_lastSettingsError = Ipc.TrySetModSettings.Subscriber(_pi).Invoke(_settingsCollection,
|
|
_settingsModDirectory, _settingsModName, group, current.ToArray());
|
|
}
|
|
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(group);
|
|
}
|
|
}
|
|
|
|
private void UpdateLastModSetting(ModSettingChange type, string collection, string mod, bool inherited)
|
|
{
|
|
_lastSettingChangeType = type;
|
|
_lastSettingChangeCollection = collection;
|
|
_lastSettingChangeMod = mod;
|
|
_lastSettingChangeInherited = inherited;
|
|
_lastSettingChange = DateTimeOffset.Now;
|
|
}
|
|
}
|
|
|
|
private class Editing
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
|
|
private string _inputPath = string.Empty;
|
|
private string _inputPath2 = string.Empty;
|
|
private string _outputPath = string.Empty;
|
|
private string _outputPath2 = string.Empty;
|
|
|
|
private TextureType _typeSelector;
|
|
private bool _mipMaps = true;
|
|
|
|
private Task? _task1;
|
|
private Task? _task2;
|
|
|
|
public Editing(DalamudPluginInterface pi)
|
|
=> _pi = pi;
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Editing");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGui.InputTextWithHint("##inputPath", "Input Texture Path...", ref _inputPath, 256);
|
|
ImGui.InputTextWithHint("##outputPath", "Output Texture Path...", ref _outputPath, 256);
|
|
ImGui.InputTextWithHint("##inputPath2", "Input Texture Path 2...", ref _inputPath2, 256);
|
|
ImGui.InputTextWithHint("##outputPath2", "Output Texture Path 2...", ref _outputPath2, 256);
|
|
TypeCombo();
|
|
ImGui.Checkbox("Add MipMaps", ref _mipMaps);
|
|
|
|
using var table = ImRaii.Table("...", 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.ConvertTextureFile.Label, "Convert Texture 1");
|
|
if (ImGuiUtil.DrawDisabledButton("Save 1", Vector2.Zero, string.Empty, _task1 is { IsCompleted: false }))
|
|
_task1 = Ipc.ConvertTextureFile.Subscriber(_pi).Invoke(_inputPath, _outputPath, _typeSelector, _mipMaps);
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_task1 == null ? "Not Initiated" : _task1.Status.ToString());
|
|
if (ImGui.IsItemHovered() && _task1?.Status == TaskStatus.Faulted)
|
|
ImGui.SetTooltip(_task1.Exception?.ToString());
|
|
|
|
DrawIntro(Ipc.ConvertTextureFile.Label, "Convert Texture 2");
|
|
if (ImGuiUtil.DrawDisabledButton("Save 2", Vector2.Zero, string.Empty, _task2 is { IsCompleted: false }))
|
|
_task2 = Ipc.ConvertTextureFile.Subscriber(_pi).Invoke(_inputPath2, _outputPath2, _typeSelector, _mipMaps);
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(_task2 == null ? "Not Initiated" : _task2.Status.ToString());
|
|
if (ImGui.IsItemHovered() && _task2?.Status == TaskStatus.Faulted)
|
|
ImGui.SetTooltip(_task2.Exception?.ToString());
|
|
}
|
|
|
|
private void TypeCombo()
|
|
{
|
|
using var combo = ImRaii.Combo("Convert To", _typeSelector.ToString());
|
|
if (!combo)
|
|
return;
|
|
|
|
foreach (var value in Enum.GetValues<TextureType>())
|
|
{
|
|
if (ImGui.Selectable(value.ToString(), _typeSelector == value))
|
|
_typeSelector = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
private class Temporary
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
private readonly ModManager _modManager;
|
|
private readonly CollectionManager _collections;
|
|
private readonly TempModManager _tempMods;
|
|
private readonly TempCollectionManager _tempCollections;
|
|
private readonly SaveService _saveService;
|
|
private readonly Configuration _config;
|
|
|
|
public Temporary(DalamudPluginInterface pi, ModManager modManager, CollectionManager collections, TempModManager tempMods,
|
|
TempCollectionManager tempCollections, SaveService saveService, Configuration config)
|
|
{
|
|
_pi = pi;
|
|
_modManager = modManager;
|
|
_collections = collections;
|
|
_tempMods = tempMods;
|
|
_tempCollections = tempCollections;
|
|
_saveService = saveService;
|
|
_config = config;
|
|
}
|
|
|
|
public string LastCreatedCollectionName = string.Empty;
|
|
|
|
private string _tempCollectionName = string.Empty;
|
|
private string _tempCharacterName = string.Empty;
|
|
private string _tempModName = string.Empty;
|
|
private string _tempGamePath = "test/game/path.mtrl";
|
|
private string _tempFilePath = "test/success.mtrl";
|
|
private string _tempManipulation = string.Empty;
|
|
private PenumbraApiEc _lastTempError;
|
|
private int _tempActorIndex = 0;
|
|
private bool _forceOverwrite;
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Temporary");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGui.InputTextWithHint("##tempCollection", "Collection Name...", ref _tempCollectionName, 128);
|
|
ImGui.InputTextWithHint("##tempCollectionChar", "Collection Character...", ref _tempCharacterName, 32);
|
|
ImGui.InputInt("##tempActorIndex", ref _tempActorIndex, 0, 0);
|
|
ImGui.InputTextWithHint("##tempMod", "Temporary Mod Name...", ref _tempModName, 32);
|
|
ImGui.InputTextWithHint("##tempGame", "Game Path...", ref _tempGamePath, 256);
|
|
ImGui.InputTextWithHint("##tempFile", "File Path...", ref _tempFilePath, 256);
|
|
ImGui.InputTextWithHint("##tempManip", "Manipulation Base64 String...", ref _tempManipulation, 256);
|
|
ImGui.Checkbox("Force Character Collection Overwrite", ref _forceOverwrite);
|
|
|
|
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro("Last Error", _lastTempError.ToString());
|
|
DrawIntro("Last Created Collection", LastCreatedCollectionName);
|
|
DrawIntro(Ipc.CreateTemporaryCollection.Label, "Create Temporary Collection");
|
|
#pragma warning disable 0612
|
|
if (ImGui.Button("Create##Collection"))
|
|
(_lastTempError, LastCreatedCollectionName) = Ipc.CreateTemporaryCollection.Subscriber(_pi)
|
|
.Invoke(_tempCollectionName, _tempCharacterName, _forceOverwrite);
|
|
|
|
DrawIntro(Ipc.CreateNamedTemporaryCollection.Label, "Create Named Temporary Collection");
|
|
if (ImGui.Button("Create##NamedCollection"))
|
|
_lastTempError = Ipc.CreateNamedTemporaryCollection.Subscriber(_pi).Invoke(_tempCollectionName);
|
|
|
|
DrawIntro(Ipc.RemoveTemporaryCollection.Label, "Remove Temporary Collection from Character");
|
|
if (ImGui.Button("Delete##Collection"))
|
|
_lastTempError = Ipc.RemoveTemporaryCollection.Subscriber(_pi).Invoke(_tempCharacterName);
|
|
#pragma warning restore 0612
|
|
DrawIntro(Ipc.RemoveTemporaryCollectionByName.Label, "Remove Temporary Collection");
|
|
if (ImGui.Button("Delete##NamedCollection"))
|
|
_lastTempError = Ipc.RemoveTemporaryCollectionByName.Subscriber(_pi).Invoke(_tempCollectionName);
|
|
|
|
DrawIntro(Ipc.AssignTemporaryCollection.Label, "Assign Temporary Collection");
|
|
if (ImGui.Button("Assign##NamedCollection"))
|
|
_lastTempError = Ipc.AssignTemporaryCollection.Subscriber(_pi).Invoke(_tempCollectionName, _tempActorIndex, _forceOverwrite);
|
|
|
|
DrawIntro(Ipc.AddTemporaryMod.Label, "Add Temporary Mod to specific Collection");
|
|
if (ImGui.Button("Add##Mod"))
|
|
_lastTempError = Ipc.AddTemporaryMod.Subscriber(_pi).Invoke(_tempModName, _tempCollectionName,
|
|
new Dictionary<string, string> { { _tempGamePath, _tempFilePath } },
|
|
_tempManipulation.Length > 0 ? _tempManipulation : string.Empty, int.MaxValue);
|
|
|
|
DrawIntro(Ipc.CreateTemporaryCollection.Label, "Copy Existing Collection");
|
|
if (ImGuiUtil.DrawDisabledButton("Copy##Collection", Vector2.Zero,
|
|
"Copies the effective list from the collection named in Temporary Mod Name...",
|
|
!_collections.Storage.ByName(_tempModName, out var copyCollection))
|
|
&& copyCollection is { HasCache: true })
|
|
{
|
|
var files = copyCollection.ResolvedFiles.ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value.Path.ToString());
|
|
var manips = Functions.ToCompressedBase64(copyCollection.MetaCache?.Manipulations.ToArray() ?? Array.Empty<MetaManipulation>(),
|
|
MetaManipulation.CurrentVersion);
|
|
_lastTempError = Ipc.AddTemporaryMod.Subscriber(_pi).Invoke(_tempModName, _tempCollectionName, files, manips, 999);
|
|
}
|
|
|
|
DrawIntro(Ipc.AddTemporaryModAll.Label, "Add Temporary Mod to all Collections");
|
|
if (ImGui.Button("Add##All"))
|
|
_lastTempError = Ipc.AddTemporaryModAll.Subscriber(_pi).Invoke(_tempModName,
|
|
new Dictionary<string, string> { { _tempGamePath, _tempFilePath } },
|
|
_tempManipulation.Length > 0 ? _tempManipulation : string.Empty, int.MaxValue);
|
|
|
|
DrawIntro(Ipc.RemoveTemporaryMod.Label, "Remove Temporary Mod from specific Collection");
|
|
if (ImGui.Button("Remove##Mod"))
|
|
_lastTempError = Ipc.RemoveTemporaryMod.Subscriber(_pi).Invoke(_tempModName, _tempCollectionName, int.MaxValue);
|
|
|
|
DrawIntro(Ipc.RemoveTemporaryModAll.Label, "Remove Temporary Mod from all Collections");
|
|
if (ImGui.Button("Remove##ModAll"))
|
|
_lastTempError = Ipc.RemoveTemporaryModAll.Subscriber(_pi).Invoke(_tempModName, int.MaxValue);
|
|
}
|
|
|
|
public void DrawCollections()
|
|
{
|
|
using var collTree = ImRaii.TreeNode("Temporary Collections##TempCollections");
|
|
if (!collTree)
|
|
return;
|
|
|
|
using var table = ImRaii.Table("##collTree", 5);
|
|
if (!table)
|
|
return;
|
|
|
|
foreach (var collection in _tempCollections.Values)
|
|
{
|
|
ImGui.TableNextColumn();
|
|
var character = _tempCollections.Collections.Where(p => p.Collection == collection).Select(p => p.DisplayName)
|
|
.FirstOrDefault()
|
|
?? "Unknown";
|
|
if (ImGui.Button($"Save##{collection.Name}"))
|
|
TemporaryMod.SaveTempCollection(_config, _saveService, _modManager, collection, character);
|
|
|
|
ImGuiUtil.DrawTableColumn(collection.Name);
|
|
ImGuiUtil.DrawTableColumn(collection.ResolvedFiles.Count.ToString());
|
|
ImGuiUtil.DrawTableColumn(collection.MetaCache?.Count.ToString() ?? "0");
|
|
ImGuiUtil.DrawTableColumn(string.Join(", ",
|
|
_tempCollections.Collections.Where(p => p.Collection == collection).Select(c => c.DisplayName)));
|
|
}
|
|
}
|
|
|
|
public void DrawMods()
|
|
{
|
|
using var modTree = ImRaii.TreeNode("Temporary Mods##TempMods");
|
|
if (!modTree)
|
|
return;
|
|
|
|
using var table = ImRaii.Table("##modTree", 5);
|
|
|
|
void PrintList(string collectionName, IReadOnlyList<TemporaryMod> list)
|
|
{
|
|
foreach (var mod in list)
|
|
{
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(mod.Name);
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(mod.Priority.ToString());
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(collectionName);
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(mod.Default.Files.Count.ToString());
|
|
if (ImGui.IsItemHovered())
|
|
{
|
|
using var tt = ImRaii.Tooltip();
|
|
foreach (var (path, file) in mod.Default.Files)
|
|
ImGui.TextUnformatted($"{path} -> {file}");
|
|
}
|
|
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(mod.TotalManipulations.ToString());
|
|
if (ImGui.IsItemHovered())
|
|
{
|
|
using var tt = ImRaii.Tooltip();
|
|
foreach (var manip in mod.Default.Manipulations)
|
|
ImGui.TextUnformatted(manip.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (table)
|
|
{
|
|
PrintList("All", _tempMods.ModsForAllCollections);
|
|
foreach (var (collection, list) in _tempMods.Mods)
|
|
PrintList(collection.Name, list);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class ResourceTree
|
|
{
|
|
private readonly DalamudPluginInterface _pi;
|
|
private readonly IObjectTable _objects;
|
|
|
|
private string _gameObjectIndices = "0";
|
|
private ResourceType _type = ResourceType.Mtrl;
|
|
private bool _withUIData = false;
|
|
|
|
private (string, IReadOnlyDictionary<string, string[]>?)[]? _lastGameObjectResourcePaths;
|
|
private (string, IReadOnlyDictionary<string, string[]>?)[]? _lastPlayerResourcePaths;
|
|
private (string, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)[]? _lastGameObjectResourcesOfType;
|
|
private (string, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)[]? _lastPlayerResourcesOfType;
|
|
|
|
public ResourceTree(DalamudPluginInterface pi, IObjectTable objects)
|
|
{
|
|
_pi = pi;
|
|
_objects = objects;
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
using var _ = ImRaii.TreeNode("Resource Tree");
|
|
if (!_)
|
|
return;
|
|
|
|
ImGui.InputText("GameObject indices", ref _gameObjectIndices, 511);
|
|
ImGuiUtil.GenericEnumCombo("Resource type", ImGui.CalcItemWidth(), _type, out _type, Enum.GetValues<ResourceType>());
|
|
ImGui.Checkbox("Also get names and icons", ref _withUIData);
|
|
|
|
using var table = ImRaii.Table(string.Empty, 3, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
DrawIntro(Ipc.GetGameObjectResourcePaths.Label, "Get GameObject resource paths");
|
|
if (ImGui.Button("Get##GameObjectResourcePaths"))
|
|
{
|
|
var gameObjects = GetSelectedGameObjects();
|
|
var resourcePaths = Ipc.GetGameObjectResourcePaths.Subscriber(_pi).Invoke(gameObjects);
|
|
|
|
_lastGameObjectResourcePaths = gameObjects
|
|
.Select(GameObjectToString)
|
|
.Zip(resourcePaths)
|
|
.ToArray();
|
|
|
|
ImGui.OpenPopup(nameof(Ipc.GetGameObjectResourcePaths));
|
|
}
|
|
|
|
DrawIntro(Ipc.GetPlayerResourcePaths.Label, "Get local player resource paths");
|
|
if (ImGui.Button("Get##PlayerResourcePaths"))
|
|
{
|
|
_lastPlayerResourcePaths = Ipc.GetPlayerResourcePaths.Subscriber(_pi).Invoke()
|
|
.Select(pair => (GameObjectToString(pair.Key), (IReadOnlyDictionary<string, string[]>?)pair.Value))
|
|
.ToArray();
|
|
|
|
ImGui.OpenPopup(nameof(Ipc.GetPlayerResourcePaths));
|
|
}
|
|
|
|
DrawIntro(Ipc.GetGameObjectResourcesOfType.Label, "Get GameObject resources of type");
|
|
if (ImGui.Button("Get##GameObjectResourcesOfType"))
|
|
{
|
|
var gameObjects = GetSelectedGameObjects();
|
|
var resourcesOfType = Ipc.GetGameObjectResourcesOfType.Subscriber(_pi).Invoke(gameObjects, _type, _withUIData);
|
|
|
|
_lastGameObjectResourcesOfType = gameObjects
|
|
.Select(GameObjectToString)
|
|
.Zip(resourcesOfType)
|
|
.ToArray();
|
|
|
|
ImGui.OpenPopup(nameof(Ipc.GetGameObjectResourcesOfType));
|
|
}
|
|
|
|
DrawIntro(Ipc.GetPlayerResourcesOfType.Label, "Get local player resources of type");
|
|
if (ImGui.Button("Get##PlayerResourcesOfType"))
|
|
{
|
|
_lastPlayerResourcesOfType = Ipc.GetPlayerResourcesOfType.Subscriber(_pi).Invoke(_type, _withUIData)
|
|
.Select(pair => (GameObjectToString(pair.Key), (IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)pair.Value))
|
|
.ToArray();
|
|
|
|
ImGui.OpenPopup(nameof(Ipc.GetPlayerResourcesOfType));
|
|
}
|
|
|
|
DrawPopup(nameof(Ipc.GetGameObjectResourcePaths), ref _lastGameObjectResourcePaths, DrawResourcePaths);
|
|
DrawPopup(nameof(Ipc.GetPlayerResourcePaths), ref _lastPlayerResourcePaths, DrawResourcePaths);
|
|
|
|
DrawPopup(nameof(Ipc.GetGameObjectResourcesOfType), ref _lastGameObjectResourcesOfType, DrawResourcesOfType);
|
|
DrawPopup(nameof(Ipc.GetPlayerResourcesOfType), ref _lastPlayerResourcesOfType, DrawResourcesOfType);
|
|
}
|
|
|
|
private static void DrawPopup<T>(string popupId, ref T? result, Action<T> drawResult) where T : class
|
|
{
|
|
ImGui.SetNextWindowSize(ImGuiHelpers.ScaledVector2(1000, 500));
|
|
using var popup = ImRaii.Popup(popupId);
|
|
if (!popup)
|
|
{
|
|
result = null;
|
|
return;
|
|
}
|
|
|
|
if (result == null)
|
|
{
|
|
ImGui.CloseCurrentPopup();
|
|
return;
|
|
}
|
|
|
|
drawResult(result);
|
|
|
|
if (ImGui.Button("Close", -Vector2.UnitX) || !ImGui.IsWindowFocused())
|
|
{
|
|
result = null;
|
|
ImGui.CloseCurrentPopup();
|
|
}
|
|
}
|
|
|
|
private static void DrawWithHeaders<T>((string, T?)[] result, Action<T> drawItem) where T : class
|
|
{
|
|
var firstSeen = new Dictionary<T, string>();
|
|
foreach (var (label, item) in result)
|
|
{
|
|
if (item == null)
|
|
{
|
|
ImRaii.TreeNode($"{label}: null", ImGuiTreeNodeFlags.Leaf).Dispose();
|
|
continue;
|
|
}
|
|
|
|
if (firstSeen.TryGetValue(item, out var firstLabel))
|
|
{
|
|
ImRaii.TreeNode($"{label}: same as {firstLabel}", ImGuiTreeNodeFlags.Leaf).Dispose();
|
|
continue;
|
|
}
|
|
|
|
firstSeen.Add(item, label);
|
|
|
|
using var header = ImRaii.TreeNode(label);
|
|
if (!header)
|
|
continue;
|
|
|
|
drawItem(item);
|
|
}
|
|
}
|
|
|
|
private static void DrawResourcePaths((string, IReadOnlyDictionary<string, string[]>?)[] result)
|
|
{
|
|
DrawWithHeaders(result, paths =>
|
|
{
|
|
using var table = ImRaii.Table(string.Empty, 2, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, 0.6f);
|
|
ImGui.TableSetupColumn("Game Paths", ImGuiTableColumnFlags.WidthStretch, 0.4f);
|
|
ImGui.TableHeadersRow();
|
|
|
|
foreach (var (actualPath, gamePaths) in paths)
|
|
{
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(actualPath);
|
|
ImGui.TableNextColumn();
|
|
foreach (var gamePath in gamePaths)
|
|
ImGui.TextUnformatted(gamePath);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void DrawResourcesOfType((string, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)[] result)
|
|
{
|
|
DrawWithHeaders(result, resources =>
|
|
{
|
|
using var table = ImRaii.Table(string.Empty, _withUIData ? 3 : 2, ImGuiTableFlags.SizingFixedFit);
|
|
if (!table)
|
|
return;
|
|
|
|
ImGui.TableSetupColumn("Resource Handle", ImGuiTableColumnFlags.WidthStretch, 0.15f);
|
|
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, _withUIData ? 0.55f : 0.85f);
|
|
if (_withUIData)
|
|
ImGui.TableSetupColumn("Icon & Name", ImGuiTableColumnFlags.WidthStretch, 0.3f);
|
|
ImGui.TableHeadersRow();
|
|
|
|
foreach (var (resourceHandle, (actualPath, name, icon)) in resources)
|
|
{
|
|
ImGui.TableNextColumn();
|
|
TextUnformattedMono($"0x{resourceHandle:X}");
|
|
ImGui.TableNextColumn();
|
|
ImGui.TextUnformatted(actualPath);
|
|
if (_withUIData)
|
|
{
|
|
ImGui.TableNextColumn();
|
|
TextUnformattedMono(icon.ToString());
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(name);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private static void TextUnformattedMono(string text)
|
|
{
|
|
using var _ = ImRaii.PushFont(UiBuilder.MonoFont);
|
|
ImGui.TextUnformatted(text);
|
|
}
|
|
|
|
private ushort[] GetSelectedGameObjects()
|
|
=> _gameObjectIndices.Split(',')
|
|
.SelectWhere(index => (ushort.TryParse(index.Trim(), out var i), i))
|
|
.ToArray();
|
|
|
|
private unsafe string GameObjectToString(ushort gameObjectIndex)
|
|
{
|
|
var gameObject = _objects[gameObjectIndex];
|
|
|
|
return gameObject != null
|
|
? $"[{gameObjectIndex}] {gameObject.Name} ({gameObject.ObjectKind})"
|
|
: $"[{gameObjectIndex}] null";
|
|
}
|
|
}
|
|
}
|