269 lines
7.5 KiB
C#
269 lines
7.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Numerics;
|
|
using System.Text.Json;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Interface.Utility.Raii;
|
|
using Dalamud.Plugin.Services;
|
|
using LLib.ImGui;
|
|
using Microsoft.Extensions.Logging;
|
|
using SmartNav.Data;
|
|
using SmartNav.Model.Navigation;
|
|
|
|
namespace Questionable.Windows.SmartNavComponents;
|
|
|
|
internal sealed class SubRegionMapPanel : IEditablePolygonSet
|
|
{
|
|
internal sealed class EditableSubRegion
|
|
{
|
|
public string Id = string.Empty;
|
|
|
|
public string Comment = string.Empty;
|
|
|
|
public float MinYEdit;
|
|
|
|
public float MaxYEdit;
|
|
|
|
public bool HasMinY;
|
|
|
|
public bool HasMaxY;
|
|
|
|
public List<Vector2> Vertices = new List<Vector2>();
|
|
}
|
|
|
|
private static readonly uint[] SubRegionColors = new uint[8] { 1610612991u, 1610678016u, 1627332640u, 1610678271u, 1627324671u, 1627389696u, 1627357184u, 1619001599u };
|
|
|
|
private readonly MapTextureService _mapService;
|
|
|
|
private readonly MapPolygonEditor _editor;
|
|
|
|
private readonly ZoneSubRegionService _zoneSubRegionService;
|
|
|
|
private readonly IClientState _clientState;
|
|
|
|
private readonly IObjectTable _objectTable;
|
|
|
|
private uint _loadedTerritory;
|
|
|
|
private readonly List<EditableSubRegion> _subRegions = new List<EditableSubRegion>();
|
|
|
|
public int SelectedIndex
|
|
{
|
|
get
|
|
{
|
|
return _editor.SelectedIndex;
|
|
}
|
|
set
|
|
{
|
|
_editor.SelectedIndex = value;
|
|
}
|
|
}
|
|
|
|
public bool IsDrawing => _editor.IsDrawing;
|
|
|
|
public IReadOnlyList<EditableSubRegion> SubRegions => _subRegions;
|
|
|
|
int IEditablePolygonSet.PolygonCount => _subRegions.Count;
|
|
|
|
public SubRegionMapPanel(ITextureProvider textureProvider, IDataManager dataManager, ZoneSubRegionService zoneSubRegionService, IClientState clientState, IObjectTable objectTable, ILoggerFactory loggerFactory)
|
|
{
|
|
_mapService = new MapTextureService(textureProvider, dataManager, loggerFactory.CreateLogger<MapTextureService>());
|
|
_editor = new MapPolygonEditor(_mapService);
|
|
_zoneSubRegionService = zoneSubRegionService;
|
|
_clientState = clientState;
|
|
_objectTable = objectTable;
|
|
}
|
|
|
|
public void Draw(JsonSerializerOptions jsonOptions)
|
|
{
|
|
uint territoryType = _clientState.TerritoryType;
|
|
EnsureLoaded(territoryType);
|
|
_mapService.LoadForTerritory(territoryType);
|
|
DrawToolbar(jsonOptions);
|
|
Vector3? playerPosition = _objectTable.LocalPlayer?.Position;
|
|
Vector2 contentRegionAvail = ImGui.GetContentRegionAvail();
|
|
_editor.Draw(this, playerPosition, new Vector2(contentRegionAvail.X, 500f));
|
|
}
|
|
|
|
private void DrawToolbar(JsonSerializerOptions jsonOptions)
|
|
{
|
|
if (_editor.IsDrawing)
|
|
{
|
|
ImGui.TextColored(new Vector4(0.2f, 1f, 0.2f, 1f), "Drawing polygon... Click to add vertices. Close: click first vertex / Enter / double-click. Escape cancels.");
|
|
}
|
|
else
|
|
{
|
|
if (ImGui.Button("Draw Polygon"))
|
|
{
|
|
_editor.StartDrawing();
|
|
}
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Reset View"))
|
|
{
|
|
_editor.ResetView();
|
|
}
|
|
if (_editor.SelectedIndex >= 0 && _editor.SelectedIndex < _subRegions.Count)
|
|
{
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Delete Selected"))
|
|
{
|
|
_subRegions.RemoveAt(_editor.SelectedIndex);
|
|
_editor.SelectedIndex = -1;
|
|
}
|
|
}
|
|
ImGui.SameLine();
|
|
if (ImGui.Button("Copy All JSON"))
|
|
{
|
|
TerritorySubRegions value = BuildTerritorySubRegions();
|
|
ImGui.SetClipboardText(JsonSerializer.Serialize(new Dictionary<string, object> { [_clientState.TerritoryType.ToString(CultureInfo.InvariantCulture)] = value }, jsonOptions));
|
|
}
|
|
}
|
|
if (_editor.SelectedIndex >= 0 && _editor.SelectedIndex < _subRegions.Count)
|
|
{
|
|
EditableSubRegion editableSubRegion = _subRegions[_editor.SelectedIndex];
|
|
ImGui.SetNextItemWidth(120f);
|
|
ImGui.InputText("ID##mapSr", ref editableSubRegion.Id, 64);
|
|
ImGui.SameLine();
|
|
ImGui.SetNextItemWidth(200f);
|
|
ImGui.InputText("Comment##mapSr", ref editableSubRegion.Comment, 128);
|
|
ImGui.Checkbox("MinY##mapSrCb", ref editableSubRegion.HasMinY);
|
|
ImGui.SameLine();
|
|
using (ImRaii.Disabled(!editableSubRegion.HasMinY))
|
|
{
|
|
ImGui.SetNextItemWidth(80f);
|
|
ImGui.InputFloat("##minY", ref editableSubRegion.MinYEdit, 0f, 0f, "%.1f");
|
|
}
|
|
ImGui.SameLine();
|
|
ImGui.Checkbox("MaxY##mapSrCb", ref editableSubRegion.HasMaxY);
|
|
ImGui.SameLine();
|
|
using (ImRaii.Disabled(!editableSubRegion.HasMaxY))
|
|
{
|
|
ImGui.SetNextItemWidth(80f);
|
|
ImGui.InputFloat("##maxY", ref editableSubRegion.MaxYEdit, 0f, 0f, "%.1f");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EnsureLoaded(uint territory)
|
|
{
|
|
if (territory == _loadedTerritory)
|
|
{
|
|
return;
|
|
}
|
|
_loadedTerritory = territory;
|
|
_subRegions.Clear();
|
|
_editor.SelectedIndex = -1;
|
|
if (!_zoneSubRegionService.HasSubRegions(territory))
|
|
{
|
|
return;
|
|
}
|
|
IReadOnlyList<SubRegionDefinition> subRegions = _zoneSubRegionService.GetSubRegions(territory);
|
|
if (subRegions == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (SubRegionDefinition item in subRegions)
|
|
{
|
|
List<Vector2> list = new List<Vector2>(item.Vertices.Count);
|
|
foreach (SubRegionVertex vertex in item.Vertices)
|
|
{
|
|
list.Add(new Vector2(vertex.X, vertex.Z));
|
|
}
|
|
_subRegions.Add(new EditableSubRegion
|
|
{
|
|
Id = item.Id,
|
|
Comment = (item.Comment ?? string.Empty),
|
|
MinYEdit = item.MinY.GetValueOrDefault(),
|
|
MaxYEdit = item.MaxY.GetValueOrDefault(),
|
|
HasMinY = item.MinY.HasValue,
|
|
HasMaxY = item.MaxY.HasValue,
|
|
Vertices = list
|
|
});
|
|
}
|
|
}
|
|
|
|
public TerritorySubRegions BuildTerritorySubRegions()
|
|
{
|
|
TerritorySubRegions territorySubRegions = new TerritorySubRegions();
|
|
foreach (EditableSubRegion subRegion in _subRegions)
|
|
{
|
|
SubRegionDefinition subRegionDefinition = new SubRegionDefinition
|
|
{
|
|
Id = subRegion.Id,
|
|
Comment = (string.IsNullOrEmpty(subRegion.Comment) ? null : subRegion.Comment),
|
|
MinY = (subRegion.HasMinY ? new float?(subRegion.MinYEdit) : ((float?)null)),
|
|
MaxY = (subRegion.HasMaxY ? new float?(subRegion.MaxYEdit) : ((float?)null))
|
|
};
|
|
foreach (Vector2 vertex in subRegion.Vertices)
|
|
{
|
|
subRegionDefinition.Vertices.Add(new SubRegionVertex
|
|
{
|
|
X = MathF.Round(vertex.X, 1),
|
|
Z = MathF.Round(vertex.Y, 1)
|
|
});
|
|
}
|
|
territorySubRegions.SubRegions.Add(subRegionDefinition);
|
|
}
|
|
return territorySubRegions;
|
|
}
|
|
|
|
public void ImportVertices(IReadOnlyList<SubRegionVertex> vertices, string id, string comment)
|
|
{
|
|
List<Vector2> list = new List<Vector2>(vertices.Count);
|
|
foreach (SubRegionVertex vertex in vertices)
|
|
{
|
|
list.Add(new Vector2(vertex.X, vertex.Z));
|
|
}
|
|
_subRegions.Add(new EditableSubRegion
|
|
{
|
|
Id = id,
|
|
Comment = comment,
|
|
Vertices = list
|
|
});
|
|
_editor.SelectedIndex = _subRegions.Count - 1;
|
|
}
|
|
|
|
public List<SubRegionVertex> ExportSelectedVertices()
|
|
{
|
|
if (_editor.SelectedIndex < 0 || _editor.SelectedIndex >= _subRegions.Count)
|
|
{
|
|
return new List<SubRegionVertex>();
|
|
}
|
|
EditableSubRegion editableSubRegion = _subRegions[_editor.SelectedIndex];
|
|
List<SubRegionVertex> list = new List<SubRegionVertex>(editableSubRegion.Vertices.Count);
|
|
foreach (Vector2 vertex in editableSubRegion.Vertices)
|
|
{
|
|
list.Add(new SubRegionVertex
|
|
{
|
|
X = MathF.Round(vertex.X, 1),
|
|
Z = MathF.Round(vertex.Y, 1)
|
|
});
|
|
}
|
|
return list;
|
|
}
|
|
|
|
IList<Vector2> IEditablePolygonSet.GetVertices(int polygonIndex)
|
|
{
|
|
return _subRegions[polygonIndex].Vertices;
|
|
}
|
|
|
|
uint IEditablePolygonSet.GetColor(int polygonIndex)
|
|
{
|
|
return SubRegionColors[polygonIndex % SubRegionColors.Length];
|
|
}
|
|
|
|
string IEditablePolygonSet.GetLabel(int polygonIndex)
|
|
{
|
|
return _subRegions[polygonIndex].Id;
|
|
}
|
|
|
|
void IEditablePolygonSet.AddPolygon(IList<Vector2> vertices)
|
|
{
|
|
_subRegions.Add(new EditableSubRegion
|
|
{
|
|
Id = $"region_{_subRegions.Count + 1}",
|
|
Vertices = new List<Vector2>(vertices)
|
|
});
|
|
}
|
|
}
|