/xldata window refactor (#1257)

Reworks the `/xldata` window so that each individual section is in its own file.
This commit is contained in:
MidoriKami 2023-06-23 10:54:40 -07:00 committed by GitHub
parent 11ea64410e
commit 694159a510
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 2701 additions and 1893 deletions

View file

@ -16,6 +16,7 @@ using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.Windows;
using Dalamud.Interface.Internal.Windows.Data;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Internal.Windows.SelfTest;
using Dalamud.Interface.Internal.Windows.Settings;

View file

@ -53,8 +53,6 @@ internal unsafe class UiDebug
{
}
private delegate AtkStage* GetAtkStageSingleton();
/// <summary>
/// Renders this window.
/// </summary>
@ -165,7 +163,7 @@ internal unsafe class UiDebug
private void PrintSimpleNode(AtkResNode* node, string treePrefix)
{
var popped = false;
var isVisible = (node->Flags & 0x10) == 0x10;
var isVisible = node->NodeFlags.HasFlag(NodeFlags.Visible);
if (isVisible)
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0, 255, 0, 255));
@ -296,7 +294,7 @@ internal unsafe class UiDebug
var compNode = (AtkComponentNode*)node;
var popped = false;
var isVisible = (node->Flags & 0x10) == 0x10;
var isVisible = node->NodeFlags.HasFlag(NodeFlags.Visible);
var componentInfo = compNode->Component->UldManager;
@ -396,7 +394,7 @@ internal unsafe class UiDebug
ImGui.SameLine();
if (ImGui.SmallButton($"T:Visible##{(ulong)node:X}"))
{
node->Flags ^= 0x10;
node->NodeFlags ^= NodeFlags.Visible;
}
ImGui.SameLine();
@ -573,7 +571,7 @@ internal unsafe class UiDebug
if (node == null) return false;
while (node != null)
{
if ((node->Flags & (short)NodeFlags.Visible) != (short)NodeFlags.Visible) return false;
if (!node->NodeFlags.HasFlag(NodeFlags.Visible)) return false;
node = node->ParentNode;
}

View file

@ -0,0 +1,158 @@
// ReSharper disable InconsistentNaming // Naming is suppressed so we can replace '_' with ' '
namespace Dalamud.Interface.Internal.Windows;
/// <summary>
/// Enum representing a DataKind for the Data Window.
/// </summary>
internal enum DataKind
{
/// <summary>
/// Server Opcode Display.
/// </summary>
Server_OpCode,
/// <summary>
/// Address.
/// </summary>
Address,
/// <summary>
/// Object Table.
/// </summary>
Object_Table,
/// <summary>
/// Fate Table.
/// </summary>
Fate_Table,
/// <summary>
/// SE Font Test.
/// </summary>
SE_Font_Test,
/// <summary>
/// FontAwesome Test.
/// </summary>
FontAwesome_Test,
/// <summary>
/// Party List.
/// </summary>
Party_List,
/// <summary>
/// Buddy List.
/// </summary>
Buddy_List,
/// <summary>
/// Plugin IPC Test.
/// </summary>
Plugin_IPC,
/// <summary>
/// Player Condition.
/// </summary>
Condition,
/// <summary>
/// Gauge.
/// </summary>
Gauge,
/// <summary>
/// Command.
/// </summary>
Command,
/// <summary>
/// Addon.
/// </summary>
Addon,
/// <summary>
/// Addon Inspector.
/// </summary>
Addon_Inspector,
/// <summary>
/// AtkArrayData Browser.
/// </summary>
AtkArrayData_Browser,
/// <summary>
/// StartInfo.
/// </summary>
StartInfo,
/// <summary>
/// Target.
/// </summary>
Target,
/// <summary>
/// Toast.
/// </summary>
Toast,
/// <summary>
/// Fly Text.
/// </summary>
FlyText,
/// <summary>
/// ImGui.
/// </summary>
ImGui,
/// <summary>
/// Tex.
/// </summary>
Tex,
/// <summary>
/// KeyState.
/// </summary>
KeyState,
/// <summary>
/// GamePad.
/// </summary>
Gamepad,
/// <summary>
/// Configuration.
/// </summary>
Configuration,
/// <summary>
/// Task Scheduler.
/// </summary>
TaskSched,
/// <summary>
/// Hook.
/// </summary>
Hook,
/// <summary>
/// Aetherytes.
/// </summary>
Aetherytes,
/// <summary>
/// DTR Bar.
/// </summary>
Dtr_Bar,
/// <summary>
/// UIColor.
/// </summary>
UIColor,
/// <summary>
/// Data Share.
/// </summary>
DataShare,
}

View file

@ -0,0 +1,191 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.Gui;
using Dalamud.Interface.Components;
using Dalamud.Interface.Windowing;
using ImGuiNET;
using Serilog;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Class responsible for drawing the data/debug window.
/// </summary>
internal class DataWindow : Window
{
private readonly IDataWindowWidget[] modules =
{
new ServerOpcodeWidget(),
new AddressesWidget(),
new ObjectTableWidget(),
new FateTableWidget(),
new SeFontTestWidget(),
new FontAwesomeTestWidget(),
new PartyListWidget(),
new BuddyListWidget(),
new PluginIpcWidget(),
new ConditionWidget(),
new GaugeWidget(),
new CommandWidget(),
new AddonWidget(),
new AddonInspectorWidget(),
new AtkArrayDataBrowserWidget(),
new StartInfoWidget(),
new TargetWidget(),
new ToastWidget(),
new FlyTextWidget(),
new ImGuiWidget(),
new TexWidget(),
new KeyStateWidget(),
new GamepadWidget(),
new ConfigurationWidget(),
new TaskSchedulerWidget(),
new HookWidget(),
new AetherytesWidget(),
new DtrBarWidget(),
new UIColorWidget(),
new DataShareWidget(),
};
private readonly Dictionary<DataKind, string> dataKindNames = new();
private bool isExcept;
private DataKind currentKind;
/// <summary>
/// Initializes a new instance of the <see cref="DataWindow"/> class.
/// </summary>
public DataWindow()
: base("Dalamud Data")
{
this.Size = new Vector2(500, 500);
this.SizeCondition = ImGuiCond.FirstUseEver;
this.RespectCloseHotkey = false;
foreach (var dataKind in Enum.GetValues<DataKind>())
{
this.dataKindNames[dataKind] = dataKind.ToString().Replace("_", " ");
}
this.Load();
}
/// <inheritdoc/>
public override void OnOpen()
{
}
/// <inheritdoc/>
public override void OnClose()
{
}
/// <summary>
/// Set the DataKind dropdown menu.
/// </summary>
/// <param name="dataKind">Data kind name, can be lower and/or without spaces.</param>
public void SetDataKind(string dataKind)
{
if (string.IsNullOrEmpty(dataKind))
return;
dataKind = dataKind switch
{
"ai" => "Addon Inspector",
"at" => "Object Table", // Actor Table
"ot" => "Object Table",
"uic" => "UIColor",
_ => dataKind,
};
dataKind = dataKind.Replace(" ", string.Empty).ToLower();
var matched = Enum
.GetValues<DataKind>()
.FirstOrDefault(kind => Enum.GetName(kind)?.Replace("_", string.Empty).ToLower() == dataKind);
if (matched != default)
{
this.currentKind = matched;
}
else
{
Service<ChatGui>.Get().PrintError($"/xldata: Invalid data type {dataKind}");
}
}
/// <summary>
/// Draw the window via ImGui.
/// </summary>
public override void Draw()
{
if (ImGuiComponents.IconButton("forceReload", FontAwesomeIcon.Sync)) this.Load();
if (ImGui.IsItemHovered()) ImGui.SetTooltip("Force Reload");
ImGui.SameLine();
var copy = ImGuiComponents.IconButton("copyAll", FontAwesomeIcon.ClipboardList);
if (ImGui.IsItemHovered()) ImGui.SetTooltip("Copy All");
ImGui.SameLine();
ImGui.SetNextItemWidth(275.0f * ImGuiHelpers.GlobalScale);
if (ImGui.BeginCombo("Data Kind", this.dataKindNames[this.currentKind]))
{
foreach (var module in this.modules.OrderBy(module => this.dataKindNames[module.DataKind]))
{
if (ImGui.Selectable(this.dataKindNames[module.DataKind], this.currentKind == module.DataKind))
{
this.currentKind = module.DataKind;
}
}
ImGui.EndCombo();
}
ImGuiHelpers.ScaledDummy(10.0f);
ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.HorizontalScrollbar);
if (copy)
ImGui.LogToClipboard();
try
{
var selectedWidget = this.modules.FirstOrDefault(dataWindowWidget => dataWindowWidget.DataKind == this.currentKind);
if (selectedWidget is { Ready: true })
{
selectedWidget.Draw();
}
else
{
ImGui.TextUnformatted("Data not ready.");
}
this.isExcept = false;
}
catch (Exception ex)
{
if (!this.isExcept)
{
Log.Error(ex, "Could not draw data");
}
this.isExcept = true;
ImGui.TextUnformatted(ex.ToString());
}
ImGui.EndChild();
}
private void Load()
{
foreach (var widget in this.modules)
{
widget.Load();
}
}
}

