PalacePal/Pal.Client/Floors/ObjectTableDebug.cs

100 lines
3.8 KiB
C#
Raw Normal View History

2023-03-07 20:55:50 +00:00
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin;
2023-10-03 09:08:38 +00:00
using Dalamud.Plugin.Services;
2023-03-07 20:55:50 +00:00
using ImGuiNET;
2023-03-30 20:01:43 +00:00
namespace Pal.Client.Floors;
/// <summary>
/// This isn't very useful for running deep dungeons normally, but it is for plugin dev.
///
/// Needs the corresponding beta feature to be enabled.
/// </summary>
internal sealed class ObjectTableDebug : IDisposable
2023-03-07 20:55:50 +00:00
{
2023-03-30 20:01:43 +00:00
public const string FeatureName = nameof(ObjectTableDebug);
2023-03-07 20:55:50 +00:00
2023-03-30 20:01:43 +00:00
private readonly DalamudPluginInterface _pluginInterface;
2023-10-03 09:08:38 +00:00
private readonly IObjectTable _objectTable;
private readonly IGameGui _gameGui;
private readonly IClientState _clientState;
2023-03-07 20:55:50 +00:00
2023-10-03 20:05:19 +00:00
public ObjectTableDebug(DalamudPluginInterface pluginInterface, IObjectTable objectTable, IGameGui gameGui,
IClientState clientState)
2023-03-30 20:01:43 +00:00
{
_pluginInterface = pluginInterface;
_objectTable = objectTable;
_gameGui = gameGui;
_clientState = clientState;
2023-03-07 20:55:50 +00:00
2023-03-30 20:01:43 +00:00
_pluginInterface.UiBuilder.Draw += Draw;
}
2023-03-07 20:55:50 +00:00
2023-03-30 20:01:43 +00:00
private void Draw()
{
int index = 0;
foreach (GameObject obj in _objectTable)
2023-03-07 20:55:50 +00:00
{
2023-03-30 20:01:43 +00:00
if (obj is EventObj eventObj && string.IsNullOrEmpty(eventObj.Name.ToString()))
2023-03-07 20:55:50 +00:00
{
2023-03-30 20:01:43 +00:00
++index;
int model = Marshal.ReadInt32(obj.Address + 128);
if (_gameGui.WorldToScreen(obj.Position, out var screenCoords))
2023-03-07 20:55:50 +00:00
{
2023-03-30 20:01:43 +00:00
// 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
float distance = DistanceToPlayer(obj.Position);
var objectText =
$"{obj.Address.ToInt64():X}:{obj.ObjectId:X}[{index}]\nkind: {obj.ObjectKind} sub: {obj.SubKind}\nmodel: {model}\nname: {obj.Name}\ndata id: {obj.DataId}";
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 (distance > 50f)
continue;
ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y));
ImGui.SetNextWindowBgAlpha(Math.Max(1f - (distance / 50f), 0.2f));
if (ImGui.Begin(
$"PalacePal_{nameof(ObjectTableDebug)}_{index}",
ImGuiWindowFlags.NoDecoration |
ImGuiWindowFlags.AlwaysAutoResize |
ImGuiWindowFlags.NoSavedSettings |
ImGuiWindowFlags.NoMove |
ImGuiWindowFlags.NoMouseInputs |
ImGuiWindowFlags.NoDocking |
ImGuiWindowFlags.NoFocusOnAppearing |
ImGuiWindowFlags.NoNav))
ImGui.Text(objectText);
ImGui.End();
2023-03-07 20:55:50 +00:00
}
}
}
2023-03-30 20:01:43 +00:00
}
2023-03-07 20:55:50 +00:00
2023-03-30 20:01:43 +00:00
private float DistanceToPlayer(Vector3 center)
=> Vector3.Distance(_clientState.LocalPlayer?.Position ?? Vector3.Zero, center);
2023-03-07 20:55:50 +00:00
2023-03-30 20:01:43 +00:00
public void Dispose()
{
_pluginInterface.UiBuilder.Draw -= Draw;
2023-03-07 20:55:50 +00:00
}
}