using System; using System.Collections.Generic; using Dalamud.Data; using Dalamud.Plugin; using Lumina; using Lumina.Data.Files; using Lumina.Data.Parsing.Layer; using Lumina.Excel.GeneratedSheets; namespace RoleplayersToolbox.Tools.Housing { internal class HousingInfo { private DataManager Data { get; } private GameData? GameData { get; } private Dictionary LgbObjects { get; } = new(); internal HousingDistances Distances { get; } internal HousingInfo(Plugin plugin) { this.Data = plugin.Interface.Data; this.GameData = plugin.GameData; this.Distances = this.PrecalculateClosest(); } private HousingAethernet? CalculateClosest(HousingArea area, uint plot) { // subtract 1 from the subrow because Lumina is zero-indexed even though the sheet isn't var info = this.Data.GetExcelSheet().GetRow((uint) area, plot - 1); if (info == null) { return null; } var (x, y, z) = (info.X, info.Y, info.Z); (HousingAethernet aethernet, double distance)? shortest = null; foreach (var aethernet in this.Data.GetExcelSheet()) { if (aethernet.TerritoryType.Row != (uint) area) { continue; } var level = aethernet.Level.Row; if (!this.LgbObjects.TryGetValue(level, out var obj)) { continue; } var translation = obj.Transform.Translation; var xDiff = translation.X - x; var yDiff = translation.Y - y; var zDiff = translation.Z - z; var sumOfSquares = Math.Pow(xDiff, 2) + Math.Pow(yDiff, 2) + Math.Pow(zDiff, 2); var distance = Math.Sqrt(sumOfSquares); if (shortest == null || shortest.Value.distance > distance) { shortest = (aethernet, distance); } } return shortest?.aethernet; } private HousingDistances PrecalculateClosest() { var allClosest = new Dictionary>(); foreach (var area in (HousingArea[]) Enum.GetValues(typeof(HousingArea))) { this.LoadObjectsFromArea(area); for (var plot = 1u; plot < 63; plot++) { var closest = this.CalculateClosest(area, plot); if (closest == null) { continue; } if (!allClosest.ContainsKey(area)) { allClosest[area] = new Dictionary(); } allClosest[area][plot] = closest; } } return new HousingDistances(this.Data, allClosest); } internal LgbFile? GetLgbFromPath(string path) { if (this.GameData == null) { return null; } try { return this.GameData.GetFile(path); } catch (Exception ex) { PluginLog.LogError(ex, $"Error reading lgb file: {path}"); return null; } } internal LgbFile? GetLgbFromArea(HousingArea area) { var territory = this.Data.GetExcelSheet().GetRow((uint) area); if (territory == null) { return null; } var path = territory.Bg.ToString(); path = path.Substring(0, path.LastIndexOf('/')); return this.GetLgbFromPath($"bg/{path}/planmap.lgb"); } internal void LoadObjectsFromFile(LgbFile lgb) { foreach (var layer in lgb.Layers) { foreach (var obj in layer.InstanceObjects) { this.LgbObjects[obj.InstanceId] = obj; } } } internal void LoadObjectsFromPath(string path) { var lgb = this.GetLgbFromPath(path); if (lgb == null) { return; } this.LoadObjectsFromFile(lgb); } internal void LoadObjectsFromArea(HousingArea area) { var lgb = this.GetLgbFromArea(area); if (lgb == null) { return; } this.LoadObjectsFromFile(lgb); } } }