View file

@ -0,0 +1,27 @@
namespace Dalamud.Interface.Internal.Windows;
/// <summary>
/// Class representing a date window entry.
/// </summary>
internal interface IDataWindowWidget
{
/// <summary>
/// Gets the Data Kind for this data window module.
/// </summary>
DataKind DataKind { get; init; }
/// <summary>
/// Gets or sets a value indicating whether this data window module is ready.
/// </summary>
bool Ready { get; protected set; }
/// <summary>
/// Loads the necessary data for this data window module.
/// </summary>
void Load();
/// <summary>
/// Draws this data window module.
/// </summary>
void Draw();
}

View file

@ -0,0 +1,32 @@
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying addon inspector.
/// </summary>
internal class AddonInspectorWidget : IDataWindowWidget
{
private UiDebug? addonInspector;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Addon_Inspector;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.addonInspector = new UiDebug();
if (this.addonInspector is not null)
{
this.Ready = true;
}
}
/// <inheritdoc/>
public void Draw()
{
this.addonInspector?.Draw();
}
}

View file

@ -0,0 +1,66 @@
using Dalamud.Game.Gui;
using Dalamud.Memory;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying Addon Data.
/// </summary>
internal unsafe class AddonWidget : IDataWindowWidget
{
private string inputAddonName = string.Empty;
private int inputAddonIndex;
private nint findAgentInterfacePtr;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Addon;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var gameGui = Service<GameGui>.Get();
ImGui.InputText("Addon Name", ref this.inputAddonName, 256);
ImGui.InputInt("Addon Index", ref this.inputAddonIndex);
if (this.inputAddonName.IsNullOrEmpty())
return;
var address = gameGui.GetAddonByName(this.inputAddonName, this.inputAddonIndex);
if (address == nint.Zero)
{
ImGui.Text("Null");
return;
}
var addon = (FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase*)address;
var name = MemoryHelper.ReadStringNullTerminated((nint)addon->Name);
ImGui.TextUnformatted($"{name} - 0x{address.ToInt64():X}\n v:{addon->IsVisible} x:{addon->X} y:{addon->Y} s:{addon->Scale}, w:{addon->RootNode->Width}, h:{addon->RootNode->Height}");
if (ImGui.Button("Find Agent"))
{
this.findAgentInterfacePtr = gameGui.FindAgentInterface(address);
}
if (this.findAgentInterfacePtr != nint.Zero)
{
ImGui.TextUnformatted($"Agent: 0x{this.findAgentInterfacePtr.ToInt64():X}");
ImGui.SameLine();
if (ImGui.Button("C"))
ImGui.SetClipboardText(this.findAgentInterfacePtr.ToInt64().ToString("X"));
}
}
}

View file

@ -0,0 +1,64 @@
using System.Collections.Generic;
using Dalamud.Game;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget to display resolved .text sigs.
/// </summary>
internal class AddressesWidget : IDataWindowWidget
{
private string inputSig = string.Empty;
private nint sigResult = nint.Zero;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Address;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
ImGui.InputText(".text sig", ref this.inputSig, 400);
if (ImGui.Button("Resolve"))
{
try
{
var sigScanner = Service<SigScanner>.Get();
this.sigResult = sigScanner.ScanText(this.inputSig);
}
catch (KeyNotFoundException)
{
this.sigResult = new nint(-1);
}
}
ImGui.Text($"Result: {this.sigResult.ToInt64():X}");
ImGui.SameLine();
if (ImGui.Button($"C##{this.sigResult.ToInt64():X}"))
ImGui.SetClipboardText(this.sigResult.ToInt64().ToString("X"));
foreach (var debugScannedValue in BaseAddressResolver.DebugScannedValues)
{
ImGui.TextUnformatted($"{debugScannedValue.Key}");
foreach (var valueTuple in debugScannedValue.Value)
{
ImGui.TextUnformatted(
$" {valueTuple.ClassName} - 0x{valueTuple.Address.ToInt64():X}");
ImGui.SameLine();
if (ImGui.Button($"C##{valueTuple.Address.ToInt64():X}"))
ImGui.SetClipboardText(valueTuple.Address.ToInt64().ToString("X"));
}
}
}
}

View file

@ -0,0 +1,87 @@
using Dalamud.Game.ClientState.Aetherytes;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying aetheryte table.
/// </summary>
internal class AetherytesWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Aetherytes;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
if (!ImGui.BeginTable("##aetheryteTable", 11, ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders))
return;
ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableSetupColumn("Idx", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("ID", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Zone", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Ward", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Plot", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Sub", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Gil", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Fav", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Shared", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Apartment", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableHeadersRow();
var tpList = Service<AetheryteList>.Get();
for (var i = 0; i < tpList.Length; i++)
{
var info = tpList[i];
if (info == null)
continue;
ImGui.TableNextColumn(); // Idx
ImGui.TextUnformatted($"{i}");
ImGui.TableNextColumn(); // Name
ImGui.TextUnformatted($"{info.AetheryteData.GameData?.PlaceName.Value?.Name}");
ImGui.TableNextColumn(); // ID
ImGui.TextUnformatted($"{info.AetheryteId}");
ImGui.TableNextColumn(); // Zone
ImGui.TextUnformatted($"{info.TerritoryId}");
ImGui.TableNextColumn(); // Ward
ImGui.TextUnformatted($"{info.Ward}");
ImGui.TableNextColumn(); // Plot
ImGui.TextUnformatted($"{info.Plot}");
ImGui.TableNextColumn(); // Sub
ImGui.TextUnformatted($"{info.SubIndex}");
ImGui.TableNextColumn(); // Gil
ImGui.TextUnformatted($"{info.GilCost}");
ImGui.TableNextColumn(); // Favourite
ImGui.TextUnformatted($"{info.IsFavourite}");
ImGui.TableNextColumn(); // Shared
ImGui.TextUnformatted($"{info.IsSharedHouse}");
ImGui.TableNextColumn(); // Apartment
ImGui.TextUnformatted($"{info.IsAppartment}");
}
ImGui.EndTable();
}
}

View file

