From db832587031a626d1c4ae367f859f7c313aa873c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E6=B0=B4?= <1123993881@qq.com> Date: Sat, 27 May 2023 23:12:50 +0800 Subject: [PATCH] fix: changed the positional showcase. --- RotationSolver/Localization/Localization.json | 1 + RotationSolver/Localization/Strings.cs | 2 +- RotationSolver/UI/OverlayWindow.cs | 185 ++++++++++++------ .../UI/RotationConfigWindow_Debug.cs | 4 - 4 files changed, 128 insertions(+), 64 deletions(-) diff --git a/RotationSolver/Localization/Localization.json b/RotationSolver/Localization/Localization.json index a8759cbdc..8d70fd2a1 100644 --- a/RotationSolver/Localization/Localization.json +++ b/RotationSolver/Localization/Localization.json @@ -147,6 +147,7 @@ "ConfigWindow_Param_HealthHealerRatio": "Heal healer first if its HP threshold is lower than this.", "ConfigWindow_Param_HealthTankRatio": "Heal tank first if its HP threshold is lower than this.", "ConfigWindow_Param_DistanceForMoving": "If the distance between Melee or Tank to target is less than this, using moving ability as attack ability.", + "ConfigWindow_Param_HealWhenNothingTodoBelow": "Healing the members with GCD if there is nothing to do in combat and their min HP ratio is lower than this.", "ConfigWindow_Param_HealingOfTimeSubtractSingle": "Set the HP threshold reduce with hot effect(single)", "ConfigWindow_Param_HealthForDyingTank": "Set the HP threshold for tank to use invincibility", "ConfigWindow_Param_MeleeRangeOffset": "Melee Range action using offset", diff --git a/RotationSolver/Localization/Strings.cs b/RotationSolver/Localization/Strings.cs index 61205d34b..32a96b2e0 100644 --- a/RotationSolver/Localization/Strings.cs +++ b/RotationSolver/Localization/Strings.cs @@ -212,7 +212,7 @@ internal partial class Strings public string ConfigWindow_Param_DistanceForMoving { get; set; } = "If the distance between Melee or Tank to target is less than this, using moving ability as attack ability."; - public string ConfigWindow_Param_HealWhenNothingTodoBelow { get; set; } = "Healing the members with GCD if there is nothing to do in combat."; + public string ConfigWindow_Param_HealWhenNothingTodoBelow { get; set; } = "Healing the members with GCD if there is nothing to do in combat and their min HP ratio is lower than this."; public string ConfigWindow_Param_HealingOfTimeSubtractSingle { get; set; } = "Set the HP threshold reduce with hot effect(single)"; public string ConfigWindow_Param_HealthForDyingTank { get; set; } = "Set the HP threshold for tank to use invincibility"; diff --git a/RotationSolver/UI/OverlayWindow.cs b/RotationSolver/UI/OverlayWindow.cs index 07d5b2f64..6f730a317 100644 --- a/RotationSolver/UI/OverlayWindow.cs +++ b/RotationSolver/UI/OverlayWindow.cs @@ -1,4 +1,5 @@ -using Dalamud.Logging; +using Dalamud.Interface.Colors; +using Dalamud.Logging; using ECommons.DalamudServices; using ECommons.GameHelpers; using FFXIVClientStructs.FFXIV.Client.Game.Event; @@ -131,27 +132,26 @@ private static void DrawTarget(BattleChara tar, uint color, float radius, out Ve const int COUNT = 20; private static void DrawPositional() { - //if (!Player.Object.IsJobCategory(JobRole.Tank) - // && !Player.Object.IsJobCategory(JobRole.Melee)) return; + if (!Player.Object.IsJobCategory(JobRole.Tank) + && !Player.Object.IsJobCategory(JobRole.Melee)) return; - //var target = ActionUpdater.NextGCDAction?.Target?.IsNPCEnemy() ?? false - // ? ActionUpdater.NextGCDAction.Target - // : Svc.Targets.Target?.IsNPCEnemy() ?? false - // ? Svc.Targets.Target - // : null; + var target = ActionUpdater.NextGCDAction?.Target?.IsNPCEnemy() ?? false + ? ActionUpdater.NextGCDAction.Target + : Svc.Targets.Target?.IsNPCEnemy() ?? false + ? Svc.Targets.Target + : null; - var target = Player.Object; if (target == null) return; - //if (ActionUpdater.NextGCDAction != null - // && !ActionUpdater.NextGCDAction.IsSingleTarget) return; + if (ActionUpdater.NextGCDAction != null + && !ActionUpdater.NextGCDAction.IsSingleTarget) return; Vector3 pPosition = target.Position; float radius = target.HitboxRadius + Player.Object.HitboxRadius + 3; float rotation = target.Rotation; - //if (Service.Config.DrawMeleeOffset && DataCenter.StateType != StateCommandType.Cancel) + if (Service.Config.DrawMeleeOffset && DataCenter.StateType != StateCommandType.Cancel) { var offsetColor = new Vector3(0.8f, 0.3f, 0.2f); var pts1 = SectorPlots(pPosition, radius, 0, 4 * COUNT, 2 * Math.PI); @@ -221,11 +221,14 @@ static void DrawRange(IEnumerable pts, bool wrong) static void DrawFill(IEnumerable pts, Vector3 color) { - foreach (var pt in pts) + foreach (var set in ConvexPoints(pts.ToArray())) { - ImGui.GetWindowDrawList().PathLineTo(pt); + foreach (var pt in set) + { + ImGui.GetWindowDrawList().PathLineTo(pt); + } + ImGui.GetWindowDrawList().PathFillConvex(ImGui.GetColorU32(new Vector4(color.X, color.Y, color.Z, Service.Config.AlphaInFill))); } - ImGui.GetWindowDrawList().PathFillConvex(ImGui.GetColorU32(new Vector4(color.X, color.Y, color.Z, Service.Config.AlphaInFill))); } static void DrawBoundary(IEnumerable pts, Vector3 color) @@ -268,16 +271,102 @@ public static IEnumerable ClosePoints(IEnumerable pts) return pts; } - public static IEnumerable GetPtsOnScreen(IEnumerable pts) + private static IEnumerable ConvexPoints(Vector2[] points) { - var cameraPts = ProjectPtsOnGround(pts, 3).Select(WorldToCamera).ToArray(); - var changedPts = ChangePtsBehindCamera(cameraPts); + if(points.Length < 4) + { + return new Vector2[][] { points }; + } - return changedPts.Select(p => + int breakIndex = -1; + Vector2 dir = Vector2.Zero; + for (int i = 0; i < points.Length; i++) { - Vector2? result = CameraToScreenCanSee(p, out var screenPos) ? screenPos : null; - return result; - }).Where(p => p.HasValue).Select(p => p.Value); + var pt1 = points[(i - 1 + points.Length) % points.Length]; + var pt2 = points[i]; + var pt3 = points[(i + 1) % points.Length]; + + var vec1 = pt2 - pt1; + var vec2 = pt3 - pt2; + if(Vector3.Cross(new Vector3(vec1.X, vec1.Y, 0), new Vector3(vec2.X, vec2.Y, 0)).Z > 0) + { + breakIndex = i; + dir = vec1 / vec1.Length() - vec2 / vec2.Length(); + dir /= dir.Length(); + break; + } + } + + if (breakIndex < 0) + { + return new Vector2[][] { points }; + } + else + { + try + { + var pt = points[breakIndex]; + var index = 0; + double maxValue = double.MinValue; + for (int i = 0; i < points.Length; i++) + { + if (Math.Abs(i - breakIndex) < 2) continue; + if (Math.Abs(i + points.Length - breakIndex) < 2) continue; + if (Math.Abs(i - points.Length - breakIndex) < 2) continue; + var d = points[i] - pt; + d /= d.Length(); + + var angle = Vector2.Dot(d, dir); + + if (angle > maxValue) + { + maxValue = angle; + index = i; + } + } + + var minIndex = Math.Min(breakIndex, index); + var maxIndex = Math.Max(breakIndex, index); + + var list1 = new List(points.Length); + var list2 = new List(points.Length); + for (int i = 0; i < points.Length; i++) + { + if (i <= minIndex || i >= maxIndex) + { + list1.Add(points[i]); + } + + if (i >= minIndex && i <= maxIndex) + { + list2.Add(points[i]); + } + } + + return ConvexPoints(list1.ToArray()).Union(ConvexPoints(list2.ToArray())).Where(l => l.Count() > 2); + } + catch (Exception ex) + { + PluginLog.Warning(ex, "Bad at drawing"); + return new Vector2[][] { points }; + } + } + } + + public static unsafe IEnumerable GetPtsOnScreen(IEnumerable pts) + { + var camera = (Vector3)CameraManager.Instance()->CurrentCamera->Object.Position; + var cameraPts = ProjectPtsOnGround(pts, 3) + //.Where(p => + //{ + // var vec = p - camera; + // var dis = vec.Length() - 0.1f; + // return !BGCollisionModule.Raycast(camera, vec, out _, dis); + //}) + .Select(WorldToCamera).ToArray(); + var changedPts = ChangePtsBehindCamera(cameraPts); + + return changedPts.Select(CameraToScreen); } private static IEnumerable ChangePtsBehindCamera(Vector3[] cameraPts) @@ -312,13 +401,21 @@ private static IEnumerable ChangePtsBehindCamera(Vector3[] cameraPts) private static IEnumerable ProjectPtsOnGround(IEnumerable pts, float height) => pts.Select(pt => { + Vector3? result; var pUp = pt + Vector3.UnitY * height; - if (BGCollisionModule.Raycast(pUp, -Vector3.UnitY, out var hit)) + if (BGCollisionModule.Raycast(pt + Vector3.UnitY * 100, -Vector3.UnitY, out var hit)) + { + var p = hit.Point; + p.Y = Math.Max(p.Y, pt.Y - height); + p.Y = Math.Min(p.Y, pt.Y + height); + result = p; + } + else { - return hit.Point; + result = null; } - return pt; - }); + return result; + }).Where(pt => pt.HasValue).Select(pt => pt.Value); const float PLANE_Z = 0.001f; public static void GetPointOnPlane(Vector3 front, ref Vector3 back) @@ -332,40 +429,10 @@ public static void GetPointOnPlane(Vector3 front, ref Vector3 back) back.Z = PLANE_Z; } - static unsafe Matrix4x4 worldToCamera - { - get - { - var camera = CameraManager.Instance()->CurrentCamera; - return camera->ViewMatrix * camera->RenderCamera->ProjectionMatrix; - } - } - - public static Vector3 WorldToCamera(Vector3 worldPos) + public static unsafe Vector3 WorldToCamera(Vector3 worldPos) { - return Vector3.Transform(worldPos, worldToCamera); - } - - private static unsafe bool CameraToScreenCanSee(Vector3 cameraPos, out Vector2 screenPos) - { - screenPos = CameraToScreen(cameraPos); - try - { - var camera = CameraManager.Instance()->CurrentCamera; - Ray ray = camera->ScreenPointToRay(screenPos); - - if (BGCollisionModule.Raycast(ray.Origin, ray.Direction, out var hit) - && Math.Abs(cameraPos.Length() - Vector3.Distance(hit.Point, camera->Object.Position)) > 0.1) - { - return false; - } - return true; - } - catch(Exception e) - { - PluginLog.Warning(e, e.Message); - return false; - } + var camera = CameraManager.Instance()->CurrentCamera; + return Vector3.Transform(worldPos, camera->ViewMatrix * camera->RenderCamera->ProjectionMatrix); } public static unsafe Vector2 CameraToScreen(Vector3 cameraPos) diff --git a/RotationSolver/UI/RotationConfigWindow_Debug.cs b/RotationSolver/UI/RotationConfigWindow_Debug.cs index 4b4e2bba7..df1257b69 100644 --- a/RotationSolver/UI/RotationConfigWindow_Debug.cs +++ b/RotationSolver/UI/RotationConfigWindow_Debug.cs @@ -63,10 +63,6 @@ private unsafe void DrawStatus() ImGui.Text("Count Down: " + Service.CountDownTime.ToString()); ImGui.Text("Fetch Time: " + DataCenter.FetchTime.ToString()); - //ImGui.Text(CameraManager.Instance()->CurrentCamera->LookAtVector.ToString()); - //ImGui.Text(CameraManager.Instance()->CurrentCamera->Vector_1.ToString()); - //ImGui.Text(Player.Object.Position.ToString()); - foreach (var status in Player.Object.StatusList) { var source = status.SourceId == Player.Object.ObjectId ? "You" : Svc.Objects.SearchById(status.SourceId) == null ? "None" : "Others";