2023-10-03 08:29:00 +00:00
|
|
|
|
using Dalamud.Game.ClientState.Objects.Enums;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
using Dalamud.Game.ClientState.Objects.Types;
|
|
|
|
|
using Dalamud.IoC;
|
|
|
|
|
using Dalamud.Plugin;
|
|
|
|
|
using ImGuiNET;
|
|
|
|
|
using System;
|
2021-09-29 11:16:39 +00:00
|
|
|
|
using System.Collections.Generic;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
using System.Numerics;
|
|
|
|
|
using System.Runtime.InteropServices;
|
2023-10-03 08:29:00 +00:00
|
|
|
|
using Dalamud.Interface.Utility;
|
|
|
|
|
using Dalamud.Plugin.Services;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
namespace SliceIsRight;
|
|
|
|
|
|
|
|
|
|
// ReSharper disable once UnusedType.Global
|
|
|
|
|
public sealed class SliceIsRightPlugin : IDalamudPlugin
|
2021-09-28 20:27:59 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
private const float HalfPi = (float)Math.PI / 2f;
|
|
|
|
|
private static readonly uint ColourBlue = ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(0.0f, 0.0f, 1f, 0.15f)));
|
|
|
|
|
private static readonly uint ColourGreen = ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(0.0f, 1f, 0.0f, 0.15f)));
|
|
|
|
|
private static readonly uint ColourRed = ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(1, 0, 0, 0.4f)));
|
2021-12-15 22:46:53 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
[PluginService]
|
|
|
|
|
[RequiredVersion("1.0")]
|
|
|
|
|
private DalamudPluginInterface PluginInterface { get; set; } = null!;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
[PluginService]
|
2023-10-03 08:29:00 +00:00
|
|
|
|
private IObjectTable ObjectTable { get; set; } = null!;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
[PluginService]
|
2023-10-03 08:29:00 +00:00
|
|
|
|
private IGameGui GameGui { get; set; } = null!;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
[PluginService]
|
2023-10-03 08:29:00 +00:00
|
|
|
|
private IClientState ClientState { get; set; } = null!;
|
2023-02-07 20:49:53 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
private const ushort GoldSaucerTerritoryId = 144;
|
|
|
|
|
private bool IsInGoldSaucer { get; set; }
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
private readonly IDictionary<uint, DateTime> _objectsAndSpawnTime = new Dictionary<uint, DateTime>();
|
|
|
|
|
private readonly ISet<uint> _objectsToMatch = new HashSet<uint>();
|
2021-09-29 11:16:39 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
private const float MaxDistance = 30f;
|
2021-09-29 11:16:39 +00:00
|
|
|
|
|
2021-12-15 22:46:53 +00:00
|
|
|
|
#pragma warning disable CS8618
|
2023-03-30 20:07:22 +00:00
|
|
|
|
public SliceIsRightPlugin()
|
|
|
|
|
{
|
|
|
|
|
PluginInterface.UiBuilder.Draw += DrawUi;
|
|
|
|
|
ClientState.TerritoryChanged += TerritoryChanged;
|
|
|
|
|
IsInGoldSaucer = ClientState.TerritoryType == GoldSaucerTerritoryId;
|
|
|
|
|
}
|
2021-12-15 22:46:53 +00:00
|
|
|
|
#pragma warning restore CS8618
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-10-03 08:29:00 +00:00
|
|
|
|
private void TerritoryChanged(ushort e)
|
2023-03-30 20:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
IsInGoldSaucer = e == GoldSaucerTerritoryId;
|
|
|
|
|
}
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
PluginInterface.UiBuilder.Draw -= DrawUi;
|
|
|
|
|
ClientState.TerritoryChanged -= TerritoryChanged;
|
|
|
|
|
}
|
2021-09-29 11:16:39 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
private void DrawUi()
|
|
|
|
|
{
|
|
|
|
|
if (!ClientState.IsLoggedIn || !IsInGoldSaucer)
|
|
|
|
|
return;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
for (int index = 0; index < ObjectTable.Length; ++index)
|
2021-09-28 20:27:59 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
GameObject? obj = ObjectTable[index];
|
|
|
|
|
if (obj == null || DistanceToPlayer(obj.Position) > MaxDistance)
|
|
|
|
|
continue;
|
2021-09-29 11:16:39 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
int model = Marshal.ReadInt32(obj.Address + 128);
|
|
|
|
|
if (obj.ObjectKind == ObjectKind.EventObj && (model >= 2010777 && model <= 2010779))
|
2021-09-29 11:16:39 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
RenderObject(obj, model);
|
2021-09-29 11:16:39 +00:00
|
|
|
|
}
|
2023-03-30 20:07:22 +00:00
|
|
|
|
else if (ClientState.LocalPlayer?.ObjectId == obj.ObjectId)
|
2021-09-29 11:16:39 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
// local player
|
|
|
|
|
//RenderObject(index, obj, 2010779, 0.1f); // circle
|
|
|
|
|
//RenderObject(index, obj, 2010778, 30f); // falls to both sides
|
|
|
|
|
//RenderObject(index, obj, 2010777, 30f); // falls to one side
|
2021-09-29 11:16:39 +00:00
|
|
|
|
}
|
2023-03-30 20:07:22 +00:00
|
|
|
|
}
|
2021-09-29 11:16:39 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
foreach (uint objectId in _objectsToMatch)
|
|
|
|
|
_objectsAndSpawnTime.Remove(objectId);
|
|
|
|
|
_objectsToMatch.Clear();
|
|
|
|
|
}
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
private void RenderObject(GameObject obj, int model, float? radius = null)
|
|
|
|
|
{
|
|
|
|
|
_objectsToMatch.Remove(obj.ObjectId);
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
if (_objectsAndSpawnTime.TryGetValue(obj.ObjectId, out DateTime spawnTime))
|
2021-12-15 22:46:53 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
if (spawnTime.AddSeconds(5) > DateTime.Now)
|
|
|
|
|
return;
|
2021-12-15 22:46:53 +00:00
|
|
|
|
}
|
2023-03-30 20:07:22 +00:00
|
|
|
|
else
|
2021-12-15 22:46:53 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
_objectsAndSpawnTime.Add(obj.ObjectId, DateTime.Now);
|
|
|
|
|
return;
|
2021-09-28 20:27:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
|
|
|
|
|
switch (model)
|
2021-09-28 20:27:59 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
case 2010777:
|
|
|
|
|
DrawRectWorld(obj, obj.Rotation + HalfPi, radius ?? 25f, 5f, ColourBlue);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2010778:
|
|
|
|
|
DrawRectWorld(obj, obj.Rotation + HalfPi, radius ?? 25f, 5f, ColourGreen);
|
|
|
|
|
DrawRectWorld(obj, obj.Rotation - HalfPi, radius ?? 25f, 5f, ColourGreen);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2010779:
|
|
|
|
|
//default:
|
|
|
|
|
DrawFilledCircleWorld(obj, radius ?? 11f, ColourRed);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-15 22:46:53 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
private void BeginRender(string name)
|
|
|
|
|
{
|
|
|
|
|
ImGui.PushID("sliceWindowI" + name);
|
2023-02-07 20:49:53 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
|
|
|
|
ImGuiHelpers.SetNextWindowPosRelativeMainViewport(Vector2.Zero, ImGuiCond.None, Vector2.Zero);
|
|
|
|
|
ImGui.Begin("sliceWindow" + name, ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoSavedSettings);
|
|
|
|
|
ImGui.SetWindowSize(ImGui.GetIO().DisplaySize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EndRender()
|
|
|
|
|
{
|
|
|
|
|
ImGui.End();
|
|
|
|
|
ImGui.PopStyleVar();
|
|
|
|
|
|
|
|
|
|
ImGui.PopID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DrawFilledCircleWorld(GameObject obj, float radius, uint colour)
|
|
|
|
|
{
|
|
|
|
|
BeginRender(obj.Address.ToString());
|
2021-12-15 22:46:53 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
var center = obj.Position;
|
|
|
|
|
int segmentCount = 100;
|
|
|
|
|
bool onScreen = false;
|
|
|
|
|
for (int index = 0; index <= 2 * segmentCount; ++index)
|
|
|
|
|
{
|
|
|
|
|
onScreen |= GameGui.WorldToScreen(new Vector3(center.X + radius * (float)Math.Sin(Math.PI / segmentCount * index), center.Y, center.Z + radius * (float)Math.Cos(Math.PI / segmentCount * index)), out Vector2 vector2);
|
|
|
|
|
ImGui.GetWindowDrawList().PathLineTo(vector2);
|
2021-09-28 20:27:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
if (onScreen)
|
|
|
|
|
ImGui.GetWindowDrawList().PathFillConvex(colour);
|
|
|
|
|
else
|
|
|
|
|
ImGui.GetWindowDrawList().PathClear();
|
|
|
|
|
|
|
|
|
|
EndRender();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DrawRectWorld(GameObject obj, float rotation, float length, float width, uint colour)
|
|
|
|
|
{
|
|
|
|
|
BeginRender($"{obj.Address}{obj.Rotation}");
|
|
|
|
|
|
|
|
|
|
var center = obj.Position;
|
|
|
|
|
Vector2 displaySize = ImGui.GetIO().DisplaySize;
|
|
|
|
|
Vector3 near1 = new Vector3(center.X + width / 2 * (float)Math.Sin(HalfPi + rotation), center.Y, center.Z + width / 2 * (float)Math.Cos(HalfPi + rotation));
|
|
|
|
|
Vector3 near2 = new Vector3(center.X + width / 2 * (float)Math.Sin(rotation - HalfPi), center.Y, center.Z + width / 2 * (float)Math.Cos(rotation - HalfPi));
|
|
|
|
|
Vector3 nearCenter = new Vector3(center.X, center.Y, center.Z);
|
|
|
|
|
int rectangleCount = 20;
|
|
|
|
|
float lengthSlice = length / rectangleCount;
|
|
|
|
|
|
|
|
|
|
var drawList = ImGui.GetWindowDrawList();
|
|
|
|
|
for (int index = 1; index <= rectangleCount; ++index)
|
2021-09-28 20:27:59 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
Vector3 far1 = new Vector3(near1.X + lengthSlice * (float)Math.Sin(rotation), near1.Y, near1.Z + lengthSlice * (float)Math.Cos(rotation));
|
|
|
|
|
Vector3 far2 = new Vector3(near2.X + lengthSlice * (float)Math.Sin(rotation), near2.Y, near2.Z + lengthSlice * (float)Math.Cos(rotation));
|
|
|
|
|
Vector3 farCenter = new Vector3(nearCenter.X + lengthSlice * (float)Math.Sin(rotation), nearCenter.Y, nearCenter.Z + lengthSlice * (float)Math.Cos(rotation));
|
2021-09-28 20:27:59 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
bool onScreen = false;
|
|
|
|
|
foreach (Vector3 v in new[] { far2, farCenter, far1, near1, nearCenter, near2 })
|
|
|
|
|
{
|
|
|
|
|
onScreen |= GameGui.WorldToScreen(v, out Vector2 nextVertex);
|
|
|
|
|
if ((nextVertex.X > 0 & nextVertex.X < displaySize.X) || (nextVertex.Y > 0 & nextVertex.Y < displaySize.Y))
|
2021-09-28 20:27:59 +00:00
|
|
|
|
{
|
2023-03-30 20:07:22 +00:00
|
|
|
|
drawList.PathLineTo(nextVertex);
|
2021-09-28 20:27:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-15 22:46:53 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
if (onScreen)
|
|
|
|
|
drawList.PathFillConvex(colour);
|
|
|
|
|
else
|
|
|
|
|
drawList.PathClear();
|
2021-09-29 11:16:39 +00:00
|
|
|
|
|
2023-03-30 20:07:22 +00:00
|
|
|
|
near1 = far1;
|
|
|
|
|
near2 = far2;
|
|
|
|
|
nearCenter = farCenter;
|
2021-09-29 11:16:39 +00:00
|
|
|
|
}
|
2023-03-30 20:07:22 +00:00
|
|
|
|
|
|
|
|
|
EndRender();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private float DistanceToPlayer(Vector3 center)
|
|
|
|
|
{
|
|
|
|
|
return Vector3.Distance(ClientState.LocalPlayer?.Position ?? Vector3.Zero, center);
|
2021-09-28 20:27:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|