@ -0,0 +1,173 @@
using System;
using System.Numerics;
using Dalamud.Memory;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying AtkArrayData.
/// </summary>
internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.AtkArrayData_Browser;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var fontWidth = ImGui.CalcTextSize("A").X;
var fontHeight = ImGui.GetTextLineHeightWithSpacing();
var uiModule = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance()->GetUiModule();
if (uiModule == null)
{
ImGui.Text("UIModule unavailable.");
return;
}
var atkArrayDataHolder = &uiModule->GetRaptureAtkModule()->AtkModule.AtkArrayDataHolder;
if (ImGui.BeginTabBar("AtkArrayDataBrowserTabBar"))
{
if (ImGui.BeginTabItem($"NumberArrayData [{atkArrayDataHolder->NumberArrayCount}]"))
{
if (ImGui.BeginTable("NumberArrayDataTable", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY))
{
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed, fontWidth * 10);
ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, fontWidth * 10);
ImGui.TableSetupColumn("Pointer", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
for (var numberArrayIndex = 0; numberArrayIndex < atkArrayDataHolder->NumberArrayCount; numberArrayIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text($"{numberArrayIndex} [{numberArrayIndex * 8:X}]");
ImGui.TableNextColumn();
var numberArrayData = atkArrayDataHolder->NumberArrays[numberArrayIndex];
if (numberArrayData != null)
{
ImGui.Text($"{numberArrayData->AtkArrayData.Size}");
ImGui.TableNextColumn();
if (ImGui.TreeNodeEx($"{(long)numberArrayData:X}###{numberArrayIndex}", ImGuiTreeNodeFlags.SpanFullWidth))
{
ImGui.NewLine();
var tableHeight = Math.Min(40, numberArrayData->AtkArrayData.Size + 4);
if (ImGui.BeginTable($"NumberArrayDataTable", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, new Vector2(0.0F, fontHeight * tableHeight)))
{
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed, fontWidth * 6);
ImGui.TableSetupColumn("Hex", ImGuiTableColumnFlags.WidthFixed, fontWidth * 9);
ImGui.TableSetupColumn("Integer", ImGuiTableColumnFlags.WidthFixed, fontWidth * 12);
ImGui.TableSetupColumn("Float", ImGuiTableColumnFlags.WidthFixed, fontWidth * 20);
ImGui.TableHeadersRow();
for (var numberIndex = 0; numberIndex < numberArrayData->AtkArrayData.Size; numberIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text($"{numberIndex}");
ImGui.TableNextColumn();
ImGui.Text($"{numberArrayData->IntArray[numberIndex]:X}");
ImGui.TableNextColumn();
ImGui.Text($"{numberArrayData->IntArray[numberIndex]}");
ImGui.TableNextColumn();
ImGui.Text($"{*(float*)&numberArrayData->IntArray[numberIndex]}");
}
ImGui.EndTable();
}
ImGui.TreePop();
}
}
else
{
ImGui.TextDisabled("--");
ImGui.TableNextColumn();
ImGui.TextDisabled("--");
}
}
ImGui.EndTable();
}
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem($"StringArrayData [{atkArrayDataHolder->StringArrayCount}]"))
{
if (ImGui.BeginTable("StringArrayDataTable", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY))
{
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed, fontWidth * 10);
ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, fontWidth * 10);
ImGui.TableSetupColumn("Pointer", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
for (var stringArrayIndex = 0; stringArrayIndex < atkArrayDataHolder->StringArrayCount; stringArrayIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text($"{stringArrayIndex} [{stringArrayIndex * 8:X}]");
ImGui.TableNextColumn();
var stringArrayData = atkArrayDataHolder->StringArrays[stringArrayIndex];
if (stringArrayData != null)
{
ImGui.Text($"{stringArrayData->AtkArrayData.Size}");
ImGui.TableNextColumn();
if (ImGui.TreeNodeEx($"{(long)stringArrayData:X}###{stringArrayIndex}", ImGuiTreeNodeFlags.SpanFullWidth))
{
ImGui.NewLine();
var tableHeight = Math.Min(40, stringArrayData->AtkArrayData.Size + 4);
if (ImGui.BeginTable($"StringArrayDataTable", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, new Vector2(0.0F, fontHeight * tableHeight)))
{
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed, fontWidth * 6);
ImGui.TableSetupColumn("String", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
for (var stringIndex = 0; stringIndex < stringArrayData->AtkArrayData.Size; stringIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text($"{stringIndex}");
ImGui.TableNextColumn();
if (stringArrayData->StringArray[stringIndex] != null)
{
ImGui.Text($"{MemoryHelper.ReadSeStringNullTerminated(new IntPtr(stringArrayData->StringArray[stringIndex]))}");
}
else
{
ImGui.TextDisabled("--");
}
}
ImGui.EndTable();
}
ImGui.TreePop();
}
}
else
{
ImGui.TextDisabled("--");
ImGui.TableNextColumn();
ImGui.TextDisabled("--");
}
}
ImGui.EndTable();
}
ImGui.EndTabItem();
}
ImGui.EndTabBar();
}
}
}

View file

@ -0,0 +1,110 @@
using Dalamud.Game.ClientState.Buddy;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying data about the Buddy List.
/// </summary>
internal class BuddyListWidget : IDataWindowWidget
{
private bool resolveGameData;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Buddy_List;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var buddyList = Service<BuddyList>.Get();
ImGui.Checkbox("Resolve GameData", ref this.resolveGameData);
ImGui.Text($"BuddyList: {buddyList.BuddyListAddress.ToInt64():X}");
{
var member = buddyList.CompanionBuddy;
if (member == null)
{
ImGui.Text("[Companion] null");
}
else
{
ImGui.Text($"[Companion] {member.Address.ToInt64():X} - {member.ObjectId} - {member.DataID}");
if (this.resolveGameData)
{
var gameObject = member.GameObject;
if (gameObject == null)
{
ImGui.Text("GameObject was null");
}
else
{
Util.PrintGameObject(gameObject, "-", this.resolveGameData);
}
}
}
}
{
var member = buddyList.PetBuddy;
if (member == null)
{
ImGui.Text("[Pet] null");
}
else
{
ImGui.Text($"[Pet] {member.Address.ToInt64():X} - {member.ObjectId} - {member.DataID}");
if (this.resolveGameData)
{
var gameObject = member.GameObject;
if (gameObject == null)
{
ImGui.Text("GameObject was null");
}
else
{
Util.PrintGameObject(gameObject, "-", this.resolveGameData);
}
}
}
}
{
var count = buddyList.Length;
if (count == 0)
{
ImGui.Text("[BattleBuddy] None present");
}
else
{
for (var i = 0; i < count; i++)
{
var member = buddyList[i];
ImGui.Text($"[BattleBuddy] [{i}] {member?.Address.ToInt64():X} - {member?.ObjectId} - {member?.DataID}");
if (this.resolveGameData)
{
var gameObject = member?.GameObject;
if (gameObject == null)
{
ImGui.Text("GameObject was null");
}
else
{
Util.PrintGameObject(gameObject, "-", this.resolveGameData);
}
}
}
}
}
}
}

View file

@ -0,0 +1,33 @@
using Dalamud.Game.Command;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying command info.
/// </summary>
internal class CommandWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Command;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var commandManager = Service<CommandManager>.Get();
foreach (var command in commandManager.Commands)
{
ImGui.Text($"{command.Key}\n -> {command.Value.HelpMessage}\n -> In help: {command.Value.ShowInHelp}\n\n");
}
}
}

View file

@ -0,0 +1,52 @@
using Dalamud.Game.ClientState.Conditions;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying current character condition flags.
/// </summary>
internal class ConditionWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Condition;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var condition = Service<Condition>.Get();
#if DEBUG
ImGui.Text($"ptr: 0x{condition.Address.ToInt64():X}");
#endif
ImGui.Text("Current Conditions:");
ImGui.Separator();
var didAny = false;
for (var i = 0; i < Condition.MaxConditionEntries; i++)
{
var typedCondition = (ConditionFlag)i;
var cond = condition[typedCondition];
if (!cond) continue;
didAny = true;
ImGui.Text($"ID: {i} Enum: {typedCondition}");
}
if (!didAny)
ImGui.Text("None. Talk to a shop NPC or visit a market board to find out more!");
}
}

View file

@ -0,0 +1,29 @@
using Dalamud.Configuration.Internal;
using Dalamud.Utility;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying configuration info.
/// </summary>
internal class ConfigurationWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Configuration;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var config = Service<DalamudConfiguration>.Get();
Util.ShowObject(config);
}
}

View file

@ -0,0 +1,53 @@
using Dalamud.Plugin.Ipc.Internal;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying plugin data share modules.
/// </summary>
internal class DataShareWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.DataShare;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
if (!ImGui.BeginTable("###DataShareTable", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg))
return;
try
{
ImGui.TableSetupColumn("Shared Tag");
ImGui.TableSetupColumn("Creator Assembly");
ImGui.TableSetupColumn("#", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Consumers");
ImGui.TableHeadersRow();
foreach (var share in Service<DataShare>.Get().GetAllShares())
{
ImGui.TableNextColumn();
ImGui.TextUnformatted(share.Tag);
ImGui.TableNextColumn();
ImGui.TextUnformatted(share.CreatorAssembly);
ImGui.TableNextColumn();
ImGui.TextUnformatted(share.Users.Length.ToString());
ImGui.TableNextColumn();
ImGui.TextUnformatted(string.Join(", ", share.Users));
}
}
finally
{
ImGui.EndTable();
}
}
}

