132 lines
4.6 KiB
C#
132 lines
4.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Numerics;
|
|
using System.Text.Json;
|
|
using Dalamud.Plugin.Services;
|
|
using Lumina.Excel;
|
|
using Lumina.Excel.Sheets;
|
|
using Microsoft.Extensions.Logging;
|
|
using SmartNav.Model.Navigation;
|
|
|
|
namespace SmartNav.Data;
|
|
|
|
public sealed class TeleportTicketService
|
|
{
|
|
public sealed record ScannedTicket(uint ItemId, string Name, uint ItemActionRowId, ushort[] ItemActionData);
|
|
|
|
public sealed record TeleportTicket(uint ItemId, string Name, ushort TerritoryId, Vector3 Position, byte RequiredGrandCompany = 0, uint RequiredQuestId = 0u);
|
|
|
|
private static readonly uint[] KnownTicketItemIds = new uint[5] { 21069u, 21070u, 21071u, 28064u, 30362u };
|
|
|
|
public IReadOnlyList<ScannedTicket> ScannedTickets { get; }
|
|
|
|
public IReadOnlyList<TeleportTicket> Tickets { get; }
|
|
|
|
internal TeleportTicketService(List<TeleportTicket> tickets)
|
|
{
|
|
ScannedTickets = Array.Empty<ScannedTicket>();
|
|
Tickets = tickets;
|
|
}
|
|
|
|
public TeleportTicketService(IDataManager dataManager, SmartNavDataOptions dataOptions, ILogger<TeleportTicketService> logger)
|
|
{
|
|
ScannedTickets = ScanTicketItems(dataManager, logger);
|
|
Dictionary<uint, (ushort, Vector3)> dictionary = new Dictionary<uint, (ushort, Vector3)>();
|
|
foreach (TeleportTicketEntry value2 in AssemblyTeleportTicketLoader.GetTickets(dataOptions.DevSourceDirectory?.FullName).Values)
|
|
{
|
|
ApplyEntry(dictionary, value2);
|
|
}
|
|
if (dataOptions.UserOverrideDirectory != null)
|
|
{
|
|
LoadDestinationsFrom(Path.Combine(dataOptions.UserOverrideDirectory.FullName, "teleport-tickets.json"), dictionary, logger);
|
|
}
|
|
ExcelSheet<ItemActionTelepo> excelSheet = dataManager.GetExcelSheet<ItemActionTelepo>();
|
|
List<TeleportTicket> list = new List<TeleportTicket>();
|
|
foreach (ScannedTicket scannedTicket in ScannedTickets)
|
|
{
|
|
if (!dictionary.TryGetValue(scannedTicket.ItemId, out var value))
|
|
{
|
|
logger.LogDebug("Teleport ticket {ItemId} ({Name}) has no known destination - record it via the debug window to make it routable", scannedTicket.ItemId, scannedTicket.Name);
|
|
}
|
|
else
|
|
{
|
|
uint num = excelSheet.GetRowOrDefault(scannedTicket.ItemActionData[0])?.Requirement.RowId ?? 0;
|
|
list.Add(new TeleportTicket(scannedTicket.ItemId, scannedTicket.Name, value.Item1, value.Item2, (byte)((num >= 1 && num <= 3) ? ((byte)num) : 0), (num >= 65536) ? num : 0u));
|
|
}
|
|
}
|
|
Tickets = list;
|
|
logger.LogInformation("Teleport tickets: {Scanned} items found, {Resolved} with destinations", ScannedTickets.Count, list.Count);
|
|
}
|
|
|
|
private static List<ScannedTicket> ScanTicketItems(IDataManager dataManager, ILogger logger)
|
|
{
|
|
ExcelSheet<Item> excelSheet = dataManager.GetExcelSheet<Item>();
|
|
uint? num = null;
|
|
uint[] knownTicketItemIds = KnownTicketItemIds;
|
|
foreach (uint rowId in knownTicketItemIds)
|
|
{
|
|
ItemAction? itemAction = excelSheet.GetRowOrDefault(rowId)?.ItemAction.ValueNullable;
|
|
if (itemAction.HasValue)
|
|
{
|
|
num = itemAction.Value.Action.RowId;
|
|
break;
|
|
}
|
|
}
|
|
List<ScannedTicket> list = new List<ScannedTicket>();
|
|
if (!num.HasValue)
|
|
{
|
|
logger.LogWarning("Teleport tickets: could not discover the ItemAction type from known items");
|
|
return list;
|
|
}
|
|
foreach (Item item in excelSheet)
|
|
{
|
|
if (item.RowId == 0)
|
|
{
|
|
continue;
|
|
}
|
|
ItemAction? valueNullable = item.ItemAction.ValueNullable;
|
|
if (valueNullable.HasValue && valueNullable.Value.Action.RowId == num)
|
|
{
|
|
string text = item.Name.ExtractText();
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
list.Add(new ScannedTicket(item.RowId, text, valueNullable.Value.RowId, new ushort[3]
|
|
{
|
|
valueNullable.Value.Data[0],
|
|
valueNullable.Value.Data[1],
|
|
valueNullable.Value.Data[2]
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
list.Sort((ScannedTicket a, ScannedTicket b) => a.ItemId.CompareTo(b.ItemId));
|
|
return list;
|
|
}
|
|
|
|
private static void ApplyEntry(Dictionary<uint, (ushort TerritoryId, Vector3 Position)> destinations, TeleportTicketEntry entry)
|
|
{
|
|
if (entry.ItemId != 0 && entry.DestTerritoryId > 0)
|
|
{
|
|
destinations[entry.ItemId] = (entry.DestTerritoryId, entry.DestPosition);
|
|
}
|
|
}
|
|
|
|
private static void LoadDestinationsFrom(string path, Dictionary<uint, (ushort TerritoryId, Vector3 Position)> destinations, ILogger logger)
|
|
{
|
|
if (!File.Exists(path))
|
|
{
|
|
return;
|
|
}
|
|
TeleportTicketFile teleportTicketFile = JsonSerializer.Deserialize<TeleportTicketFile>(File.ReadAllText(path));
|
|
if (teleportTicketFile == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (TeleportTicketEntry value in teleportTicketFile.Tickets.Values)
|
|
{
|
|
ApplyEntry(destinations, value);
|
|
}
|
|
logger.LogDebug("Teleport tickets: loaded {Count} destinations from {Path}", teleportTicketFile.Tickets.Count, path);
|
|
}
|
|
}
|