#define RELEASE using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text.Json; using Dalamud.Plugin; using LLib.GameData; using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.GatheringPaths; using Questionable.Model; using Questionable.Model.Gathering; namespace Questionable.Controller; internal sealed class GatheringPointRegistry : IDisposable { private readonly IDalamudPluginInterface _pluginInterface; private readonly QuestRegistry _questRegistry; private readonly GatheringData _gatheringData; private readonly ILogger _logger; private readonly Dictionary _gatheringPoints = new Dictionary(); public GatheringPointRegistry(IDalamudPluginInterface pluginInterface, QuestRegistry questRegistry, GatheringData gatheringData, ILogger logger) { _pluginInterface = pluginInterface; _questRegistry = questRegistry; _gatheringData = gatheringData; _logger = logger; _questRegistry.Reloaded += OnReloaded; } private void OnReloaded(object? sender, EventArgs e) { Reload(); } public void Reload() { _gatheringPoints.Clear(); LoadGatheringPointsFromAssembly(); try { LoadFromDirectory(new DirectoryInfo(Path.Combine(_pluginInterface.ConfigDirectory.FullName, "GatheringPoints"))); } catch (Exception exception) { _logger.LogError(exception, "Failed to load gathering points from user directory (some may have been successfully loaded)"); } _logger.LogInformation("Loaded {Count} gathering points in total", _gatheringPoints.Count); } [Conditional("RELEASE")] private void LoadGatheringPointsFromAssembly() { _logger.LogInformation("Loading gathering points from assembly"); foreach (var (value, value2) in AssemblyGatheringLocationLoader.GetLocations()) { _gatheringPoints[new GatheringPointId(value)] = value2; } _logger.LogInformation("Loaded {Count} gathering points from assembly", _gatheringPoints.Count); } [Conditional("DEBUG")] private void LoadGatheringPointsFromProjectDirectory() { DirectoryInfo directoryInfo = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent; if (directoryInfo == null) { return; } DirectoryInfo directoryInfo2 = new DirectoryInfo(Path.Combine(directoryInfo.FullName, "GatheringPaths")); if (!directoryInfo2.Exists) { return; } try { foreach (string value in ExpansionData.ExpansionFolders.Values) { LoadFromDirectory(new DirectoryInfo(Path.Combine(directoryInfo2.FullName, value))); } } catch (Exception exception) { _gatheringPoints.Clear(); _logger.LogError(exception, "Failed to load gathering points from project directory"); } } private void LoadGatheringPointFromStream(string fileName, Stream stream) { GatheringPointId gatheringPointId = ExtractGatheringPointIdFromName(fileName); if (!(gatheringPointId == null)) { _gatheringPoints[gatheringPointId] = JsonSerializer.Deserialize(stream); } } private void LoadFromDirectory(DirectoryInfo directory) { if (!directory.Exists) { _logger.LogInformation("Not loading gathering points from {DirectoryName} (doesn't exist)", directory); return; } FileInfo[] files = directory.GetFiles("*.json"); foreach (FileInfo fileInfo in files) { try { using FileStream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read); LoadGatheringPointFromStream(fileInfo.Name, stream); } catch (Exception innerException) { throw new InvalidDataException("Unable to load file " + fileInfo.FullName, innerException); } } DirectoryInfo[] directories = directory.GetDirectories(); foreach (DirectoryInfo directory2 in directories) { LoadFromDirectory(directory2); } } private static GatheringPointId? ExtractGatheringPointIdFromName(string resourceName) { string text = resourceName.Substring(0, resourceName.Length - ".json".Length); text = text.Substring(text.LastIndexOf('.') + 1); if (!text.Contains('_', StringComparison.Ordinal)) { return null; } return GatheringPointId.FromString(text.Split('_', 2)[0]); } public bool TryGetGatheringPoint(GatheringPointId gatheringPointId, [NotNullWhen(true)] out GatheringRoot? gatheringRoot) { return _gatheringPoints.TryGetValue(gatheringPointId, out gatheringRoot); } public bool TryGetGatheringPointId(uint itemId, EClassJob classJobId, [NotNullWhen(true)] out GatheringPointId? gatheringPointId) { switch (classJobId) { case EClassJob.Miner: if (_gatheringData.TryGetMinerGatheringPointByItemId(itemId, out gatheringPointId)) { return true; } gatheringPointId = (from x in _gatheringPoints where x.Value.ExtraQuestItems.Contains(itemId) select x.Key).FirstOrDefault((GatheringPointId x) => _gatheringData.MinerGatheringPoints.Contains(x)); return gatheringPointId != null; case EClassJob.Botanist: if (_gatheringData.TryGetBotanistGatheringPointByItemId(itemId, out gatheringPointId)) { return true; } gatheringPointId = (from x in _gatheringPoints where x.Value.ExtraQuestItems.Contains(itemId) select x.Key).FirstOrDefault((GatheringPointId x) => _gatheringData.BotanistGatheringPoints.Contains(x)); return gatheringPointId != null; default: gatheringPointId = null; return false; } } public void Dispose() { _questRegistry.Reloaded -= OnReloaded; } }