View file

@ -0,0 +1,80 @@
using Dalamud.Configuration.Internal;
using Dalamud.Game.Gui.Dtr;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying dtr test.
/// </summary>
internal class DtrBarWidget : IDataWindowWidget
{
private DtrBarEntry? dtrTest1;
private DtrBarEntry? dtrTest2;
private DtrBarEntry? dtrTest3;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Dtr_Bar;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
this.DrawDtrTestEntry(ref this.dtrTest1, "DTR Test #1");
ImGui.Separator();
this.DrawDtrTestEntry(ref this.dtrTest2, "DTR Test #2");
ImGui.Separator();
this.DrawDtrTestEntry(ref this.dtrTest3, "DTR Test #3");
ImGui.Separator();
var configuration = Service<DalamudConfiguration>.Get();
if (configuration.DtrOrder != null)
{
ImGui.Separator();
foreach (var order in configuration.DtrOrder)
{
ImGui.Text(order);
}
}
}
private void DrawDtrTestEntry(ref DtrBarEntry? entry, string title)
{
var dtrBar = Service<DtrBar>.Get();
if (entry != null)
{
ImGui.Text(title);
var text = entry.Text?.TextValue ?? string.Empty;
if (ImGui.InputText($"Text###{entry.Title}t", ref text, 255))
entry.Text = text;
var shown = entry.Shown;
if (ImGui.Checkbox($"Shown###{entry.Title}s", ref shown))
entry.Shown = shown;
if (ImGui.Button($"Remove###{entry.Title}r"))
{
entry.Remove();
entry = null;
}
}
else
{
if (ImGui.Button($"Add###{title}"))
{
entry = dtrBar.Get(title, title);
}
}
}
}

View file

@ -0,0 +1,68 @@
using Dalamud.Game.ClientState.Fates;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying the Fate Table.
/// </summary>
internal class FateTableWidget : IDataWindowWidget
{
private bool resolveGameData;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Fate_Table;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
ImGui.Checkbox("Resolve GameData", ref this.resolveGameData);
var fateTable = Service<FateTable>.Get();
var stateString = string.Empty;
if (fateTable.Length == 0)
{
ImGui.TextUnformatted("No fates or data not ready.");
}
else
{
stateString += $"FateTableLen: {fateTable.Length}\n";
ImGui.TextUnformatted(stateString);
for (var i = 0; i < fateTable.Length; i++)
{
var fate = fateTable[i];
if (fate == null)
continue;
var fateString = $"{fate.Address.ToInt64():X}:[{i}]" +
$" - Lv.{fate.Level} {fate.Name} ({fate.Progress}%)" +
$" - X{fate.Position.X} Y{fate.Position.Y} Z{fate.Position.Z}" +
$" - Territory {(this.resolveGameData ? (fate.TerritoryType.GameData?.Name ?? fate.TerritoryType.Id.ToString()) : fate.TerritoryType.Id.ToString())}\n";
fateString += $" StartTimeEpoch: {fate.StartTimeEpoch}" +
$" - Duration: {fate.Duration}" +
$" - State: {fate.State}" +
$" - GameData name: {(this.resolveGameData ? (fate.GameData.Name ?? fate.FateId.ToString()) : fate.FateId.ToString())}";
ImGui.TextUnformatted(fateString);
ImGui.SameLine();
if (ImGui.Button("C"))
{
ImGui.SetClipboardText(fate.Address.ToString("X"));
}
}
}
}
}

View file

@ -0,0 +1,77 @@
using System;
using System.Numerics;
using Dalamud.Game.Gui.FlyText;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying fly text info.
/// </summary>
internal class FlyTextWidget : IDataWindowWidget
{
private int flyActor;
private FlyTextKind flyKind;
private int flyVal1;
private int flyVal2;
private string flyText1 = string.Empty;
private string flyText2 = string.Empty;
private int flyIcon;
private int flyDmgIcon;
private Vector4 flyColor = new(1, 0, 0, 1);
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.FlyText;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
if (ImGui.BeginCombo("Kind", this.flyKind.ToString()))
{
var names = Enum.GetNames(typeof(FlyTextKind));
for (var i = 0; i < names.Length; i++)
{
if (ImGui.Selectable($"{names[i]} ({i})"))
this.flyKind = (FlyTextKind)i;
}
ImGui.EndCombo();
}
ImGui.InputText("Text1", ref this.flyText1, 200);
ImGui.InputText("Text2", ref this.flyText2, 200);
ImGui.InputInt("Val1", ref this.flyVal1);
ImGui.InputInt("Val2", ref this.flyVal2);
ImGui.InputInt("Icon ID", ref this.flyIcon);
ImGui.InputInt("Damage Icon ID", ref this.flyDmgIcon);
ImGui.ColorEdit4("Color", ref this.flyColor);
ImGui.InputInt("Actor Index", ref this.flyActor);
var sendColor = ImGui.ColorConvertFloat4ToU32(this.flyColor);
if (ImGui.Button("Send"))
{
Service<FlyTextGui>.Get().AddFlyText(
this.flyKind,
unchecked((uint)this.flyActor),
unchecked((uint)this.flyVal1),
unchecked((uint)this.flyVal2),
this.flyText1,
this.flyText2,
sendColor,
unchecked((uint)this.flyIcon),
unchecked((uint)this.flyDmgIcon));
}
}
}

View file

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget to display FontAwesome Symbols.
/// </summary>
internal class FontAwesomeTestWidget : IDataWindowWidget
{
private List<FontAwesomeIcon>? icons;
private List<string>? iconNames;
private string[]? iconCategories;
private int selectedIconCategory;
private string iconSearchInput = string.Empty;
private bool iconSearchChanged = true;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.FontAwesome_Test;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
this.iconCategories ??= FontAwesomeHelpers.GetCategories();
if (this.iconSearchChanged)
{
this.icons = FontAwesomeHelpers.SearchIcons(this.iconSearchInput, this.iconCategories[this.selectedIconCategory]);
this.iconNames = this.icons.Select(icon => Enum.GetName(icon)!).ToList();
this.iconSearchChanged = false;
}
ImGui.SetNextItemWidth(160f);
var categoryIndex = this.selectedIconCategory;
if (ImGui.Combo("####FontAwesomeCategorySearch", ref categoryIndex, this.iconCategories, this.iconCategories.Length))
{
this.selectedIconCategory = categoryIndex;
this.iconSearchChanged = true;
}
ImGui.SameLine(170f);
ImGui.SetNextItemWidth(180f);
if (ImGui.InputTextWithHint($"###FontAwesomeInputSearch", "search icons", ref this.iconSearchInput, 50))
{
this.iconSearchChanged = true;
}
ImGuiHelpers.ScaledDummy(10f);
for (var i = 0; i < this.icons?.Count; i++)
{
ImGui.Text($"0x{(int)this.icons[i].ToIconChar():X}");
ImGuiHelpers.ScaledRelativeSameLine(50f);
ImGui.Text($"{this.iconNames?[i]}");
ImGuiHelpers.ScaledRelativeSameLine(280f);
ImGui.PushFont(UiBuilder.IconFont);
ImGui.Text(this.icons[i].ToIconString());
ImGui.PopFont();
ImGuiHelpers.ScaledDummy(2f);
}
ImGui.PopStyleVar();
}
}

View file

