using System.Collections.Generic; using System.Linq; using System.Numerics; using Dalamud.Plugin.Services; using LLib.Shop; using Lumina.Excel; using Lumina.Excel.Sheets; using Microsoft.Extensions.Logging; namespace Questionable.Data; internal sealed class MenderDataService(IDataManager dataManager, NpcPositionCache npcPositionCache, ILogger logger) { public static readonly IReadOnlyList CityFallbacks = new global::_003C_003Ez__ReadOnlyArray(new MenderNpc[3] { new MenderNpc(1003251u, 128, new Vector3(17.715698f, 40.200005f, 3.9520264f)), new MenderNpc(1000394u, 132, new Vector3(24.826416f, -8f, 93.18677f)), new MenderNpc(1004416u, 130, new Vector3(32.85266f, 6.999999f, -81.31531f)) }); private readonly object _lock = new object(); private ILookup? _byTerritory; public MenderNpc? FindNearestInTerritory(ushort territoryId, Vector3 nearPosition) { ILookup lookup; lock (_lock) { if (_byTerritory == null && !npcPositionCache.IsBuilt) { return null; } lookup = _byTerritory ?? (_byTerritory = BuildIndex()); } return lookup[territoryId].OrderBy((MenderNpc x) => Vector3.DistanceSquared(x.Position, nearPosition)).FirstOrDefault(); } private ILookup BuildIndex() { ExcelSheet excelSheet = dataManager.GetExcelSheet(); List list = new List(); foreach (uint allNpcId in npcPositionCache.GetAllNpcIds()) { if (!excelSheet.TryGetRow(allNpcId, out var row)) { continue; } bool flag = false; for (int i = 0; i < row.ENpcData.Count; i++) { if (row.ENpcData[i].RowId == 720915) { flag = true; break; } } if (flag) { (ushort, Vector3)? position = npcPositionCache.GetPosition(allNpcId); if (position.HasValue) { (ushort, Vector3) valueOrDefault = position.GetValueOrDefault(); list.Add(new MenderNpc(allNpcId, valueOrDefault.Item1, valueOrDefault.Item2)); } } } logger.LogDebug("Mender index built with {Count} menders across {Territories} territories", list.Count, list.Select((MenderNpc x) => x.TerritoryId).Distinct().Count()); return list.ToLookup((MenderNpc x) => x.TerritoryId); } }