using System; using System.Numerics; using AcDream.Core.Selection; using AcDream.Core.World; namespace AcDream.Core.Tests.Selection; public sealed class WorldPickerRectOverloadTests { private static (Matrix4x4 view, Matrix4x4 proj, Vector2 viewport) StdCam() { var view = Matrix4x4.Identity; var proj = Matrix4x4.CreatePerspectiveFieldOfView( MathF.PI * 0.5f, 800f / 600f, 0.1f, 100f); var viewport = new Vector2(800, 600); return (view, proj, viewport); } private static WorldEntity MakeEntity(uint serverGuid, Vector3 position) => new() { Id = serverGuid == 0u ? 1u : serverGuid, ServerGuid = serverGuid, SourceGfxObjOrSetupId = 0u, Position = position, Rotation = Quaternion.Identity, MeshRefs = Array.Empty(), }; [Fact] public void Pick_RectHitTest_ReturnsHitWhenMouseInsideRect() { var (view, proj, viewport) = StdCam(); var e = MakeEntity(0x10001u, new Vector3(0, 0, -10)); uint? picked = WorldPicker.Pick( mouseX: 400f, mouseY: 300f, view, proj, viewport, new[] { e }, skipServerGuid: 0u, sphereForEntity: x => ((Vector3, float)?)(x.Position, 1.0f), inflatePixels: 0f); Assert.Equal(0x10001u, picked); } [Fact] public void Pick_RectHitTest_ReturnsNullWhenMouseOutsideRect() { var (view, proj, viewport) = StdCam(); var e = MakeEntity(0x10001u, new Vector3(0, 0, -10)); uint? picked = WorldPicker.Pick( mouseX: 50f, mouseY: 50f, view, proj, viewport, new[] { e }, skipServerGuid: 0u, sphereForEntity: x => ((Vector3, float)?)(x.Position, 1.0f), inflatePixels: 0f); Assert.Null(picked); } [Fact] public void Pick_RectHitTest_PicksNearerWhenRectsOverlap() { var (view, proj, viewport) = StdCam(); var near = MakeEntity(0x10001u, new Vector3(0, 0, -8)); var far = MakeEntity(0x10002u, new Vector3(0, 0, -15)); uint? picked = WorldPicker.Pick( mouseX: 400f, mouseY: 300f, view, proj, viewport, new[] { far, near } /* deliberately reversed */, skipServerGuid: 0u, sphereForEntity: x => ((Vector3, float)?)(x.Position, 1.0f), inflatePixels: 0f); Assert.Equal(0x10001u, picked); } [Fact] public void Pick_RectHitTest_NullResolverSkipsCandidates() { var (view, proj, viewport) = StdCam(); var e1 = MakeEntity(0x10001u, new Vector3(0, 0, -10)); var e2 = MakeEntity(0x10002u, new Vector3(0, 0, -20)); uint? picked = WorldPicker.Pick( mouseX: 400f, mouseY: 300f, view, proj, viewport, new[] { e1, e2 }, skipServerGuid: 0u, sphereForEntity: x => x.ServerGuid == 0x10001u ? ((Vector3, float)?)null : ((Vector3, float)?)(x.Position, 1.0f), inflatePixels: 0f); Assert.Equal(0x10002u, picked); } [Fact] public void Pick_RectHitTest_RespectsSkipServerGuid() { var (view, proj, viewport) = StdCam(); var player = MakeEntity(0x5000000Au, new Vector3(0, 0, -10)); var npc = MakeEntity(0x10002u, new Vector3(0, 0, -15)); uint? picked = WorldPicker.Pick( mouseX: 400f, mouseY: 300f, view, proj, viewport, new[] { player, npc }, skipServerGuid: 0x5000000Au, sphereForEntity: x => ((Vector3, float)?)(x.Position, 1.0f), inflatePixels: 0f); Assert.Equal(0x10002u, picked); } [Fact] public void Pick_RectHitTest_InflateExpandsClickableArea() { var (view, proj, viewport) = StdCam(); var e = MakeEntity(0x10001u, new Vector3(0, 0, -10)); uint? withoutInflate = WorldPicker.Pick( mouseX: 400f + 200f, mouseY: 300f, view, proj, viewport, new[] { e }, skipServerGuid: 0u, sphereForEntity: x => ((Vector3, float)?)(x.Position, 1.0f), inflatePixels: 0f); Assert.Null(withoutInflate); uint? withInflate = WorldPicker.Pick( mouseX: 400f + 200f, mouseY: 300f, view, proj, viewport, new[] { e }, skipServerGuid: 0u, sphereForEntity: x => ((Vector3, float)?)(x.Position, 1.0f), inflatePixels: 250f); Assert.Equal(0x10001u, withInflate); } }