@ -0,0 +1,86 @@
using System;
using Dalamud.Game.ClientState.GamePad;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying gamepad info.
/// </summary>
internal class GamepadWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Gamepad;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var gamepadState = Service<GamepadState>.Get();
static void DrawHelper(string text, uint mask, Func<GamepadButtons, float> resolve)
{
ImGui.Text($"{text} {mask:X4}");
ImGui.Text($"DPadLeft {resolve(GamepadButtons.DpadLeft)} " +
$"DPadUp {resolve(GamepadButtons.DpadUp)} " +
$"DPadRight {resolve(GamepadButtons.DpadRight)} " +
$"DPadDown {resolve(GamepadButtons.DpadDown)} ");
ImGui.Text($"West {resolve(GamepadButtons.West)} " +
$"North {resolve(GamepadButtons.North)} " +
$"East {resolve(GamepadButtons.East)} " +
$"South {resolve(GamepadButtons.South)} ");
ImGui.Text($"L1 {resolve(GamepadButtons.L1)} " +
$"L2 {resolve(GamepadButtons.L2)} " +
$"R1 {resolve(GamepadButtons.R1)} " +
$"R2 {resolve(GamepadButtons.R2)} ");
ImGui.Text($"Select {resolve(GamepadButtons.Select)} " +
$"Start {resolve(GamepadButtons.Start)} " +
$"L3 {resolve(GamepadButtons.L3)} " +
$"R3 {resolve(GamepadButtons.R3)} ");
}
ImGui.Text($"GamepadInput 0x{gamepadState.GamepadInputAddress.ToInt64():X}");
#if DEBUG
if (ImGui.IsItemHovered())
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
if (ImGui.IsItemClicked())
ImGui.SetClipboardText($"0x{gamepadState.GamepadInputAddress.ToInt64():X}");
#endif
DrawHelper(
"Buttons Raw",
gamepadState.ButtonsRaw,
gamepadState.Raw);
DrawHelper(
"Buttons Pressed",
gamepadState.ButtonsPressed,
gamepadState.Pressed);
DrawHelper(
"Buttons Repeat",
gamepadState.ButtonsRepeat,
gamepadState.Repeat);
DrawHelper(
"Buttons Released",
gamepadState.ButtonsReleased,
gamepadState.Released);
ImGui.Text($"LeftStickLeft {gamepadState.LeftStickLeft:0.00} " +
$"LeftStickUp {gamepadState.LeftStickUp:0.00} " +
$"LeftStickRight {gamepadState.LeftStickRight:0.00} " +
$"LeftStickDown {gamepadState.LeftStickDown:0.00} ");
ImGui.Text($"RightStickLeft {gamepadState.RightStickLeft:0.00} " +
$"RightStickUp {gamepadState.RightStickUp:0.00} " +
$"RightStickRight {gamepadState.RightStickRight:0.00} " +
$"RightStickDown {gamepadState.RightStickDown:0.00} ");
}
}

View file

@ -0,0 +1,72 @@
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.JobGauge;
using Dalamud.Game.ClientState.JobGauge.Types;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying job gauge data.
/// </summary>
internal class GaugeWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Gauge;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var clientState = Service<ClientState>.Get();
var jobGauges = Service<JobGauges>.Get();
var player = clientState.LocalPlayer;
if (player == null)
{
ImGui.Text("Player is not present");
return;
}
var jobID = player.ClassJob.Id;
JobGaugeBase? gauge = jobID switch
{
19 => jobGauges.Get<PLDGauge>(),
20 => jobGauges.Get<MNKGauge>(),
21 => jobGauges.Get<WARGauge>(),
22 => jobGauges.Get<DRGGauge>(),
23 => jobGauges.Get<BRDGauge>(),
24 => jobGauges.Get<WHMGauge>(),
25 => jobGauges.Get<BLMGauge>(),
27 => jobGauges.Get<SMNGauge>(),
28 => jobGauges.Get<SCHGauge>(),
30 => jobGauges.Get<NINGauge>(),
31 => jobGauges.Get<MCHGauge>(),
32 => jobGauges.Get<DRKGauge>(),
33 => jobGauges.Get<ASTGauge>(),
34 => jobGauges.Get<SAMGauge>(),
35 => jobGauges.Get<RDMGauge>(),
37 => jobGauges.Get<GNBGauge>(),
38 => jobGauges.Get<DNCGauge>(),
39 => jobGauges.Get<RPRGauge>(),
40 => jobGauges.Get<SGEGauge>(),
_ => null,
};
if (gauge == null)
{
ImGui.Text("No supported gauge exists for this job.");
return;
}
Util.ShowObject(gauge);
}
}

View file

@ -0,0 +1,87 @@
using System;
using System.Runtime.InteropServices;
using Dalamud.Hooking;
using ImGuiNET;
using PInvoke;
using Serilog;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying hook information.
/// </summary>
internal class HookWidget : IDataWindowWidget
{
private Hook<MessageBoxWDelegate>? messageBoxMinHook;
private bool hookUseMinHook;
private delegate int MessageBoxWDelegate(
IntPtr hWnd,
[MarshalAs(UnmanagedType.LPWStr)] string text,
[MarshalAs(UnmanagedType.LPWStr)] string caption,
NativeFunctions.MessageBoxType type);
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Hook;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
try
{
ImGui.Checkbox("Use MinHook", ref this.hookUseMinHook);
if (ImGui.Button("Create"))
this.messageBoxMinHook = Hook<MessageBoxWDelegate>.FromSymbol("User32", "MessageBoxW", this.MessageBoxWDetour, this.hookUseMinHook);
if (ImGui.Button("Enable"))
this.messageBoxMinHook?.Enable();
if (ImGui.Button("Disable"))
this.messageBoxMinHook?.Disable();
if (ImGui.Button("Call Original"))
this.messageBoxMinHook?.Original(IntPtr.Zero, "Hello from .Original", "Hook Test", NativeFunctions.MessageBoxType.Ok);
if (ImGui.Button("Dispose"))
{
this.messageBoxMinHook?.Dispose();
this.messageBoxMinHook = null;
}
if (ImGui.Button("Test"))
_ = NativeFunctions.MessageBoxW(IntPtr.Zero, "Hi", "Hello", NativeFunctions.MessageBoxType.Ok);
if (this.messageBoxMinHook != null)
ImGui.Text("Enabled: " + this.messageBoxMinHook?.IsEnabled);
}
catch (Exception ex)
{
Log.Error(ex, "MinHook error caught");
}
}
private int MessageBoxWDetour(IntPtr hwnd, string text, string caption, NativeFunctions.MessageBoxType type)
{
Log.Information("[DATAHOOK] {Hwnd} {Text} {Caption} {Type}", hwnd, text, caption, type);
var result = this.messageBoxMinHook!.Original(hwnd, "Cause Access Violation?", caption, NativeFunctions.MessageBoxType.YesNo);
if (result == (int)User32.MessageBoxResult.IDYES)
{
Marshal.ReadByte(IntPtr.Zero);
}
return result;
}
}

View file

@ -0,0 +1,74 @@
using System;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Windowing;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying ImGui test.
/// </summary>
internal class ImGuiWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.ImGui;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var interfaceManager = Service<InterfaceManager>.Get();
var notifications = Service<NotificationManager>.Get();
ImGui.Text("Monitor count: " + ImGui.GetPlatformIO().Monitors.Size);
ImGui.Text("OverrideGameCursor: " + interfaceManager.OverrideGameCursor);
ImGui.Button("THIS IS A BUTTON###hoverTestButton");
interfaceManager.OverrideGameCursor = !ImGui.IsItemHovered();
ImGui.Separator();
ImGui.TextUnformatted($"WindowSystem.TimeSinceLastAnyFocus: {WindowSystem.TimeSinceLastAnyFocus.TotalMilliseconds:0}ms");
ImGui.Separator();
if (ImGui.Button("Add random notification"))
{
var rand = new Random();
var title = rand.Next(0, 5) switch
{
0 => "This is a toast",
1 => "Truly, a toast",
2 => "I am testing this toast",
3 => "I hope this looks right",
4 => "Good stuff",
5 => "Nice",
_ => null,
};
var type = rand.Next(0, 4) switch
{
0 => NotificationType.Error,
1 => NotificationType.Warning,
2 => NotificationType.Info,
3 => NotificationType.Success,
4 => NotificationType.None,
_ => NotificationType.None,
};
const string text = "Bla bla bla bla bla bla bla bla bla bla bla.\nBla bla bla bla bla bla bla bla bla bla bla bla bla bla.";
notifications.AddNotification(text, title, type);
}
}
}

View file

