DI: Split QueueHandler into multiple classes
This commit is contained in:
parent
29aefee135
commit
7d04cd7575
@ -69,7 +69,6 @@ namespace Pal.Client.DependencyInjection
|
||||
services.AddSingleton<FrameworkService>();
|
||||
services.AddSingleton<ChatService>();
|
||||
services.AddSingleton<FloorService>();
|
||||
services.AddSingleton<QueueHandler>();
|
||||
|
||||
// windows & related services
|
||||
services.AddSingleton<AgreementWindow>();
|
||||
@ -82,6 +81,12 @@ namespace Pal.Client.DependencyInjection
|
||||
services.AddSingleton<SplatoonRenderer>();
|
||||
services.AddSingleton<RenderAdapter>();
|
||||
|
||||
// queue handling
|
||||
services.AddTransient<IQueueOnFrameworkThread.Handler<QueuedImport>, QueuedImport.Handler>();
|
||||
services.AddTransient<IQueueOnFrameworkThread.Handler<QueuedUndoImport>, QueuedUndoImport.Handler>();
|
||||
services.AddTransient<IQueueOnFrameworkThread.Handler<QueuedConfigUpdate>, QueuedConfigUpdate.Handler>();
|
||||
services.AddTransient<IQueueOnFrameworkThread.Handler<QueuedSyncResponse>, QueuedSyncResponse.Handler>();
|
||||
|
||||
// set up the current UI language before creating anything
|
||||
Localization.Culture = new CultureInfo(pluginInterface.UiLanguage);
|
||||
|
||||
|
@ -9,7 +9,9 @@ using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Logging;
|
||||
using ImGuiNET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Net;
|
||||
@ -20,6 +22,7 @@ namespace Pal.Client.DependencyInjection
|
||||
{
|
||||
internal sealed class FrameworkService : IDisposable
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly Framework _framework;
|
||||
private readonly ConfigurationManager _configurationManager;
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
@ -28,7 +31,6 @@ namespace Pal.Client.DependencyInjection
|
||||
private readonly FloorService _floorService;
|
||||
private readonly DebugState _debugState;
|
||||
private readonly RenderAdapter _renderAdapter;
|
||||
private readonly QueueHandler _queueHandler;
|
||||
private readonly ObjectTable _objectTable;
|
||||
private readonly RemoteApi _remoteApi;
|
||||
|
||||
@ -36,7 +38,9 @@ namespace Pal.Client.DependencyInjection
|
||||
internal Queue<IQueueOnFrameworkThread> LateEventQueue { get; } = new();
|
||||
internal ConcurrentQueue<nint> NextUpdateObjects { get; } = new();
|
||||
|
||||
public FrameworkService(Framework framework,
|
||||
public FrameworkService(
|
||||
IServiceProvider serviceProvider,
|
||||
Framework framework,
|
||||
ConfigurationManager configurationManager,
|
||||
IPalacePalConfiguration configuration,
|
||||
ClientState clientState,
|
||||
@ -44,10 +48,10 @@ namespace Pal.Client.DependencyInjection
|
||||
FloorService floorService,
|
||||
DebugState debugState,
|
||||
RenderAdapter renderAdapter,
|
||||
QueueHandler queueHandler,
|
||||
ObjectTable objectTable,
|
||||
RemoteApi remoteApi)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_framework = framework;
|
||||
_configurationManager = configurationManager;
|
||||
_configuration = configuration;
|
||||
@ -56,7 +60,6 @@ namespace Pal.Client.DependencyInjection
|
||||
_floorService = floorService;
|
||||
_debugState = debugState;
|
||||
_renderAdapter = renderAdapter;
|
||||
_queueHandler = queueHandler;
|
||||
_objectTable = objectTable;
|
||||
_remoteApi = remoteApi;
|
||||
|
||||
@ -84,7 +87,7 @@ namespace Pal.Client.DependencyInjection
|
||||
bool saveMarkers = false;
|
||||
|
||||
while (EarlyEventQueue.TryDequeue(out IQueueOnFrameworkThread? queued))
|
||||
_queueHandler.Handle(queued, ref recreateLayout, ref saveMarkers);
|
||||
HandleQueued(queued, ref recreateLayout, ref saveMarkers);
|
||||
|
||||
if (_territoryState.LastTerritory != _clientState.TerritoryType)
|
||||
{
|
||||
@ -111,12 +114,13 @@ namespace Pal.Client.DependencyInjection
|
||||
}
|
||||
|
||||
while (LateEventQueue.TryDequeue(out IQueueOnFrameworkThread? queued))
|
||||
_queueHandler.Handle(queued, ref recreateLayout, ref saveMarkers);
|
||||
HandleQueued(queued, ref recreateLayout, ref saveMarkers);
|
||||
|
||||
var currentFloor = _floorService.GetFloorMarkers(_territoryState.LastTerritory);
|
||||
|
||||
IList<Marker> visibleMarkers = GetRelevantGameObjects();
|
||||
HandlePersistentMarkers(currentFloor, visibleMarkers.Where(x => x.IsPermanent()).ToList(), saveMarkers, recreateLayout);
|
||||
HandlePersistentMarkers(currentFloor, visibleMarkers.Where(x => x.IsPermanent()).ToList(), saveMarkers,
|
||||
recreateLayout);
|
||||
HandleEphemeralMarkers(visibleMarkers.Where(x => !x.IsPermanent()).ToList(), recreateLayout);
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -126,7 +130,9 @@ namespace Pal.Client.DependencyInjection
|
||||
}
|
||||
|
||||
#region Render Markers
|
||||
private void HandlePersistentMarkers(LocalState currentFloor, IList<Marker> visibleMarkers, bool saveMarkers, bool recreateLayout)
|
||||
|
||||
private void HandlePersistentMarkers(LocalState currentFloor, IList<Marker> visibleMarkers, bool saveMarkers,
|
||||
bool recreateLayout)
|
||||
{
|
||||
var currentFloorMarkers = currentFloor.Markers;
|
||||
|
||||
@ -145,7 +151,8 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
// This requires you to have seen a trap/hoard marker once per floor to synchronize this for older local states,
|
||||
// markers discovered afterwards are automatically marked seen.
|
||||
if (partialAccountId != null && knownMarker is { NetworkId: { }, RemoteSeenRequested: false } && !knownMarker.RemoteSeenOn.Contains(partialAccountId))
|
||||
if (partialAccountId != null && knownMarker is { NetworkId: { }, RemoteSeenRequested: false } &&
|
||||
!knownMarker.RemoteSeenOn.Contains(partialAccountId))
|
||||
updateSeenMarkers = true;
|
||||
|
||||
continue;
|
||||
@ -156,9 +163,10 @@ namespace Pal.Client.DependencyInjection
|
||||
saveMarkers = true;
|
||||
}
|
||||
|
||||
if (!recreateLayout && currentFloorMarkers.Count > 0 && (_configuration.DeepDungeons.Traps.OnlyVisibleAfterPomander || _configuration.DeepDungeons.HoardCoffers.OnlyVisibleAfterPomander))
|
||||
if (!recreateLayout && currentFloorMarkers.Count > 0 &&
|
||||
(_configuration.DeepDungeons.Traps.OnlyVisibleAfterPomander ||
|
||||
_configuration.DeepDungeons.HoardCoffers.OnlyVisibleAfterPomander))
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var marker in currentFloorMarkers)
|
||||
@ -183,7 +191,9 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
if (updateSeenMarkers && partialAccountId != null)
|
||||
{
|
||||
var markersToUpdate = currentFloorMarkers.Where(x => x is { Seen: true, NetworkId: { }, RemoteSeenRequested: false } && !x.RemoteSeenOn.Contains(partialAccountId)).ToList();
|
||||
var markersToUpdate = currentFloorMarkers.Where(x =>
|
||||
x is { Seen: true, NetworkId: { }, RemoteSeenRequested: false } &&
|
||||
!x.RemoteSeenOn.Contains(partialAccountId)).ToList();
|
||||
foreach (var marker in markersToUpdate)
|
||||
marker.RemoteSeenRequested = true;
|
||||
Task.Run(async () => await SyncSeenMarkersForTerritory(_territoryState.LastTerritory, markersToUpdate));
|
||||
@ -195,12 +205,14 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
if (_territoryState.TerritorySyncState == SyncState.Complete)
|
||||
{
|
||||
var markersToUpload = currentFloorMarkers.Where(x => x.IsPermanent() && x.NetworkId == null && !x.UploadRequested).ToList();
|
||||
var markersToUpload = currentFloorMarkers
|
||||
.Where(x => x.IsPermanent() && x.NetworkId == null && !x.UploadRequested).ToList();
|
||||
if (markersToUpload.Count > 0)
|
||||
{
|
||||
foreach (var marker in markersToUpload)
|
||||
marker.UploadRequested = true;
|
||||
Task.Run(async () => await UploadMarkersForTerritory(_territoryState.LastTerritory, markersToUpload));
|
||||
Task.Run(async () =>
|
||||
await UploadMarkersForTerritory(_territoryState.LastTerritory, markersToUpload));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -212,15 +224,18 @@ namespace Pal.Client.DependencyInjection
|
||||
List<IRenderElement> elements = new();
|
||||
foreach (var marker in currentFloorMarkers)
|
||||
{
|
||||
if (marker.Seen || _configuration.Mode == EMode.Online || marker is { WasImported: true, Imports.Count: > 0 })
|
||||
if (marker.Seen || _configuration.Mode == EMode.Online ||
|
||||
marker is { WasImported: true, Imports.Count: > 0 })
|
||||
{
|
||||
if (marker.Type == Marker.EType.Trap)
|
||||
{
|
||||
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers), _configuration.DeepDungeons.Traps);
|
||||
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers),
|
||||
_configuration.DeepDungeons.Traps);
|
||||
}
|
||||
else if (marker.Type == Marker.EType.Hoard)
|
||||
{
|
||||
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers), _configuration.DeepDungeons.HoardCoffers);
|
||||
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers),
|
||||
_configuration.DeepDungeons.HoardCoffers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -234,8 +249,10 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
private void HandleEphemeralMarkers(IList<Marker> visibleMarkers, bool recreateLayout)
|
||||
{
|
||||
recreateLayout |= _floorService.EphemeralMarkers.Any(existingMarker => visibleMarkers.All(x => x != existingMarker));
|
||||
recreateLayout |= visibleMarkers.Any(visibleMarker => _floorService.EphemeralMarkers.All(x => x != visibleMarker));
|
||||
recreateLayout |=
|
||||
_floorService.EphemeralMarkers.Any(existingMarker => visibleMarkers.All(x => x != existingMarker));
|
||||
recreateLayout |=
|
||||
visibleMarkers.Any(visibleMarker => _floorService.EphemeralMarkers.All(x => x != visibleMarker));
|
||||
|
||||
if (recreateLayout)
|
||||
{
|
||||
@ -249,7 +266,8 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
if (marker.Type == Marker.EType.SilverCoffer && _configuration.DeepDungeons.SilverCoffers.Show)
|
||||
{
|
||||
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers), _configuration.DeepDungeons.SilverCoffers);
|
||||
CreateRenderElement(marker, elements, DetermineColor(marker, visibleMarkers),
|
||||
_configuration.DeepDungeons.SilverCoffers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,9 +282,13 @@ namespace Pal.Client.DependencyInjection
|
||||
{
|
||||
switch (marker.Type)
|
||||
{
|
||||
case Marker.EType.Trap when _territoryState.PomanderOfSight == PomanderState.Inactive || !_configuration.DeepDungeons.Traps.OnlyVisibleAfterPomander || visibleMarkers.Any(x => x == marker):
|
||||
case Marker.EType.Trap when _territoryState.PomanderOfSight == PomanderState.Inactive ||
|
||||
!_configuration.DeepDungeons.Traps.OnlyVisibleAfterPomander ||
|
||||
visibleMarkers.Any(x => x == marker):
|
||||
return _configuration.DeepDungeons.Traps.Color;
|
||||
case Marker.EType.Hoard when _territoryState.PomanderOfIntuition == PomanderState.Inactive || !_configuration.DeepDungeons.HoardCoffers.OnlyVisibleAfterPomander || visibleMarkers.Any(x => x == marker):
|
||||
case Marker.EType.Hoard when _territoryState.PomanderOfIntuition == PomanderState.Inactive ||
|
||||
!_configuration.DeepDungeons.HoardCoffers.OnlyVisibleAfterPomander ||
|
||||
visibleMarkers.Any(x => x == marker):
|
||||
return _configuration.DeepDungeons.HoardCoffers.Color;
|
||||
case Marker.EType.SilverCoffer:
|
||||
return _configuration.DeepDungeons.SilverCoffers.Color;
|
||||
@ -278,7 +300,8 @@ namespace Pal.Client.DependencyInjection
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateRenderElement(Marker marker, List<IRenderElement> elements, uint color, MarkerConfiguration config)
|
||||
private void CreateRenderElement(Marker marker, List<IRenderElement> elements, uint color,
|
||||
MarkerConfiguration config)
|
||||
{
|
||||
if (!config.Show)
|
||||
return;
|
||||
@ -287,9 +310,11 @@ namespace Pal.Client.DependencyInjection
|
||||
marker.RenderElement = element;
|
||||
elements.Add(element);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Up-/Download
|
||||
|
||||
private async Task DownloadMarkersForTerritory(ushort territoryId)
|
||||
{
|
||||
try
|
||||
@ -346,6 +371,7 @@ namespace Pal.Client.DependencyInjection
|
||||
_debugState.SetFromException(e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private IList<Marker> GetRelevantGameObjects()
|
||||
@ -388,5 +414,13 @@ namespace Pal.Client.DependencyInjection
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void HandleQueued(IQueueOnFrameworkThread queued, ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
Type handlerType = typeof(IQueueOnFrameworkThread.Handler<>).MakeGenericType(queued.GetType());
|
||||
var handler = (IQueueOnFrameworkThread.IHandler)_serviceProvider.GetRequiredService(handlerType);
|
||||
|
||||
handler.RunIfCompatible(queued, ref recreateLayout, ref saveMarkers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,31 @@
|
||||
namespace Pal.Client.Scheduled
|
||||
using Dalamud.Logging;
|
||||
|
||||
namespace Pal.Client.Scheduled
|
||||
{
|
||||
internal interface IQueueOnFrameworkThread
|
||||
{
|
||||
internal interface IHandler
|
||||
{
|
||||
void RunIfCompatible(IQueueOnFrameworkThread queued, ref bool recreateLayout, ref bool saveMarkers);
|
||||
}
|
||||
|
||||
internal abstract class Handler<T> : IHandler
|
||||
where T : IQueueOnFrameworkThread
|
||||
{
|
||||
protected abstract void Run(T queued, ref bool recreateLayout, ref bool saveMarkers);
|
||||
|
||||
public void RunIfCompatible(IQueueOnFrameworkThread queued, ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
if (queued is T t)
|
||||
{
|
||||
PluginLog.Information($"Handling {queued.GetType()} with handler {GetType()}");
|
||||
Run(t, ref recreateLayout, ref saveMarkers);
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginLog.Error($"Could not use queue handler {GetType()} with type {queued.GetType()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,203 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Logging;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Net;
|
||||
using Pal.Client.Properties;
|
||||
using Pal.Common;
|
||||
|
||||
namespace Pal.Client.Scheduled
|
||||
{
|
||||
// TODO The idea was to split this from the queue objects, should be in individual classes tho
|
||||
internal sealed class QueueHandler
|
||||
{
|
||||
private readonly ConfigurationManager _configurationManager;
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly FloorService _floorService;
|
||||
private readonly TerritoryState _territoryState;
|
||||
private readonly DebugState _debugState;
|
||||
private readonly ChatGui _chatGui;
|
||||
|
||||
public QueueHandler(
|
||||
ConfigurationManager configurationManager,
|
||||
IPalacePalConfiguration configuration,
|
||||
FloorService floorService,
|
||||
TerritoryState territoryState,
|
||||
DebugState debugState,
|
||||
ChatGui chatGui)
|
||||
{
|
||||
_configurationManager = configurationManager;
|
||||
_configuration = configuration;
|
||||
_floorService = floorService;
|
||||
_territoryState = territoryState;
|
||||
_debugState = debugState;
|
||||
_chatGui = chatGui;
|
||||
}
|
||||
|
||||
public void Handle(IQueueOnFrameworkThread queued, ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
if (queued is QueuedConfigUpdate)
|
||||
{
|
||||
ConfigUpdate(ref recreateLayout, ref saveMarkers);
|
||||
}
|
||||
else if (queued is QueuedSyncResponse queuedSyncResponse)
|
||||
{
|
||||
SyncResponse(queuedSyncResponse);
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
}
|
||||
else if (queued is QueuedImport queuedImport)
|
||||
{
|
||||
Import(queuedImport);
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
}
|
||||
else if (queued is QueuedUndoImport queuedUndoImport)
|
||||
{
|
||||
UndoImport(queuedUndoImport);
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private void ConfigUpdate(ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
if (_configuration.Mode == EMode.Offline)
|
||||
{
|
||||
LocalState.UpdateAll();
|
||||
_floorService.FloorMarkers.Clear();
|
||||
_floorService.EphemeralMarkers.Clear();
|
||||
_territoryState.LastTerritory = 0;
|
||||
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SyncResponse(QueuedSyncResponse queued)
|
||||
{
|
||||
try
|
||||
{
|
||||
var remoteMarkers = queued.Markers;
|
||||
var currentFloor = _floorService.GetFloorMarkers(queued.TerritoryType);
|
||||
if (_configuration.Mode == EMode.Online && queued.Success && remoteMarkers.Count > 0)
|
||||
{
|
||||
switch (queued.Type)
|
||||
{
|
||||
case SyncType.Download:
|
||||
case SyncType.Upload:
|
||||
foreach (var remoteMarker in remoteMarkers)
|
||||
{
|
||||
// Both uploads and downloads return the network id to be set, but only the downloaded marker is new as in to-be-saved.
|
||||
Marker? localMarker = currentFloor.Markers.SingleOrDefault(x => x == remoteMarker);
|
||||
if (localMarker != null)
|
||||
{
|
||||
localMarker.NetworkId = remoteMarker.NetworkId;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (queued.Type == SyncType.Download)
|
||||
currentFloor.Markers.Add(remoteMarker);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyncType.MarkSeen:
|
||||
var partialAccountId =
|
||||
_configuration.FindAccount(RemoteApi.RemoteUrl)?.AccountId.ToPartialId();
|
||||
if (partialAccountId == null)
|
||||
break;
|
||||
foreach (var remoteMarker in remoteMarkers)
|
||||
{
|
||||
Marker? localMarker = currentFloor.Markers.SingleOrDefault(x => x == remoteMarker);
|
||||
if (localMarker != null)
|
||||
localMarker.RemoteSeenOn.Add(partialAccountId);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// don't modify state for outdated floors
|
||||
if (_territoryState.LastTerritory != queued.TerritoryType)
|
||||
return;
|
||||
|
||||
if (queued.Type == SyncType.Download)
|
||||
{
|
||||
if (queued.Success)
|
||||
_territoryState.TerritorySyncState = SyncState.Complete;
|
||||
else
|
||||
_territoryState.TerritorySyncState = SyncState.Failed;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_debugState.SetFromException(e);
|
||||
if (queued.Type == SyncType.Download)
|
||||
_territoryState.TerritorySyncState = SyncState.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
private void Import(QueuedImport queued)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!queued.Validate(_chatGui))
|
||||
return;
|
||||
|
||||
var oldExportIds = string.IsNullOrEmpty(queued.Export.ServerUrl)
|
||||
? _configuration.ImportHistory.Where(x => x.RemoteUrl == queued.Export.ServerUrl).Select(x => x.Id)
|
||||
.Where(x => x != Guid.Empty).ToList()
|
||||
: new List<Guid>();
|
||||
|
||||
foreach (var remoteFloor in queued.Export.Floors)
|
||||
{
|
||||
ushort territoryType = (ushort)remoteFloor.TerritoryType;
|
||||
var localState = _floorService.GetFloorMarkers(territoryType);
|
||||
|
||||
localState.UndoImport(oldExportIds);
|
||||
queued.ImportFloor(remoteFloor, localState);
|
||||
|
||||
localState.Save();
|
||||
}
|
||||
|
||||
_configuration.ImportHistory.RemoveAll(hist =>
|
||||
oldExportIds.Contains(hist.Id) || hist.Id == queued.ExportId);
|
||||
_configuration.ImportHistory.Add(new ConfigurationV1.ImportHistoryEntry
|
||||
{
|
||||
Id = queued.ExportId,
|
||||
RemoteUrl = queued.Export.ServerUrl,
|
||||
ExportedAt = queued.Export.CreatedAt.ToDateTime(),
|
||||
ImportedAt = DateTime.UtcNow,
|
||||
});
|
||||
_configurationManager.Save(_configuration);
|
||||
|
||||
_chatGui.Print(string.Format(Localization.ImportCompleteStatistics, queued.ImportedTraps,
|
||||
queued.ImportedHoardCoffers));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PluginLog.Error(e, "Import failed");
|
||||
_chatGui.PalError(string.Format(Localization.Error_ImportFailed, e));
|
||||
}
|
||||
}
|
||||
|
||||
private void UndoImport(QueuedUndoImport queued)
|
||||
{
|
||||
foreach (ETerritoryType territoryType in typeof(ETerritoryType).GetEnumValues())
|
||||
{
|
||||
var localState = _floorService.GetFloorMarkers((ushort)territoryType);
|
||||
localState.UndoImport(new List<Guid> { queued.ExportId });
|
||||
localState.Save();
|
||||
}
|
||||
|
||||
_configuration.ImportHistory.RemoveAll(hist => hist.Id == queued.ExportId);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,37 @@
|
||||
namespace Pal.Client.Scheduled
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
|
||||
namespace Pal.Client.Scheduled
|
||||
{
|
||||
internal sealed class QueuedConfigUpdate : IQueueOnFrameworkThread
|
||||
{
|
||||
internal sealed class Handler : IQueueOnFrameworkThread.Handler<QueuedConfigUpdate>
|
||||
{
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly FloorService _floorService;
|
||||
private readonly TerritoryState _territoryState;
|
||||
|
||||
public Handler(IPalacePalConfiguration configuration, FloorService floorService,
|
||||
TerritoryState territoryState)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_floorService = floorService;
|
||||
_territoryState = territoryState;
|
||||
}
|
||||
|
||||
protected override void Run(QueuedConfigUpdate queued, ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
if (_configuration.Mode == EMode.Offline)
|
||||
{
|
||||
LocalState.UpdateAll();
|
||||
_floorService.FloorMarkers.Clear();
|
||||
_floorService.EphemeralMarkers.Clear();
|
||||
_territoryState.LastTerritory = 0;
|
||||
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,25 @@
|
||||
using Account;
|
||||
using Pal.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Logging;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Properties;
|
||||
|
||||
namespace Pal.Client.Scheduled
|
||||
{
|
||||
internal sealed class QueuedImport : IQueueOnFrameworkThread
|
||||
{
|
||||
public ExportRoot Export { get; }
|
||||
public Guid ExportId { get; private set; }
|
||||
public int ImportedTraps { get; private set; }
|
||||
public int ImportedHoardCoffers { get; private set; }
|
||||
private ExportRoot Export { get; }
|
||||
private Guid ExportId { get; set; }
|
||||
private int ImportedTraps { get; set; }
|
||||
private int ImportedHoardCoffers { get; set; }
|
||||
|
||||
public QueuedImport(string sourcePath)
|
||||
{
|
||||
@ -22,50 +27,116 @@ namespace Pal.Client.Scheduled
|
||||
Export = ExportRoot.Parser.ParseFrom(input);
|
||||
}
|
||||
|
||||
public bool Validate(ChatGui chatGui)
|
||||
internal sealed class Handler : IQueueOnFrameworkThread.Handler<QueuedImport>
|
||||
{
|
||||
if (Export.ExportVersion != ExportConfig.ExportVersion)
|
||||
private readonly ChatGui _chatGui;
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly ConfigurationManager _configurationManager;
|
||||
private readonly FloorService _floorService;
|
||||
|
||||
public Handler(ChatGui chatGui, IPalacePalConfiguration configuration,
|
||||
ConfigurationManager configurationManager, FloorService floorService)
|
||||
{
|
||||
chatGui.PrintError(Localization.Error_ImportFailed_IncompatibleVersion);
|
||||
return false;
|
||||
_chatGui = chatGui;
|
||||
_configuration = configuration;
|
||||
_configurationManager = configurationManager;
|
||||
_floorService = floorService;
|
||||
}
|
||||
|
||||
if (!Guid.TryParse(Export.ExportId, out Guid exportId) || ExportId == Guid.Empty)
|
||||
protected override void Run(QueuedImport import, ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
chatGui.PrintError(Localization.Error_ImportFailed_InvalidFile);
|
||||
return false;
|
||||
}
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
|
||||
ExportId = exportId;
|
||||
|
||||
if (string.IsNullOrEmpty(Export.ServerUrl))
|
||||
{
|
||||
// If we allow for backups as import/export, this should be removed
|
||||
chatGui.PrintError(Localization.Error_ImportFailed_InvalidFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ImportFloor(ExportFloor remoteFloor, LocalState localState)
|
||||
{
|
||||
var remoteMarkers = remoteFloor.Objects.Select(m => new Marker((Marker.EType)m.Type, new Vector3(m.X, m.Y, m.Z)) { WasImported = true });
|
||||
foreach (var remoteMarker in remoteMarkers)
|
||||
{
|
||||
Marker? localMarker = localState.Markers.SingleOrDefault(x => x == remoteMarker);
|
||||
if (localMarker == null)
|
||||
try
|
||||
{
|
||||
localState.Markers.Add(remoteMarker);
|
||||
localMarker = remoteMarker;
|
||||
if (!Validate(import))
|
||||
return;
|
||||
|
||||
if (localMarker.Type == Marker.EType.Trap)
|
||||
ImportedTraps++;
|
||||
else if (localMarker.Type == Marker.EType.Hoard)
|
||||
ImportedHoardCoffers++;
|
||||
var oldExportIds = string.IsNullOrEmpty(import.Export.ServerUrl)
|
||||
? _configuration.ImportHistory.Where(x => x.RemoteUrl == import.Export.ServerUrl)
|
||||
.Select(x => x.Id)
|
||||
.Where(x => x != Guid.Empty).ToList()
|
||||
: new List<Guid>();
|
||||
|
||||
foreach (var remoteFloor in import.Export.Floors)
|
||||
{
|
||||
ushort territoryType = (ushort)remoteFloor.TerritoryType;
|
||||
var localState = _floorService.GetFloorMarkers(territoryType);
|
||||
|
||||
localState.UndoImport(oldExportIds);
|
||||
ImportFloor(import, remoteFloor, localState);
|
||||
|
||||
localState.Save();
|
||||
}
|
||||
|
||||
_configuration.ImportHistory.RemoveAll(hist =>
|
||||
oldExportIds.Contains(hist.Id) || hist.Id == import.ExportId);
|
||||
_configuration.ImportHistory.Add(new ConfigurationV1.ImportHistoryEntry
|
||||
{
|
||||
Id = import.ExportId,
|
||||
RemoteUrl = import.Export.ServerUrl,
|
||||
ExportedAt = import.Export.CreatedAt.ToDateTime(),
|
||||
ImportedAt = DateTime.UtcNow,
|
||||
});
|
||||
_configurationManager.Save(_configuration);
|
||||
|
||||
_chatGui.Print(string.Format(Localization.ImportCompleteStatistics, import.ImportedTraps,
|
||||
import.ImportedHoardCoffers));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PluginLog.Error(e, "Import failed");
|
||||
_chatGui.PalError(string.Format(Localization.Error_ImportFailed, e));
|
||||
}
|
||||
}
|
||||
|
||||
private bool Validate(QueuedImport import)
|
||||
{
|
||||
if (import.Export.ExportVersion != ExportConfig.ExportVersion)
|
||||
{
|
||||
_chatGui.PrintError(Localization.Error_ImportFailed_IncompatibleVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
remoteMarker.Imports.Add(ExportId);
|
||||
if (!Guid.TryParse(import.Export.ExportId, out Guid exportId) || import.ExportId == Guid.Empty)
|
||||
{
|
||||
_chatGui.PrintError(Localization.Error_ImportFailed_InvalidFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
import.ExportId = exportId;
|
||||
|
||||
if (string.IsNullOrEmpty(import.Export.ServerUrl))
|
||||
{
|
||||
// If we allow for backups as import/export, this should be removed
|
||||
_chatGui.PrintError(Localization.Error_ImportFailed_InvalidFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ImportFloor(QueuedImport import, ExportFloor remoteFloor, LocalState localState)
|
||||
{
|
||||
var remoteMarkers = remoteFloor.Objects.Select(m =>
|
||||
new Marker((Marker.EType)m.Type, new Vector3(m.X, m.Y, m.Z)) { WasImported = true });
|
||||
foreach (var remoteMarker in remoteMarkers)
|
||||
{
|
||||
Marker? localMarker = localState.Markers.SingleOrDefault(x => x == remoteMarker);
|
||||
if (localMarker == null)
|
||||
{
|
||||
localState.Markers.Add(remoteMarker);
|
||||
localMarker = remoteMarker;
|
||||
|
||||
if (localMarker.Type == Marker.EType.Trap)
|
||||
import.ImportedTraps++;
|
||||
else if (localMarker.Type == Marker.EType.Hoard)
|
||||
import.ImportedHoardCoffers++;
|
||||
}
|
||||
|
||||
remoteMarker.Imports.Add(import.ExportId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Net;
|
||||
|
||||
namespace Pal.Client.Scheduled
|
||||
{
|
||||
@ -8,6 +14,89 @@ namespace Pal.Client.Scheduled
|
||||
public required ushort TerritoryType { get; init; }
|
||||
public required bool Success { get; init; }
|
||||
public required List<Marker> Markers { get; init; }
|
||||
|
||||
internal sealed class Handler : IQueueOnFrameworkThread.Handler<QueuedSyncResponse>
|
||||
{
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly FloorService _floorService;
|
||||
private readonly TerritoryState _territoryState;
|
||||
private readonly DebugState _debugState;
|
||||
|
||||
public Handler(IPalacePalConfiguration configuration, FloorService floorService, TerritoryState territoryState, DebugState debugState)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_floorService = floorService;
|
||||
_territoryState = territoryState;
|
||||
_debugState = debugState;
|
||||
}
|
||||
|
||||
protected override void Run(QueuedSyncResponse queued, ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
|
||||
try
|
||||
{
|
||||
var remoteMarkers = queued.Markers;
|
||||
var currentFloor = _floorService.GetFloorMarkers(queued.TerritoryType);
|
||||
if (_configuration.Mode == EMode.Online && queued.Success && remoteMarkers.Count > 0)
|
||||
{
|
||||
switch (queued.Type)
|
||||
{
|
||||
case SyncType.Download:
|
||||
case SyncType.Upload:
|
||||
foreach (var remoteMarker in remoteMarkers)
|
||||
{
|
||||
// Both uploads and downloads return the network id to be set, but only the downloaded marker is new as in to-be-saved.
|
||||
Marker? localMarker = currentFloor.Markers.SingleOrDefault(x => x == remoteMarker);
|
||||
if (localMarker != null)
|
||||
{
|
||||
localMarker.NetworkId = remoteMarker.NetworkId;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (queued.Type == SyncType.Download)
|
||||
currentFloor.Markers.Add(remoteMarker);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyncType.MarkSeen:
|
||||
var partialAccountId =
|
||||
_configuration.FindAccount(RemoteApi.RemoteUrl)?.AccountId.ToPartialId();
|
||||
if (partialAccountId == null)
|
||||
break;
|
||||
foreach (var remoteMarker in remoteMarkers)
|
||||
{
|
||||
Marker? localMarker = currentFloor.Markers.SingleOrDefault(x => x == remoteMarker);
|
||||
if (localMarker != null)
|
||||
localMarker.RemoteSeenOn.Add(partialAccountId);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// don't modify state for outdated floors
|
||||
if (_territoryState.LastTerritory != queued.TerritoryType)
|
||||
return;
|
||||
|
||||
if (queued.Type == SyncType.Download)
|
||||
{
|
||||
if (queued.Success)
|
||||
_territoryState.TerritorySyncState = SyncState.Complete;
|
||||
else
|
||||
_territoryState.TerritorySyncState = SyncState.Failed;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_debugState.SetFromException(e);
|
||||
if (queued.Type == SyncType.Download)
|
||||
_territoryState.TerritorySyncState = SyncState.Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum SyncState
|
||||
|
@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
using Pal.Common;
|
||||
|
||||
namespace Pal.Client.Scheduled
|
||||
{
|
||||
@ -9,6 +13,33 @@ namespace Pal.Client.Scheduled
|
||||
ExportId = exportId;
|
||||
}
|
||||
|
||||
public Guid ExportId { get; }
|
||||
private Guid ExportId { get; }
|
||||
|
||||
internal sealed class Handler : IQueueOnFrameworkThread.Handler<QueuedUndoImport>
|
||||
{
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly FloorService _floorService;
|
||||
|
||||
public Handler(IPalacePalConfiguration configuration, FloorService floorService)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_floorService = floorService;
|
||||
}
|
||||
|
||||
protected override void Run(QueuedUndoImport queued, ref bool recreateLayout, ref bool saveMarkers)
|
||||
{
|
||||
recreateLayout = true;
|
||||
saveMarkers = true;
|
||||
|
||||
foreach (ETerritoryType territoryType in typeof(ETerritoryType).GetEnumValues())
|
||||
{
|
||||
var localState = _floorService.GetFloorMarkers((ushort)territoryType);
|
||||
localState.UndoImport(new List<Guid> { queued.ExportId });
|
||||
localState.Save();
|
||||
}
|
||||
|
||||
_configuration.ImportHistory.RemoveAll(hist => hist.Id == queued.ExportId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user