commit f9f14fb80b964df61a58cb563ce8a26fe7cfe74c Author: Liza Carvelli Date: Tue Sep 28 22:27:59 2021 +0200 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7990fe7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vs/ +obj/ +bin/ +*.user \ No newline at end of file diff --git a/SliceIsRight.csproj b/SliceIsRight.csproj new file mode 100644 index 0000000..abf1807 --- /dev/null +++ b/SliceIsRight.csproj @@ -0,0 +1,70 @@ + + + + + + 1.0.0.0 + Slice is Right. + + https://github.com/carvelli/SliceIsRight + + + + net5.0-windows + x64 + enable + latest + true + false + false + $(AppData)\XIVLauncher\devPlugins\SliceIsRight\ + + + + + PreserveNewest + + + + + $(appdata)\XIVLauncher\addon\Hooks\dev\ + + + + none + false + + + + + + $(DalamudLibPath)FFXIVClientStructs.dll + false + + + $(DalamudLibPath)Newtonsoft.Json.dll + false + + + $(DalamudLibPath)Dalamud.dll + false + + + $(DalamudLibPath)ImGui.NET.dll + false + + + $(DalamudLibPath)ImGuiScene.dll + false + + + $(DalamudLibPath)Lumina.dll + false + + + $(DalamudLibPath)Lumina.Excel.dll + false + + + + diff --git a/SliceIsRight.json b/SliceIsRight.json new file mode 100644 index 0000000..bd453c5 --- /dev/null +++ b/SliceIsRight.json @@ -0,0 +1,12 @@ +{ + "Author": "???", + "Name": "Bamboo Chopper", + "Punchline": "Shows where Bamboo falls.", + "Description": "Shows where Bamboo falls.", + "InternalName": "chopbamboo", + "DalamudApiLevel": 4, + "Tags": [ + "gold saucer", + "yojimbo" + ] +} diff --git a/SliceIsRight.sln b/SliceIsRight.sln new file mode 100644 index 0000000..9c6d351 --- /dev/null +++ b/SliceIsRight.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29709.97 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SliceIsRight", "SliceIsRight.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.ActiveCfg = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64 + {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} + EndGlobalSection +EndGlobal diff --git a/SlightIsRightPlugin.cs b/SlightIsRightPlugin.cs new file mode 100644 index 0000000..5dff936 --- /dev/null +++ b/SlightIsRightPlugin.cs @@ -0,0 +1,231 @@ +using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.ClientState.Objects.Enums; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Game.Gui; +using Dalamud.Interface; +using Dalamud.IoC; +using Dalamud.Plugin; +using ImGuiNET; +using System; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace SliceIsRight +{ + public sealed class SliceIsRightPlugin : IDalamudPlugin + { + public string Name => "Slice is Right"; + + [PluginService] + [RequiredVersion("1.0")] + private DalamudPluginInterface PluginInterface { get; set; } + + [PluginService] + private ObjectTable ObjectTable { get; set; } + + [PluginService] + private GameGui GameGui { get; set; } + + [PluginService] + private ClientState ClientState { get; set; } + + private const ushort GoldSaucerTerritoryId = 144; + private bool IsInGoldSaucer { get; set; } + + public SliceIsRightPlugin() + { + PluginInterface!.UiBuilder.Draw += DrawUI; + ClientState!.TerritoryChanged += TerritoryChanged; + IsInGoldSaucer = ClientState.TerritoryType == GoldSaucerTerritoryId; + } + + private void TerritoryChanged(object? sender, ushort e) + { + IsInGoldSaucer = e == GoldSaucerTerritoryId; + } + + public void Dispose() + { + PluginInterface.UiBuilder.Draw -= DrawUI; + ClientState.TerritoryChanged -= TerritoryChanged; + } + + private void DrawUI() + { + /* + if (ImGui.Begin("Debug", ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoInputs)) + { + ImGui.Text("Current zone: " + this.ClientState.TerritoryType); + ImGui.Text("Logged in: " + this.ClientState.IsLoggedIn + ", InGS: " + this.IsInGoldSaucer); + ImGui.End(); + } + */ + if (!ClientState.IsLoggedIn || !IsInGoldSaucer || ObjectTable == null) + return; + + + for (int index = 0; index < ObjectTable.Length; ++ index) + { + GameObject? obj = ObjectTable[index]; + if (obj == null) + continue; + + int model = Marshal.ReadInt32(obj.Address + 128); + if (obj.ObjectKind == ObjectKind.EventObj && (model >= 2010777 && model <= 2010779)) + { + //this.DebugObject(index, obj, model); + RenderObject(index, obj, model); + } + else if (ClientState.LocalPlayer?.ObjectId == obj.ObjectId) + { + // local player + //this.DebugObject(index, obj, model); + //this.RenderObject(index, obj, 2010777); + } + } + } + + + private void DebugObject(int index, GameObject obj, int model) + { + if (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}[{index}] - {obj.ObjectKind} - {model}: {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) + return; + + if (obj.YalmDistanceX > 20f) + return; + + ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y)); + + ImGui.SetNextWindowBgAlpha(Math.Max(1f - (obj.YalmDistanceX / 20f), 0.2f)); + if (ImGui.Begin( + $"Actor{index}##ActorWindow{index}", + ImGuiWindowFlags.NoDecoration | + ImGuiWindowFlags.AlwaysAutoResize | + ImGuiWindowFlags.NoSavedSettings | + ImGuiWindowFlags.NoMove | + ImGuiWindowFlags.NoMouseInputs | + ImGuiWindowFlags.NoDocking | + ImGuiWindowFlags.NoFocusOnAppearing | + ImGuiWindowFlags.NoNav)) + ImGui.Text(objectText); + ImGui.End(); + } + } + + private void RenderObject(int index, GameObject obj, int model) + { + ImGui.PushID("booWindow" + index); + + ImGui.PushStyleVar((ImGuiStyleVar)1, new Vector2(0.0f, 0.0f)); + ImGuiHelpers.SetNextWindowPosRelativeMainViewport(new Vector2(0.0f, 0.0f), ImGuiCond.None, new Vector2()); + ImGui.Begin("drawCtx" + index, ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoInputs); + ImGui.SetWindowSize(ImGui.GetIO().DisplaySize); + + switch (model) + { + case 2010777: + DrawRectWorld(obj.Position, obj.Rotation + 1.570796f, 25f, 5f, ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(0.0f, 0.0f, 1f, 0.15f)))); + break; + + case 2010778: + DrawRectWorld(obj.Position, obj.Rotation + 1.570796f, 25f, 5f, ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(0.0f, 1f, 0.0f, 0.15f)))); + DrawRectWorld(obj.Position, obj.Rotation - 1.570796f, 25f, 5f, ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(0.0f, 1f, 0.0f, 0.15f)))); + break; + + case 2010779: + DrawFilledCircleWorld(obj.Position, 11f, ImGui.GetColorU32(ImGui.ColorConvertFloat4ToU32(new Vector4(1, 0, 0, 0.4f)))); + break; + } + + ImGui.End(); + ImGui.PopStyleVar(); + + ImGui.PopID(); + } + + private void DrawFilledCircleWorld(Vector3 center, float radius, uint colour) + { + int num = 100; + for (int index = 0; index <= 200; ++index) + { + GameGui.WorldToScreen(new Vector3(center.X + radius * (float)Math.Sin(Math.PI / num * index), center.Y, center.Z + radius * (float)Math.Cos(Math.PI / num * index)), out Vector2 vector2); + ImGui.GetWindowDrawList().PathLineTo(vector2); + } + ImGui.GetWindowDrawList().PathFillConvex(colour); + } + + private void DrawRectWorld(Vector3 center, float rotation, float length, float width, uint colour) + { + Vector2 vector2_1 = ImGui.GetIO().DisplaySize; + Vector3 vector3_1 = new Vector3(center.X + width * 0.5f * (float)Math.Sin(Math.PI / 2.0 + rotation), center.Y, center.Z + width * 0.5f * (float)Math.Cos(Math.PI / 2.0 + rotation)); + Vector3 vector3_2 = new Vector3(center.X + width * 0.5f * (float)Math.Sin(rotation - Math.PI / 2.0), center.Y, center.Z + width * 0.5f * (float)Math.Cos(rotation - Math.PI / 2.0)); + Vector3 vector3_3 = new Vector3(center.X, center.Y, center.Z); + int num1 = 200; + double num2 = (double)length / (double)num1; + + var drawList = ImGui.GetWindowDrawList(); + for (int index = 1; index <= num1; ++index) + { + Vector3 vector3_4 = vector3_1 = new Vector3((float)(vector3_1.X + length / (double)num1 * Math.Sin(0.0 + rotation)), vector3_1.Y, (float)(vector3_1.Z + length / (double)num1 * Math.Cos(0.0 + rotation))); + Vector3 vector3_5 = vector3_2 = new Vector3((float)(vector3_2.X + length / (double)num1 * Math.Sin(0.0 + rotation)), vector3_2.Y, (float)(vector3_2.Z + length / (double)num1 * Math.Cos(0.0 + rotation))); + Vector3 vector3_6 = vector3_3 = new Vector3((float)(vector3_3.X + length / (double)num1 * Math.Sin(0.0 + rotation)), vector3_3.Y, (float)(vector3_3.Z + length / (double)num1 * Math.Cos(0.0 + rotation))); + + GameGui.WorldToScreen(vector3_5, out Vector2 vector2_2); + if (vector2_2.X > 0.0 & vector2_2.X < (double)vector2_1.X | vector2_2.Y > 0.0 & vector2_2.Y < (double)vector2_1.Y) + { + drawList.PathLineTo(new Vector2((float)vector2_2.X, (float)vector2_2.Y)); + } + + GameGui.WorldToScreen(vector3_6, out vector2_2); + if (vector2_2.X > 0.0 & vector2_2.X < (double)vector2_1.X | vector2_2.Y > 0.0 & vector2_2.Y < (double)vector2_1.Y) + { + drawList.PathLineTo(new Vector2((float)vector2_2.X, (float)vector2_2.Y)); + } + + GameGui.WorldToScreen(vector3_4, out vector2_2); + if (vector2_2.X > 0.0 & vector2_2.X < (double)vector2_1.X | vector2_2.Y > 0.0 & vector2_2.Y < (double)vector2_1.Y) + { + drawList.PathLineTo(new Vector2((float)vector2_2.X, (float)vector2_2.Y)); + } + + GameGui.WorldToScreen(vector3_1, out vector2_2); + if (vector2_2.X > 0.0 & vector2_2.X < (double)vector2_1.X | vector2_2.Y > 0.0 & vector2_2.Y < (double)vector2_1.Y) + { + drawList.PathLineTo(new Vector2((float)vector2_2.X, (float)vector2_2.Y)); + } + + GameGui.WorldToScreen(vector3_3, out vector2_2); + if (vector2_2.X > 0.0 & vector2_2.X < (double)vector2_1.X | vector2_2.Y > 0.0 & vector2_2.Y < (double)vector2_1.Y) + { + drawList.PathLineTo(new Vector2((float)vector2_2.X, (float)vector2_2.Y)); + } + + GameGui.WorldToScreen(vector3_2, out vector2_2); + if (vector2_2.X > 0.0 & vector2_2.X < (double)vector2_1.X | vector2_2.Y > 0.0 & vector2_2.Y < (double)vector2_1.Y) + { + drawList.PathLineTo(new Vector2((float)vector2_2.X, (float)vector2_2.Y)); + } + + drawList.PathFillConvex(colour); + } + } + } +}