@ -0,0 +1,50 @@
using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface.Colors;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying keyboard state.
/// </summary>
internal class KeyStateWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.KeyState;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var keyState = Service<KeyState>.Get();
ImGui.Columns(4);
var i = 0;
foreach (var vkCode in keyState.GetValidVirtualKeys())
{
var code = (int)vkCode;
var value = keyState[code];
ImGui.PushStyleColor(ImGuiCol.Text, value ? ImGuiColors.HealerGreen : ImGuiColors.DPSRed);
ImGui.Text($"{vkCode} ({code})");
ImGui.PopStyleColor();
i++;
if (i % 24 == 0)
ImGui.NextColumn();
}
ImGui.Columns(1);
}
}

View file

@ -0,0 +1,119 @@
using System;
using System.Numerics;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Gui;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget to display the Object Table.
/// </summary>
internal class ObjectTableWidget : IDataWindowWidget
{
private bool resolveGameData;
private bool drawCharacters;
private float maxCharaDrawDistance = 20.0f;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Object_Table;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
ImGui.Checkbox("Resolve GameData", ref this.resolveGameData);
var chatGui = Service<ChatGui>.Get();
var clientState = Service<ClientState>.Get();
var gameGui = Service<GameGui>.Get();
var objectTable = Service<ObjectTable>.Get();
var stateString = string.Empty;
if (clientState.LocalPlayer == null)
{
ImGui.TextUnformatted("LocalPlayer null.");
}
else if (clientState.IsPvPExcludingDen)
{
ImGui.TextUnformatted("Cannot access object table while in PvP.");
}
else
{
stateString += $"ObjectTableLen: {objectTable.Length}\n";
stateString += $"LocalPlayerName: {clientState.LocalPlayer.Name}\n";
stateString += $"CurrentWorldName: {(this.resolveGameData ? clientState.LocalPlayer.CurrentWorld.GameData?.Name : clientState.LocalPlayer.CurrentWorld.Id.ToString())}\n";
stateString += $"HomeWorldName: {(this.resolveGameData ? clientState.LocalPlayer.HomeWorld.GameData?.Name : clientState.LocalPlayer.HomeWorld.Id.ToString())}\n";
stateString += $"LocalCID: {clientState.LocalContentId:X}\n";
stateString += $"LastLinkedItem: {chatGui.LastLinkedItemId}\n";
stateString += $"TerritoryType: {clientState.TerritoryType}\n\n";
ImGui.TextUnformatted(stateString);
ImGui.Checkbox("Draw characters on screen", ref this.drawCharacters);
ImGui.SliderFloat("Draw Distance", ref this.maxCharaDrawDistance, 2f, 40f);
for (var i = 0; i < objectTable.Length; i++)
{
var obj = objectTable[i];
if (obj == null)
continue;
Util.PrintGameObject(obj, i.ToString(), this.resolveGameData);
if (this.drawCharacters && gameGui.WorldToScreen(obj.Position, out var screenCoords))
{
// So, while WorldToScreen will return false if the point is off of game client screen, to
// to avoid performance issues, we have to manually determine if creating a window would
// produce a new viewport, and skip rendering it if so
var objectText = $"{obj.Address.ToInt64():X}:{obj.ObjectId:X}[{i}] - {obj.ObjectKind} - {obj.Name}";
var screenPos = ImGui.GetMainViewport().Pos;
var screenSize = ImGui.GetMainViewport().Size;
var windowSize = ImGui.CalcTextSize(objectText);
// Add some extra safety padding
windowSize.X += ImGui.GetStyle().WindowPadding.X + 10;
windowSize.Y += ImGui.GetStyle().WindowPadding.Y + 10;
if (screenCoords.X + windowSize.X > screenPos.X + screenSize.X ||
screenCoords.Y + windowSize.Y > screenPos.Y + screenSize.Y)
continue;
if (obj.YalmDistanceX > this.maxCharaDrawDistance)
continue;
ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y));
ImGui.SetNextWindowBgAlpha(Math.Max(1f - (obj.YalmDistanceX / this.maxCharaDrawDistance), 0.2f));
if (ImGui.Begin(
$"Actor{i}##ActorWindow{i}",
ImGuiWindowFlags.NoDecoration |
ImGuiWindowFlags.AlwaysAutoResize |
ImGuiWindowFlags.NoSavedSettings |
ImGuiWindowFlags.NoMove |
ImGuiWindowFlags.NoMouseInputs |
ImGuiWindowFlags.NoDocking |
ImGuiWindowFlags.NoFocusOnAppearing |
ImGuiWindowFlags.NoNav))
ImGui.Text(objectText);
ImGui.End();
}
}
}
}
}

View file

@ -0,0 +1,63 @@
using Dalamud.Game.ClientState.Party;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying information about the current party.
/// </summary>
internal class PartyListWidget : IDataWindowWidget
{
private bool resolveGameData;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Party_List;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var partyList = Service<PartyList>.Get();
ImGui.Checkbox("Resolve GameData", ref this.resolveGameData);
ImGui.Text($"GroupManager: {partyList.GroupManagerAddress.ToInt64():X}");
ImGui.Text($"GroupList: {partyList.GroupListAddress.ToInt64():X}");
ImGui.Text($"AllianceList: {partyList.AllianceListAddress.ToInt64():X}");
ImGui.Text($"{partyList.Length} Members");
for (var i = 0; i < partyList.Length; i++)
{
var member = partyList[i];
if (member == null)
{
ImGui.Text($"[{i}] was null");
continue;
}
ImGui.Text($"[{i}] {member.Address.ToInt64():X} - {member.Name} - {member.GameObject?.ObjectId}");
if (this.resolveGameData)
{
var actor = member.GameObject;
if (actor == null)
{
ImGui.Text("Actor was null");
}
else
{
Util.PrintGameObject(actor, "-", this.resolveGameData);
}
}
}
}
}

View file

@ -0,0 +1,84 @@
using System;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Ipc.Internal;
using Dalamud.Utility;
using ImGuiNET;
using Serilog;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for testing plugin IPC systems.
/// </summary>
internal class PluginIpcWidget : IDataWindowWidget
{
// IPC
private ICallGateProvider<string, string>? ipcPub;
private ICallGateSubscriber<string, string>? ipcSub;
private string callGateResponse = string.Empty;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Plugin_IPC;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
if (this.ipcPub == null)
{
this.ipcPub = new CallGatePubSub<string, string>("dataDemo1");
this.ipcPub.RegisterAction(msg =>
{
Log.Information("Data action was called: {Msg}", msg);
});
this.ipcPub.RegisterFunc(msg =>
{
Log.Information("Data func was called: {Msg}", msg);
return Guid.NewGuid().ToString();
});
}
if (this.ipcSub == null)
{
this.ipcSub = new CallGatePubSub<string, string>("dataDemo1");
this.ipcSub.Subscribe(_ =>
{
Log.Information("PONG1");
});
this.ipcSub.Subscribe(_ =>
{
Log.Information("PONG2");
});
this.ipcSub.Subscribe(_ => throw new Exception("PONG3"));
}
if (ImGui.Button("PING"))
{
this.ipcPub.SendMessage("PING");
}
if (ImGui.Button("Action"))
{
this.ipcSub.InvokeAction("button1");
}
if (ImGui.Button("Func"))
{
this.callGateResponse = this.ipcSub.InvokeFunc("button2");
}
if (!this.callGateResponse.IsNullOrEmpty())
ImGui.Text($"Response: {this.callGateResponse}");
}
}

View file

@ -0,0 +1,33 @@
using Dalamud.Game.Text;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying test data for SE Font Symbols.
/// </summary>
internal class SeFontTestWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.SE_Font_Test;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var specialChars = string.Empty;
for (var i = 0xE020; i <= 0xE0DB; i++)
specialChars += $"0x{i:X} - {(SeIconChar)i} - {(char)i}\n";
ImGui.TextUnformatted(specialChars);
}
}

View file

