diff --git a/SlightIsRightPlugin.cs b/SlightIsRightPlugin.cs index e97f36d..b0b3d28 100644 --- a/SlightIsRightPlugin.cs +++ b/SlightIsRightPlugin.cs @@ -12,206 +12,206 @@ using System.Collections.Generic; using System.Numerics; using System.Runtime.InteropServices; -namespace SliceIsRight +namespace SliceIsRight; + +// ReSharper disable once UnusedType.Global +public sealed class SliceIsRightPlugin : IDalamudPlugin { - public sealed class SliceIsRightPlugin : IDalamudPlugin - { - private const float HALF_PI = (float)Math.PI / 2f; - private uint COLOUR_BLUE = ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(0.0f, 0.0f, 1f, 0.15f))); - private uint COLOUR_GREEN = ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(0.0f, 1f, 0.0f, 0.15f))); - private uint COLOUR_RED = ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(1, 0, 0, 0.4f))); + 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))); - public string Name => "Slice is Right"; + public string Name => "Slice is Right"; - [PluginService] - [RequiredVersion("1.0")] - private DalamudPluginInterface PluginInterface { get; set; } + [PluginService] + [RequiredVersion("1.0")] + private DalamudPluginInterface PluginInterface { get; set; } = null!; - [PluginService] - private ObjectTable ObjectTable { get; set; } + [PluginService] + private ObjectTable ObjectTable { get; set; } = null!; - [PluginService] - private GameGui GameGui { get; set; } + [PluginService] + private GameGui GameGui { get; set; } = null!; - [PluginService] - private ClientState ClientState { get; set; } + [PluginService] + private ClientState ClientState { get; set; } = null!; - private const ushort GoldSaucerTerritoryId = 144; - private bool IsInGoldSaucer { get; set; } + private const ushort GoldSaucerTerritoryId = 144; + private bool IsInGoldSaucer { get; set; } - private readonly IDictionary objectsAndSpawnTime = new Dictionary(); - private readonly ISet objectsToMatch = new HashSet(); + private readonly IDictionary _objectsAndSpawnTime = new Dictionary(); + private readonly ISet _objectsToMatch = new HashSet(); - private const float MaxDistance = 30f; + private const float MaxDistance = 30f; #pragma warning disable CS8618 - public SliceIsRightPlugin() - { - PluginInterface!.UiBuilder.Draw += DrawUI; - ClientState!.TerritoryChanged += TerritoryChanged; - IsInGoldSaucer = ClientState.TerritoryType == GoldSaucerTerritoryId; - } + public SliceIsRightPlugin() + { + PluginInterface.UiBuilder.Draw += DrawUi; + ClientState.TerritoryChanged += TerritoryChanged; + IsInGoldSaucer = ClientState.TerritoryType == GoldSaucerTerritoryId; + } #pragma warning restore CS8618 - private void TerritoryChanged(object? sender, ushort e) + private void TerritoryChanged(object? sender, ushort e) + { + IsInGoldSaucer = e == GoldSaucerTerritoryId; + } + + public void Dispose() + { + PluginInterface.UiBuilder.Draw -= DrawUi; + ClientState.TerritoryChanged -= TerritoryChanged; + } + + private void DrawUi() + { + if (!ClientState.IsLoggedIn || !IsInGoldSaucer) + return; + + for (int index = 0; index < ObjectTable.Length; ++index) { - IsInGoldSaucer = e == GoldSaucerTerritoryId; + GameObject? obj = ObjectTable[index]; + if (obj == null || DistanceToPlayer(obj.Position) > MaxDistance) + continue; + + int model = Marshal.ReadInt32(obj.Address + 128); + if (obj.ObjectKind == ObjectKind.EventObj && (model >= 2010777 && model <= 2010779)) + { + RenderObject(obj, model); + } + else if (ClientState.LocalPlayer?.ObjectId == obj.ObjectId) + { + // 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 + } } - public void Dispose() - { - PluginInterface.UiBuilder.Draw -= DrawUI; - ClientState.TerritoryChanged -= TerritoryChanged; - } + foreach (uint objectId in _objectsToMatch) + _objectsAndSpawnTime.Remove(objectId); + _objectsToMatch.Clear(); + } - private void DrawUI() + private void RenderObject(GameObject obj, int model, float? radius = null) + { + _objectsToMatch.Remove(obj.ObjectId); + + if (_objectsAndSpawnTime.TryGetValue(obj.ObjectId, out DateTime spawnTime)) { - if (!ClientState.IsLoggedIn || !IsInGoldSaucer || ObjectTable == null) + if (spawnTime.AddSeconds(5) > DateTime.Now) return; - - for (int index = 0; index < ObjectTable.Length; ++index) - { - GameObject? obj = ObjectTable[index]; - if (obj == null || DistanceToPlayer(obj.Position) > MaxDistance) - continue; - - int model = Marshal.ReadInt32(obj.Address + 128); - if (obj.ObjectKind == ObjectKind.EventObj && (model >= 2010777 && model <= 2010779)) - { - RenderObject(index, obj, model); - } - else if (ClientState.LocalPlayer?.ObjectId == obj.ObjectId) - { - // 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 - } - } - - foreach (uint objectId in objectsToMatch) - objectsAndSpawnTime.Remove(objectId); - objectsToMatch.Clear(); + } + else + { + _objectsAndSpawnTime.Add(obj.ObjectId, DateTime.Now); + return; } - private void RenderObject(int index, GameObject obj, int model, float? radius = null) + + switch (model) { - objectsToMatch.Remove(obj.ObjectId); + case 2010777: + DrawRectWorld(obj, obj.Rotation + HalfPi, radius ?? 25f, 5f, ColourBlue); + break; - if (objectsAndSpawnTime.TryGetValue(obj.ObjectId, out DateTime spawnTime)) - { - if (spawnTime.AddSeconds(5) > DateTime.Now) - return; - } - else - { - objectsAndSpawnTime.Add(obj.ObjectId, DateTime.Now); - return; - } + 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; + } + } - switch (model) - { - case 2010777: - DrawRectWorld(obj, obj.Rotation + HALF_PI, radius ?? 25f, 5f, COLOUR_BLUE); - break; + private void BeginRender(string name) + { + ImGui.PushID("sliceWindowI" + name); - case 2010778: - DrawRectWorld(obj, obj.Rotation + HALF_PI, radius ?? 25f, 5f, COLOUR_GREEN); - DrawRectWorld(obj, obj.Rotation - HALF_PI, radius ?? 25f, 5f, COLOUR_GREEN); - break; + 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); + } - case 2010779: - //default: - DrawFilledCircleWorld(obj, radius ?? 11f, COLOUR_RED); - break; - } + private void EndRender() + { + ImGui.End(); + ImGui.PopStyleVar(); + + ImGui.PopID(); + } + + private void DrawFilledCircleWorld(GameObject obj, float radius, uint colour) + { + BeginRender(obj.Address.ToString()); + + 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); } - private void BeginRender(string name) + 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) { - ImGui.PushID("sliceWindowI" + name); + 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)); - 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()); - - var center = obj.Position; - int segmentCount = 100; bool onScreen = false; - for (int index = 0; index <= 2 * segmentCount; ++index) + foreach (Vector3 v in new[] { far2, farCenter, far1, near1, nearCenter, near2 }) { - 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); + onScreen |= GameGui.WorldToScreen(v, out Vector2 nextVertex); + if ((nextVertex.X > 0 & nextVertex.X < displaySize.X) || (nextVertex.Y > 0 & nextVertex.Y < displaySize.Y)) + { + drawList.PathLineTo(nextVertex); + } } if (onScreen) - ImGui.GetWindowDrawList().PathFillConvex(colour); + drawList.PathFillConvex(colour); else - ImGui.GetWindowDrawList().PathClear(); + drawList.PathClear(); - EndRender(); + near1 = far1; + near2 = far2; + nearCenter = farCenter; } - private void DrawRectWorld(GameObject obj, float rotation, float length, float width, uint colour) - { - BeginRender(obj.Address.ToString() + obj.Rotation.ToString()); + EndRender(); + } - var center = obj.Position; - Vector2 displaySize = ImGui.GetIO().DisplaySize; - Vector3 near1 = new Vector3(center.X + width / 2 * (float)Math.Sin(HALF_PI + rotation), center.Y, center.Z + width / 2 * (float)Math.Cos(HALF_PI + rotation)); - Vector3 near2 = new Vector3(center.X + width / 2 * (float)Math.Sin(rotation - HALF_PI), center.Y, center.Z + width / 2 * (float)Math.Cos(rotation - HALF_PI)); - 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) - { - 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)); - - 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)) - { - drawList.PathLineTo(nextVertex); - } - } - - if (onScreen) - drawList.PathFillConvex(colour); - else - drawList.PathClear(); - - near1 = far1; - near2 = far2; - nearCenter = farCenter; - } - - EndRender(); - } - - private float DistanceToPlayer(Vector3 center) - { - return Vector3.Distance(ClientState.LocalPlayer?.Position ?? Vector3.Zero, center); - } + private float DistanceToPlayer(Vector3 center) + { + return Vector3.Distance(ClientState.LocalPlayer?.Position ?? Vector3.Zero, center); } }