@ -0,0 +1,37 @@
using Dalamud.Data;
using ImGuiNET;
using Newtonsoft.Json;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget to display the currently set server opcodes.
/// </summary>
internal class ServerOpcodeWidget : IDataWindowWidget
{
private string? serverOpString;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Server_OpCode;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
var dataManager = Service<DataManager>.Get();
if (dataManager.IsDataReady)
{
this.serverOpString = JsonConvert.SerializeObject(dataManager.ServerOpCodes, Formatting.Indented);
this.Ready = true;
}
}
/// <inheritdoc/>
public void Draw()
{
ImGui.TextUnformatted(this.serverOpString ?? "serverOpString not initialized");
}
}

View file

@ -0,0 +1,30 @@
using ImGuiNET;
using Newtonsoft.Json;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying start info.
/// </summary>
internal class StartInfoWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.StartInfo;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var startInfo = Service<DalamudStartInfo>.Get();
ImGui.Text(JsonConvert.SerializeObject(startInfo, Formatting.Indented));
}
}

View file

@ -0,0 +1,88 @@
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying target info.
/// </summary>
internal class TargetWidget : IDataWindowWidget
{
private bool resolveGameData;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Target;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
ImGui.Checkbox("Resolve GameData", ref this.resolveGameData);
var clientState = Service<ClientState>.Get();
var targetMgr = Service<TargetManager>.Get();
if (targetMgr.Target != null)
{
Util.PrintGameObject(targetMgr.Target, "CurrentTarget", this.resolveGameData);
ImGui.Text("Target");
Util.ShowGameObjectStruct(targetMgr.Target);
var tot = targetMgr.Target.TargetObject;
if (tot != null)
{
ImGuiHelpers.ScaledDummy(10);
ImGui.Separator();
ImGui.Text("ToT");
Util.ShowGameObjectStruct(tot);
}
ImGuiHelpers.ScaledDummy(10);
}
if (targetMgr.FocusTarget != null)
Util.PrintGameObject(targetMgr.FocusTarget, "FocusTarget", this.resolveGameData);
if (targetMgr.MouseOverTarget != null)
Util.PrintGameObject(targetMgr.MouseOverTarget, "MouseOverTarget", this.resolveGameData);
if (targetMgr.PreviousTarget != null)
Util.PrintGameObject(targetMgr.PreviousTarget, "PreviousTarget", this.resolveGameData);
if (targetMgr.SoftTarget != null)
Util.PrintGameObject(targetMgr.SoftTarget, "SoftTarget", this.resolveGameData);
if (ImGui.Button("Clear CT"))
targetMgr.ClearTarget();
if (ImGui.Button("Clear FT"))
targetMgr.ClearFocusTarget();
var localPlayer = clientState.LocalPlayer;
if (localPlayer != null)
{
if (ImGui.Button("Set CT"))
targetMgr.SetTarget(localPlayer);
if (ImGui.Button("Set FT"))
targetMgr.SetFocusTarget(localPlayer);
}
else
{
ImGui.Text("LocalPlayer is null.");
}
}
}

View file

@ -0,0 +1,256 @@
// ReSharper disable MethodSupportsCancellation // Using alternative method of cancelling tasks by throwing exceptions.
using System;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Game;
using Dalamud.Interface.Colors;
using Dalamud.Logging.Internal;
using ImGuiNET;
using Serilog;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying task scheduler test.
/// </summary>
internal class TaskSchedulerWidget : IDataWindowWidget
{
private CancellationTokenSource taskSchedulerCancelSource = new();
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.TaskSched;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
if (ImGui.Button("Clear list"))
{
TaskTracker.Clear();
}
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(10);
ImGui.SameLine();
if (ImGui.Button("Cancel using CancellationTokenSource"))
{
this.taskSchedulerCancelSource.Cancel();
this.taskSchedulerCancelSource = new();
}
ImGui.Text("Run in any thread: ");
ImGui.SameLine();
if (ImGui.Button("Short Task.Run"))
{
Task.Run(() => { Thread.Sleep(500); });
}
ImGui.SameLine();
if (ImGui.Button("Task in task(Delay)"))
{
var token = this.taskSchedulerCancelSource.Token;
Task.Run(async () => await this.TestTaskInTaskDelay(token), token);
}
ImGui.SameLine();
if (ImGui.Button("Task in task(Sleep)"))
{
Task.Run(async () => await this.TestTaskInTaskSleep());
}
ImGui.SameLine();
if (ImGui.Button("Faulting task"))
{
Task.Run(() =>
{
Thread.Sleep(200);
string a = null;
a.Contains("dalamud"); // Intentional null exception.
});
}
ImGui.Text("Run in Framework.Update: ");
ImGui.SameLine();
if (ImGui.Button("ASAP"))
{
Task.Run(async () => await Service<Framework>.Get().RunOnTick(() => { }, cancellationToken: this.taskSchedulerCancelSource.Token));
}
ImGui.SameLine();
if (ImGui.Button("In 1s"))
{
Task.Run(async () => await Service<Framework>.Get().RunOnTick(() => { }, cancellationToken: this.taskSchedulerCancelSource.Token, delay: TimeSpan.FromSeconds(1)));
}
ImGui.SameLine();
if (ImGui.Button("In 60f"))
{
Task.Run(async () => await Service<Framework>.Get().RunOnTick(() => { }, cancellationToken: this.taskSchedulerCancelSource.Token, delayTicks: 60));
}
ImGui.SameLine();
if (ImGui.Button("Error in 1s"))
{
Task.Run(async () => await Service<Framework>.Get().RunOnTick(() => throw new Exception("Test Exception"), cancellationToken: this.taskSchedulerCancelSource.Token, delay: TimeSpan.FromSeconds(1)));
}
ImGui.SameLine();
if (ImGui.Button("As long as it's in Framework Thread"))
{
Task.Run(async () => await Service<Framework>.Get().RunOnFrameworkThread(() => { Log.Information("Task dispatched from non-framework.update thread"); }));
Service<Framework>.Get().RunOnFrameworkThread(() => { Log.Information("Task dispatched from framework.update thread"); }).Wait();
}
if (ImGui.Button("Drown in tasks"))
{
var token = this.taskSchedulerCancelSource.Token;
Task.Run(
() =>
{
for (var i = 0; i < 100; i++)
{
token.ThrowIfCancellationRequested();
Task.Run(
() =>
{
for (var j = 0; j < 100; j++)
{
token.ThrowIfCancellationRequested();
Task.Run(
() =>
{
for (var k = 0; k < 100; k++)
{
token.ThrowIfCancellationRequested();
Task.Run(
() =>
{
for (var l = 0; l < 100; l++)
{
token.ThrowIfCancellationRequested();
Task.Run(
async () =>
{
for (var m = 0; m < 100; m++)
{
token.ThrowIfCancellationRequested();
await Task.Delay(1, token);
}
});
}
});
}
});
}
});
}
});
}
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(20);
// Needed to init the task tracker, if we're not on a debug build
Service<TaskTracker>.Get().Enable();
for (var i = 0; i < TaskTracker.Tasks.Count; i++)
{
var task = TaskTracker.Tasks[i];
var subTime = DateTime.Now;
if (task.Task == null)
subTime = task.FinishTime;
switch (task.Status)
{
case TaskStatus.Created:
case TaskStatus.WaitingForActivation:
case TaskStatus.WaitingToRun:
ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.DalamudGrey);
break;
case TaskStatus.Running:
case TaskStatus.WaitingForChildrenToComplete:
ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.ParsedBlue);
break;
case TaskStatus.RanToCompletion:
ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.ParsedGreen);
break;
case TaskStatus.Canceled:
case TaskStatus.Faulted:
ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.DalamudRed);
break;
default:
throw new ArgumentOutOfRangeException();
}
if (ImGui.CollapsingHeader($"#{task.Id} - {task.Status} {(subTime - task.StartTime).TotalMilliseconds}ms###task{i}"))
{
task.IsBeingViewed = true;
if (ImGui.Button("CANCEL (May not work)"))
{
try
{
var cancelFunc =
typeof(Task).GetMethod("InternalCancel", BindingFlags.NonPublic | BindingFlags.Instance);
cancelFunc?.Invoke(task, null);
}
catch (Exception ex)
{
Log.Error(ex, "Could not cancel task");
}
}
ImGuiHelpers.ScaledDummy(10);
ImGui.TextUnformatted(task.StackTrace?.ToString());
if (task.Exception != null)
{
ImGuiHelpers.ScaledDummy(15);
ImGui.TextColored(ImGuiColors.DalamudRed, "EXCEPTION:");
ImGui.TextUnformatted(task.Exception.ToString());
}
}
else
{
task.IsBeingViewed = false;
}
ImGui.PopStyleColor(1);
}
}
private async Task TestTaskInTaskDelay(CancellationToken token)
{
await Task.Delay(5000, token);
}
#pragma warning disable 1998
private async Task TestTaskInTaskSleep()
#pragma warning restore 1998
{
Thread.Sleep(5000);
}
}

View file

@ -0,0 +1,69 @@
using System;
using System.Numerics;
using Dalamud.Data;
using Dalamud.Utility;
using ImGuiNET;
using ImGuiScene;
using Serilog;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying texture test.
/// </summary>
internal class TexWidget : IDataWindowWidget
{
private string inputTexPath = string.Empty;
private TextureWrap? debugTex;
private Vector2 inputTexUv0 = Vector2.Zero;
private Vector2 inputTexUv1 = Vector2.One;
private Vector4 inputTintCol = Vector4.One;
private Vector2 inputTexScale = Vector2.Zero;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Tex;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var dataManager = Service<DataManager>.Get();
ImGui.InputText("Tex Path", ref this.inputTexPath, 255);
ImGui.InputFloat2("UV0", ref this.inputTexUv0);
ImGui.InputFloat2("UV1", ref this.inputTexUv1);
ImGui.InputFloat4("Tint", ref this.inputTintCol);
ImGui.InputFloat2("Scale", ref this.inputTexScale);
if (ImGui.Button("Load Tex"))
{
try
{
this.debugTex = dataManager.GetImGuiTexture(this.inputTexPath);
this.inputTexScale = new Vector2(this.debugTex?.Width ?? 0, this.debugTex?.Height ?? 0);
}
catch (Exception ex)
{
Log.Error(ex, "Could not load tex");
}
}
ImGuiHelpers.ScaledDummy(10);
if (this.debugTex != null)
{
ImGui.Image(this.debugTex.ImGuiHandle, this.inputTexScale, this.inputTexUv0, this.inputTexUv1, this.inputTintCol);
ImGuiHelpers.ScaledDummy(5);
Util.ShowObject(this.debugTex);
}
}
}

View file

@ -0,0 +1,74 @@
using System.Numerics;
using Dalamud.Game.Gui.Toast;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying toast test.
/// </summary>
internal class ToastWidget : IDataWindowWidget
{
private string inputTextToast = string.Empty;
private int toastPosition;
private int toastSpeed;
private int questToastPosition;
private bool questToastSound;
private int questToastIconId;
private bool questToastCheckmark;
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.Toast;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var toastGui = Service<ToastGui>.Get();
ImGui.InputText("Toast text", ref this.inputTextToast, 200);
ImGui.Combo("Toast Position", ref this.toastPosition, new[] { "Bottom", "Top", }, 2);
ImGui.Combo("Toast Speed", ref this.toastSpeed, new[] { "Slow", "Fast", }, 2);
ImGui.Combo("Quest Toast Position", ref this.questToastPosition, new[] { "Centre", "Right", "Left" }, 3);
ImGui.Checkbox("Quest Checkmark", ref this.questToastCheckmark);
ImGui.Checkbox("Quest Play Sound", ref this.questToastSound);
ImGui.InputInt("Quest Icon ID", ref this.questToastIconId);
ImGuiHelpers.ScaledDummy(new Vector2(10, 10));
if (ImGui.Button("Show toast"))
{
toastGui.ShowNormal(this.inputTextToast, new ToastOptions
{
Position = (ToastPosition)this.toastPosition,
Speed = (ToastSpeed)this.toastSpeed,
});
}
if (ImGui.Button("Show Quest toast"))
{
toastGui.ShowQuest(this.inputTextToast, new QuestToastOptions
{
Position = (QuestToastPosition)this.questToastPosition,
DisplayCheckmark = this.questToastCheckmark,
IconId = (uint)this.questToastIconId,
PlaySound = this.questToastSound,
});
}
if (ImGui.Button("Show Error toast"))
{
toastGui.ShowError(this.inputTextToast);
}
}
}

View file

@ -0,0 +1,60 @@
using System.Numerics;
using Dalamud.Data;
using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
namespace Dalamud.Interface.Internal.Windows.Data;
/// <summary>
/// Widget for displaying all UI Colors from Lumina.
/// </summary>
internal class UIColorWidget : IDataWindowWidget
{
/// <inheritdoc/>
public DataKind DataKind { get; init; } = DataKind.UIColor;
/// <inheritdoc/>
public bool Ready { get; set; }
/// <inheritdoc/>
public void Load()
{
this.Ready = true;
}
/// <inheritdoc/>
public void Draw()
{
var colorSheet = Service<DataManager>.Get().GetExcelSheet<UIColor>();
if (colorSheet is null) return;
foreach (var color in colorSheet)
{
this.DrawUiColor(color);
}
}
private void DrawUiColor(UIColor color)
{
ImGui.Text($"[{color.RowId:D3}] ");
ImGui.SameLine();
ImGui.TextColored(this.ConvertToVector4(color.Unknown2), $"Unknown2 ");
ImGui.SameLine();
ImGui.TextColored(this.ConvertToVector4(color.UIForeground), "UIForeground ");
ImGui.SameLine();
ImGui.TextColored(this.ConvertToVector4(color.Unknown3), "Unknown3 ");
ImGui.SameLine();
ImGui.TextColored(this.ConvertToVector4(color.UIGlow), "UIGlow");
}
private Vector4 ConvertToVector4(uint color)
{
var r = (byte)(color >> 24);
var g = (byte)(color >> 16);
var b = (byte)(color >> 8);
var a = (byte)color;
return new Vector4(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
}
}

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,7 @@ using System.Text;
using Dalamud.Configuration.Internal;
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
@ -672,6 +673,40 @@ public static class Util
return names.ElementAt(rng.Next(0, names.Count() - 1)).Singular.RawString;
}
/// <summary>
/// Print formatted GameObject Information to ImGui
/// </summary>
/// <param name="actor">Game Object to Display.</param>
/// <param name="tag">Display Tag.</param>
/// <param name="resolveGameData">If the GameObjects data should be resolved.</param>
internal static void PrintGameObject(GameObject actor, string tag, bool resolveGameData)
{
var actorString =
$"{actor.Address.ToInt64():X}:{actor.ObjectId:X}[{tag}] - {actor.ObjectKind} - {actor.Name} - X{actor.Position.X} Y{actor.Position.Y} Z{actor.Position.Z} D{actor.YalmDistanceX} R{actor.Rotation} - Target: {actor.TargetObjectId:X}\n";
if (actor is Npc npc)
actorString += $" DataId: {npc.DataId} NameId:{npc.NameId}\n";
if (actor is Character chara)
{
actorString +=
$" Level: {chara.Level} ClassJob: {(resolveGameData ? chara.ClassJob.GameData?.Name : chara.ClassJob.Id.ToString())} CHP: {chara.CurrentHp} MHP: {chara.MaxHp} CMP: {chara.CurrentMp} MMP: {chara.MaxMp}\n Customize: {BitConverter.ToString(chara.Customize).Replace("-", " ")} StatusFlags: {chara.StatusFlags}\n";
}
if (actor is PlayerCharacter pc)
{
actorString +=
$" HomeWorld: {(resolveGameData ? pc.HomeWorld.GameData?.Name : pc.HomeWorld.Id.ToString())} CurrentWorld: {(resolveGameData ? pc.CurrentWorld.GameData?.Name : pc.CurrentWorld.Id.ToString())} FC: {pc.CompanyTag}\n";
}
ImGui.TextUnformatted(actorString);
ImGui.SameLine();
if (ImGui.Button($"C##{actor.Address.ToInt64()}"))
{
ImGui.SetClipboardText(actor.Address.ToInt64().ToString("X"));
}
}
private static unsafe void ShowValue(ulong addr, IEnumerable<string> path, Type type, object value)
{
if (type.IsPointer)