Compare commits
4 Commits
main
...
513845b811
| Author | SHA1 | Date | |
|---|---|---|---|
|
513845b811
|
|||
|
84586cac3d
|
|||
|
b4108c7803
|
|||
|
d891dceb28
|
Submodule Glamourer.Api updated: 7e8505cd6f...59a7ab5fa9
@@ -1,4 +1,5 @@
|
|||||||
using MareSynchronos.Interop.Ipc;
|
using System;
|
||||||
|
using MareSynchronos.Interop.Ipc;
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
@@ -606,14 +607,35 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
_scanCancellationTokenSource?.Cancel();
|
try
|
||||||
|
{
|
||||||
|
_scanCancellationTokenSource.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
_scanCancellationTokenSource.Dispose();
|
||||||
PenumbraWatcher?.Dispose();
|
PenumbraWatcher?.Dispose();
|
||||||
MareWatcher?.Dispose();
|
MareWatcher?.Dispose();
|
||||||
SubstWatcher?.Dispose();
|
SubstWatcher?.Dispose();
|
||||||
_penumbraFswCts?.CancelDispose();
|
TryCancelAndDispose(_penumbraFswCts);
|
||||||
_mareFswCts?.CancelDispose();
|
TryCancelAndDispose(_mareFswCts);
|
||||||
_substFswCts?.CancelDispose();
|
TryCancelAndDispose(_substFswCts);
|
||||||
_periodicCalculationTokenSource?.CancelDispose();
|
TryCancelAndDispose(_periodicCalculationTokenSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TryCancelAndDispose(CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FullFileScan(CancellationToken ct)
|
private void FullFileScan(CancellationToken ct)
|
||||||
@@ -856,4 +878,4 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
StartPenumbraWatcher(penumbraDir);
|
StartPenumbraWatcher(penumbraDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public sealed class FileCompactor
|
|||||||
|
|
||||||
private readonly Dictionary<string, int> _clusterSizes;
|
private readonly Dictionary<string, int> _clusterSizes;
|
||||||
|
|
||||||
private readonly WOF_FILE_COMPRESSION_INFO_V1 _efInfo;
|
private readonly WofFileCompressionInfoV1 _efInfo;
|
||||||
private readonly ILogger<FileCompactor> _logger;
|
private readonly ILogger<FileCompactor> _logger;
|
||||||
|
|
||||||
private readonly MareConfigService _mareConfigService;
|
private readonly MareConfigService _mareConfigService;
|
||||||
@@ -24,7 +24,7 @@ public sealed class FileCompactor
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
_mareConfigService = mareConfigService;
|
_mareConfigService = mareConfigService;
|
||||||
_dalamudUtilService = dalamudUtilService;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_efInfo = new WOF_FILE_COMPRESSION_INFO_V1
|
_efInfo = new WofFileCompressionInfoV1
|
||||||
{
|
{
|
||||||
Algorithm = CompressionAlgorithm.XPRESS8K,
|
Algorithm = CompressionAlgorithm.XPRESS8K,
|
||||||
Flags = 0
|
Flags = 0
|
||||||
@@ -123,7 +123,7 @@ public sealed class FileCompactor
|
|||||||
out uint lpTotalNumberOfClusters);
|
out uint lpTotalNumberOfClusters);
|
||||||
|
|
||||||
[DllImport("WoFUtil.dll")]
|
[DllImport("WoFUtil.dll")]
|
||||||
private static extern int WofIsExternalFile([MarshalAs(UnmanagedType.LPWStr)] string Filepath, out int IsExternalFile, out uint Provider, out WOF_FILE_COMPRESSION_INFO_V1 Info, ref uint BufferLength);
|
private static extern int WofIsExternalFile([MarshalAs(UnmanagedType.LPWStr)] string Filepath, out int IsExternalFile, out uint Provider, out WofFileCompressionInfoV1 Info, ref uint BufferLength);
|
||||||
|
|
||||||
[DllImport("WofUtil.dll")]
|
[DllImport("WofUtil.dll")]
|
||||||
private static extern int WofSetFileDataLocation(IntPtr FileHandle, ulong Provider, IntPtr ExternalFileInfo, ulong Length);
|
private static extern int WofSetFileDataLocation(IntPtr FileHandle, ulong Provider, IntPtr ExternalFileInfo, ulong Length);
|
||||||
@@ -242,9 +242,9 @@ public sealed class FileCompactor
|
|||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
private struct WOF_FILE_COMPRESSION_INFO_V1
|
private struct WofFileCompressionInfoV1
|
||||||
{
|
{
|
||||||
public CompressionAlgorithm Algorithm;
|
public CompressionAlgorithm Algorithm;
|
||||||
public ulong Flags;
|
public ulong Flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ namespace MareSynchronos.Interop;
|
|||||||
|
|
||||||
public record ChatChannelOverride
|
public record ChatChannelOverride
|
||||||
{
|
{
|
||||||
public string ChannelName = string.Empty;
|
public string ChannelName { get; set; } = string.Empty;
|
||||||
public Action<byte[]>? ChatMessageHandler;
|
public Action<byte[]>? ChatMessageHandler { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe sealed class GameChatHooks : IDisposable
|
public unsafe sealed class GameChatHooks : IDisposable
|
||||||
|
|||||||
@@ -31,11 +31,11 @@ public class MdlFile
|
|||||||
public ushort Unknown9;
|
public ushort Unknown9;
|
||||||
|
|
||||||
// Offsets are stored relative to RuntimeSize instead of file start.
|
// Offsets are stored relative to RuntimeSize instead of file start.
|
||||||
public uint[] VertexOffset = [0, 0, 0];
|
public uint[] VertexOffset;
|
||||||
public uint[] IndexOffset = [0, 0, 0];
|
public uint[] IndexOffset;
|
||||||
|
|
||||||
public uint[] VertexBufferSize = [0, 0, 0];
|
public uint[] VertexBufferSize;
|
||||||
public uint[] IndexBufferSize = [0, 0, 0];
|
public uint[] IndexBufferSize;
|
||||||
public byte LodCount;
|
public byte LodCount;
|
||||||
public bool EnableIndexBufferStreaming;
|
public bool EnableIndexBufferStreaming;
|
||||||
public bool EnableEdgeGeometry;
|
public bool EnableEdgeGeometry;
|
||||||
@@ -43,15 +43,26 @@ public class MdlFile
|
|||||||
public ModelFlags1 Flags1;
|
public ModelFlags1 Flags1;
|
||||||
public ModelFlags2 Flags2;
|
public ModelFlags2 Flags2;
|
||||||
|
|
||||||
public VertexDeclarationStruct[] VertexDeclarations = [];
|
public VertexDeclarationStruct[] VertexDeclarations;
|
||||||
public ElementIdStruct[] ElementIds = [];
|
public ElementIdStruct[] ElementIds;
|
||||||
public MeshStruct[] Meshes = [];
|
public MeshStruct[] Meshes;
|
||||||
public BoundingBoxStruct[] BoneBoundingBoxes = [];
|
public BoundingBoxStruct[] BoneBoundingBoxes;
|
||||||
public LodStruct[] Lods = [];
|
public LodStruct[] Lods;
|
||||||
public ExtraLodStruct[] ExtraLods = [];
|
public ExtraLodStruct[] ExtraLods;
|
||||||
|
|
||||||
public MdlFile(string filePath)
|
public MdlFile(string filePath)
|
||||||
{
|
{
|
||||||
|
VertexOffset = Array.Empty<uint>();
|
||||||
|
IndexOffset = Array.Empty<uint>();
|
||||||
|
VertexBufferSize = Array.Empty<uint>();
|
||||||
|
IndexBufferSize = Array.Empty<uint>();
|
||||||
|
VertexDeclarations = Array.Empty<VertexDeclarationStruct>();
|
||||||
|
ElementIds = Array.Empty<ElementIdStruct>();
|
||||||
|
Meshes = Array.Empty<MeshStruct>();
|
||||||
|
BoneBoundingBoxes = Array.Empty<BoundingBoxStruct>();
|
||||||
|
Lods = Array.Empty<LodStruct>();
|
||||||
|
ExtraLods = Array.Empty<ExtraLodStruct>();
|
||||||
|
|
||||||
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||||
using var r = new LuminaBinaryReader(stream);
|
using var r = new LuminaBinaryReader(stream);
|
||||||
|
|
||||||
@@ -256,4 +267,4 @@ public class MdlFile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore S1104 // Fields should not have public accessibility
|
#pragma warning restore S1104 // Fields should not have public accessibility
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using System;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Ipc;
|
using Dalamud.Plugin.Ipc;
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
@@ -29,7 +30,7 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
private bool _marePluginEnabled = false;
|
private bool _marePluginEnabled = false;
|
||||||
private bool _impersonating = false;
|
private bool _impersonating = false;
|
||||||
private DateTime _unregisterTime = DateTime.UtcNow;
|
private DateTime _unregisterTime = DateTime.UtcNow;
|
||||||
private CancellationTokenSource _registerDelayCts = new();
|
private CancellationTokenSource? _registerDelayCts = new();
|
||||||
|
|
||||||
public bool MarePluginEnabled => _marePluginEnabled;
|
public bool MarePluginEnabled => _marePluginEnabled;
|
||||||
public bool ImpersonationActive => _impersonating;
|
public bool ImpersonationActive => _impersonating;
|
||||||
@@ -100,7 +101,7 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
{
|
{
|
||||||
if (_mareConfig.Current.MareAPI)
|
if (_mareConfig.Current.MareAPI)
|
||||||
{
|
{
|
||||||
var cancelToken = _registerDelayCts.Token;
|
var cancelToken = EnsureFreshCts(ref _registerDelayCts).Token;
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
// Wait before registering to reduce the chance of a race condition
|
// Wait before registering to reduce the chance of a race condition
|
||||||
@@ -125,7 +126,7 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_registerDelayCts = _registerDelayCts.CancelRecreate();
|
EnsureFreshCts(ref _registerDelayCts);
|
||||||
if (_impersonating)
|
if (_impersonating)
|
||||||
{
|
{
|
||||||
_loadFileProviderMare?.UnregisterFunc();
|
_loadFileProviderMare?.UnregisterFunc();
|
||||||
@@ -146,7 +147,7 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
_loadFileAsyncProvider?.UnregisterFunc();
|
_loadFileAsyncProvider?.UnregisterFunc();
|
||||||
_handledGameAddresses?.UnregisterFunc();
|
_handledGameAddresses?.UnregisterFunc();
|
||||||
|
|
||||||
_registerDelayCts.Cancel();
|
TryCancel(_registerDelayCts);
|
||||||
if (_impersonating)
|
if (_impersonating)
|
||||||
{
|
{
|
||||||
_loadFileProviderMare?.UnregisterFunc();
|
_loadFileProviderMare?.UnregisterFunc();
|
||||||
@@ -155,6 +156,7 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mediator.UnsubscribeAll(this);
|
Mediator.UnsubscribeAll(this);
|
||||||
|
CancelAndDispose(ref _registerDelayCts);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,4 +195,31 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
return _activeGameObjectHandlers.Where(g => g.Address != nint.Zero).Select(g => g.Address).Distinct().ToList();
|
return _activeGameObjectHandlers.Where(g => g.Address != nint.Zero).Select(g => g.Address).Distinct().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CancellationTokenSource EnsureFreshCts(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref cts);
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
TryCancel(cts);
|
||||||
|
cts.Dispose();
|
||||||
|
cts = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TryCancel(CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using System;
|
||||||
using MareSynchronos.PlayerData.Handlers;
|
using MareSynchronos.PlayerData.Handlers;
|
||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Utils;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace MareSynchronos.Interop.Ipc;
|
namespace MareSynchronos.Interop.Ipc;
|
||||||
|
|
||||||
public class RedrawManager
|
public class RedrawManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly MareMediator _mareMediator;
|
private readonly MareMediator _mareMediator;
|
||||||
private readonly DalamudUtilService _dalamudUtil;
|
private readonly DalamudUtilService _dalamudUtil;
|
||||||
private readonly ConcurrentDictionary<nint, bool> _penumbraRedrawRequests = [];
|
private readonly ConcurrentDictionary<nint, bool> _penumbraRedrawRequests = [];
|
||||||
private CancellationTokenSource _disposalCts = new();
|
private CancellationTokenSource? _disposalCts = new();
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public SemaphoreSlim RedrawSemaphore { get; init; } = new(2, 2);
|
public SemaphoreSlim RedrawSemaphore { get; init; } = new(2, 2);
|
||||||
|
|
||||||
@@ -32,12 +33,12 @@ public class RedrawManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using CancellationTokenSource cancelToken = new CancellationTokenSource();
|
using CancellationTokenSource cancelToken = new CancellationTokenSource();
|
||||||
using CancellationTokenSource combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, token, _disposalCts.Token);
|
using CancellationTokenSource combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, token, EnsureFreshCts(ref _disposalCts).Token);
|
||||||
var combinedToken = combinedCts.Token;
|
var combinedToken = combinedCts.Token;
|
||||||
cancelToken.CancelAfter(TimeSpan.FromSeconds(15));
|
cancelToken.CancelAfter(TimeSpan.FromSeconds(15));
|
||||||
await handler.ActOnFrameworkAfterEnsureNoDrawAsync(action, combinedToken).ConfigureAwait(false);
|
await handler.ActOnFrameworkAfterEnsureNoDrawAsync(action, combinedToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!_disposalCts.Token.IsCancellationRequested)
|
if (!_disposalCts!.Token.IsCancellationRequested)
|
||||||
await _dalamudUtil.WaitWhileCharacterIsDrawing(logger, handler, applicationId, 30000, combinedToken).ConfigureAwait(false);
|
await _dalamudUtil.WaitWhileCharacterIsDrawing(logger, handler, applicationId, 30000, combinedToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -49,6 +50,45 @@ public class RedrawManager
|
|||||||
|
|
||||||
internal void Cancel()
|
internal void Cancel()
|
||||||
{
|
{
|
||||||
_disposalCts = _disposalCts.CancelRecreate();
|
EnsureFreshCts(ref _disposalCts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref _disposalCts);
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CancellationTokenSource EnsureFreshCts(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref cts);
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.Dispose();
|
||||||
|
cts = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ public class PlayerPerformanceConfig : IMareConfiguration
|
|||||||
public bool AutoPausePlayersExceedingThresholds { get; set; } = true;
|
public bool AutoPausePlayersExceedingThresholds { get; set; } = true;
|
||||||
public bool NotifyAutoPauseDirectPairs { get; set; } = true;
|
public bool NotifyAutoPauseDirectPairs { get; set; } = true;
|
||||||
public bool NotifyAutoPauseGroupPairs { get; set; } = true;
|
public bool NotifyAutoPauseGroupPairs { get; set; } = true;
|
||||||
|
public bool ShowSelfAnalysisWarnings { get; set; } = true;
|
||||||
public int VRAMSizeAutoPauseThresholdMiB { get; set; } = 500;
|
public int VRAMSizeAutoPauseThresholdMiB { get; set; } = 500;
|
||||||
public int TrisAutoPauseThresholdThousands { get; set; } = 400;
|
public int TrisAutoPauseThresholdThousands { get; set; } = 400;
|
||||||
public bool IgnoreDirectPairs { get; set; } = true;
|
public bool IgnoreDirectPairs { get; set; } = true;
|
||||||
public TextureShrinkMode TextureShrinkMode { get; set; } = TextureShrinkMode.Default;
|
public TextureShrinkMode TextureShrinkMode { get; set; } = TextureShrinkMode.Default;
|
||||||
public bool TextureShrinkDeleteOriginal { get; set; } = false;
|
public bool TextureShrinkDeleteOriginal { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>UmbraSync</AssemblyName>
|
<AssemblyName>UmbraSync</AssemblyName>
|
||||||
<RootNamespace>UmbraSync</RootNamespace>
|
<RootNamespace>UmbraSync</RootNamespace>
|
||||||
<Version>0.1.9.5</Version>
|
<Version>0.1.9.9</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using MareSynchronos.PlayerData.Handlers;
|
|||||||
using MareSynchronos.PlayerData.Pairs;
|
using MareSynchronos.PlayerData.Pairs;
|
||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Services.ServerConfiguration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@@ -23,7 +22,6 @@ public class PairHandlerFactory
|
|||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
private readonly MareMediator _mareMediator;
|
private readonly MareMediator _mareMediator;
|
||||||
private readonly PlayerPerformanceService _playerPerformanceService;
|
private readonly PlayerPerformanceService _playerPerformanceService;
|
||||||
private readonly ServerConfigurationManager _serverConfigManager;
|
|
||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
@@ -32,7 +30,7 @@ public class PairHandlerFactory
|
|||||||
FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService,
|
FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService,
|
||||||
PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime,
|
PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime,
|
||||||
FileCacheManager fileCacheManager, MareMediator mareMediator, PlayerPerformanceService playerPerformanceService,
|
FileCacheManager fileCacheManager, MareMediator mareMediator, PlayerPerformanceService playerPerformanceService,
|
||||||
ServerConfigurationManager serverConfigManager, PairAnalyzerFactory pairAnalyzerFactory,
|
PairAnalyzerFactory pairAnalyzerFactory,
|
||||||
MareConfigService configService, VisibilityService visibilityService)
|
MareConfigService configService, VisibilityService visibilityService)
|
||||||
{
|
{
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
@@ -45,7 +43,6 @@ public class PairHandlerFactory
|
|||||||
_fileCacheManager = fileCacheManager;
|
_fileCacheManager = fileCacheManager;
|
||||||
_mareMediator = mareMediator;
|
_mareMediator = mareMediator;
|
||||||
_playerPerformanceService = playerPerformanceService;
|
_playerPerformanceService = playerPerformanceService;
|
||||||
_serverConfigManager = serverConfigManager;
|
|
||||||
_pairAnalyzerFactory = pairAnalyzerFactory;
|
_pairAnalyzerFactory = pairAnalyzerFactory;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
@@ -55,6 +52,6 @@ public class PairHandlerFactory
|
|||||||
{
|
{
|
||||||
return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory,
|
return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory,
|
||||||
_ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime,
|
_ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime,
|
||||||
_fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService);
|
_fileCacheManager, _mareMediator, _playerPerformanceService, _configService, _visibilityService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using MareSynchronos.PlayerData.Pairs;
|
|||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
using MareSynchronos.Services.Events;
|
using MareSynchronos.Services.Events;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Services.ServerConfiguration;
|
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using MareSynchronos.WebAPI.Files;
|
using MareSynchronos.WebAPI.Files;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
@@ -29,7 +28,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
||||||
private readonly IpcManager _ipcManager;
|
private readonly IpcManager _ipcManager;
|
||||||
private readonly PlayerPerformanceService _playerPerformanceService;
|
private readonly PlayerPerformanceService _playerPerformanceService;
|
||||||
private readonly ServerConfigurationManager _serverConfigManager;
|
|
||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
||||||
@@ -53,7 +51,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
DalamudUtilService dalamudUtil, IHostApplicationLifetime lifetime,
|
DalamudUtilService dalamudUtil, IHostApplicationLifetime lifetime,
|
||||||
FileCacheManager fileDbManager, MareMediator mediator,
|
FileCacheManager fileDbManager, MareMediator mediator,
|
||||||
PlayerPerformanceService playerPerformanceService,
|
PlayerPerformanceService playerPerformanceService,
|
||||||
ServerConfigurationManager serverConfigManager,
|
|
||||||
MareConfigService configService, VisibilityService visibilityService) : base(logger, mediator)
|
MareConfigService configService, VisibilityService visibilityService) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
Pair = pair;
|
Pair = pair;
|
||||||
@@ -65,7 +62,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
_fileDbManager = fileDbManager;
|
_fileDbManager = fileDbManager;
|
||||||
_playerPerformanceService = playerPerformanceService;
|
_playerPerformanceService = playerPerformanceService;
|
||||||
_serverConfigManager = serverConfigManager;
|
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
|
|
||||||
@@ -887,4 +883,4 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
Logger.LogDebug("[BASE-{appBase}] ModdedPaths calculated in {time}ms, missing files: {count}, total files: {total}", applicationBase, st.ElapsedMilliseconds, missingFiles.Count, moddedDictionary.Keys.Count);
|
Logger.LogDebug("[BASE-{appBase}] ModdedPaths calculated in {time}ms, missing files: {count}, total files: {total}", applicationBase, st.ElapsedMilliseconds, missingFiles.Count, moddedDictionary.Keys.Count);
|
||||||
return [.. missingFiles];
|
return [.. missingFiles];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,6 +270,20 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_applicationCts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_applicationCts.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetNote(string note)
|
public void SetNote(string note)
|
||||||
{
|
{
|
||||||
_serverConfigurationManager.SetNoteForUid(UserData.UID, note);
|
_serverConfigurationManager.SetNoteForUid(UserData.UID, note);
|
||||||
@@ -368,4 +382,4 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,17 +182,22 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
// add scoped services
|
// add scoped services
|
||||||
collection.AddScoped<CacheMonitor>();
|
collection.AddScoped<CacheMonitor>();
|
||||||
collection.AddScoped<UiFactory>();
|
collection.AddScoped<UiFactory>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, SettingsUi>();
|
collection.AddScoped<SettingsUi>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, CompactUi>();
|
collection.AddScoped<CompactUi>();
|
||||||
|
collection.AddScoped<EditProfileUi>();
|
||||||
|
collection.AddScoped<DataAnalysisUi>();
|
||||||
|
collection.AddScoped<AutoDetectUi>();
|
||||||
|
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<SettingsUi>());
|
||||||
|
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<CompactUi>());
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, IntroUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase, IntroUi>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, DownloadUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase, DownloadUi>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, AutoDetectUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<AutoDetectUi>());
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, ChangelogUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase, ChangelogUi>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, PopoutProfileUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase, PopoutProfileUi>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, DataAnalysisUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<DataAnalysisUi>());
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, EventViewerUI>();
|
collection.AddScoped<WindowMediatorSubscriberBase, EventViewerUI>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, CharaDataHubUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase, CharaDataHubUi>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, EditProfileUi>();
|
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<EditProfileUi>());
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, PopupHandler>();
|
collection.AddScoped<WindowMediatorSubscriberBase, PopupHandler>();
|
||||||
collection.AddScoped<WindowMediatorSubscriberBase, TypingIndicatorOverlay>();
|
collection.AddScoped<WindowMediatorSubscriberBase, TypingIndicatorOverlay>();
|
||||||
collection.AddScoped<IPopupHandler, ReportPopupHandler>();
|
collection.AddScoped<IPopupHandler, ReportPopupHandler>();
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ public class DiscoveryConfigProvider
|
|||||||
private readonly TokenProvider _tokenProvider;
|
private readonly TokenProvider _tokenProvider;
|
||||||
|
|
||||||
private WellKnownRoot? _config;
|
private WellKnownRoot? _config;
|
||||||
private DateTimeOffset _lastLoad = DateTimeOffset.MinValue;
|
|
||||||
|
|
||||||
public DiscoveryConfigProvider(ILogger<DiscoveryConfigProvider> logger, ServerConfigurationManager serverManager, TokenProvider tokenProvider)
|
public DiscoveryConfigProvider(ILogger<DiscoveryConfigProvider> logger, ServerConfigurationManager serverManager, TokenProvider tokenProvider)
|
||||||
{
|
{
|
||||||
@@ -51,7 +50,6 @@ public class DiscoveryConfigProvider
|
|||||||
|
|
||||||
root.NearbyDiscovery?.Hydrate();
|
root.NearbyDiscovery?.Hydrate();
|
||||||
_config = root;
|
_config = root;
|
||||||
_lastLoad = DateTimeOffset.UtcNow;
|
|
||||||
_logger.LogDebug("Loaded Nearby well-known (stapled), enabled={enabled}, expires={exp}", NearbyEnabled, _config?.NearbyDiscovery?.SaltExpiresAt);
|
_logger.LogDebug("Loaded Nearby well-known (stapled), enabled={enabled}, expires={exp}", NearbyEnabled, _config?.NearbyDiscovery?.SaltExpiresAt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -97,7 +95,6 @@ public class DiscoveryConfigProvider
|
|||||||
|
|
||||||
root.NearbyDiscovery?.Hydrate();
|
root.NearbyDiscovery?.Hydrate();
|
||||||
_config = root;
|
_config = root;
|
||||||
_lastLoad = DateTimeOffset.UtcNow;
|
|
||||||
_logger.LogInformation("Loaded Nearby well-known (http {path}), enabled={enabled}", path, NearbyEnabled);
|
_logger.LogInformation("Loaded Nearby well-known (http {path}), enabled={enabled}", path, NearbyEnabled);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
@@ -7,6 +8,7 @@ using MareSynchronos.WebAPI.AutoDetect;
|
|||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
|
|
||||||
namespace MareSynchronos.Services.AutoDetect;
|
namespace MareSynchronos.Services.AutoDetect;
|
||||||
@@ -34,6 +36,8 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
|
|||||||
private bool _lastAutoDetectState;
|
private bool _lastAutoDetectState;
|
||||||
private DateTime _lastHeartbeat = DateTime.MinValue;
|
private DateTime _lastHeartbeat = DateTime.MinValue;
|
||||||
private static readonly TimeSpan HeartbeatInterval = TimeSpan.FromSeconds(75);
|
private static readonly TimeSpan HeartbeatInterval = TimeSpan.FromSeconds(75);
|
||||||
|
private readonly object _entriesLock = new();
|
||||||
|
private List<NearbyEntry> _lastEntries = [];
|
||||||
|
|
||||||
public NearbyDiscoveryService(ILogger<NearbyDiscoveryService> logger, MareMediator mediator,
|
public NearbyDiscoveryService(ILogger<NearbyDiscoveryService> logger, MareMediator mediator,
|
||||||
MareConfigService config, DiscoveryConfigProvider configProvider, DalamudUtilService dalamudUtilService,
|
MareConfigService config, DiscoveryConfigProvider configProvider, DalamudUtilService dalamudUtilService,
|
||||||
@@ -52,6 +56,7 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
CancelAndDispose(ref _loopCts);
|
||||||
_loopCts = new CancellationTokenSource();
|
_loopCts = new CancellationTokenSource();
|
||||||
_mediator.Subscribe<ConnectedMessage>(this, _ => { _isConnected = true; _configProvider.TryLoadFromStapled(); });
|
_mediator.Subscribe<ConnectedMessage>(this, _ => { _isConnected = true; _configProvider.TryLoadFromStapled(); });
|
||||||
_mediator.Subscribe<DisconnectedMessage>(this, _ => { _isConnected = false; _lastPublishedSignature = null; });
|
_mediator.Subscribe<DisconnectedMessage>(this, _ => { _isConnected = false; _lastPublishedSignature = null; });
|
||||||
@@ -128,10 +133,41 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
|
|||||||
public Task StopAsync(CancellationToken cancellationToken)
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_mediator.UnsubscribeAll(this);
|
_mediator.UnsubscribeAll(this);
|
||||||
try { _loopCts?.Cancel(); } catch { }
|
CancelAndDispose(ref _loopCts);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<NearbyEntry> SnapshotEntries()
|
||||||
|
{
|
||||||
|
lock (_entriesLock)
|
||||||
|
{
|
||||||
|
return _lastEntries.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSnapshot(List<NearbyEntry> entries)
|
||||||
|
{
|
||||||
|
lock (_entriesLock)
|
||||||
|
{
|
||||||
|
_lastEntries = entries.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.Dispose();
|
||||||
|
cts = null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Loop(CancellationToken ct)
|
private async Task Loop(CancellationToken ct)
|
||||||
{
|
{
|
||||||
_configProvider.TryLoadFromStapled();
|
_configProvider.TryLoadFromStapled();
|
||||||
@@ -426,6 +462,7 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber
|
|||||||
_logger.LogDebug("Nearby: well-known not available or disabled; running in local-only mode");
|
_logger.LogDebug("Nearby: well-known not available or disabled; running in local-only mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UpdateSnapshot(entries);
|
||||||
_mediator.Publish(new DiscoveryListUpdated(entries));
|
_mediator.Publish(new DiscoveryListUpdated(entries));
|
||||||
|
|
||||||
var delayMs = Math.Max(1000, _configProvider.MinQueryIntervalMs);
|
var delayMs = Math.Max(1000, _configProvider.MinQueryIntervalMs);
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ public sealed class NearbyPendingService : IMediatorSubscriber
|
|||||||
private readonly ApiController _api;
|
private readonly ApiController _api;
|
||||||
private readonly AutoDetectRequestService _requestService;
|
private readonly AutoDetectRequestService _requestService;
|
||||||
private readonly ConcurrentDictionary<string, string> _pending = new(StringComparer.Ordinal);
|
private readonly ConcurrentDictionary<string, string> _pending = new(StringComparer.Ordinal);
|
||||||
private static readonly Regex ReqRegex = new(@"^Nearby Request: (.+) \[(?<uid>[A-Z0-9]+)\]$", RegexOptions.Compiled);
|
private static readonly TimeSpan RegexTimeout = TimeSpan.FromSeconds(1);
|
||||||
private static readonly Regex AcceptRegex = new(@"^Nearby Accept: (.+) \[(?<uid>[A-Z0-9]+)\]$", RegexOptions.Compiled);
|
private static readonly Regex ReqRegex = new(@"^Nearby Request: .+ \[(?<uid>[A-Z0-9]+)\]$", RegexOptions.Compiled | RegexOptions.ExplicitCapture, RegexTimeout);
|
||||||
|
private static readonly Regex AcceptRegex = new(@"^Nearby Accept: .+ \[(?<uid>[A-Z0-9]+)\]$", RegexOptions.Compiled | RegexOptions.ExplicitCapture, RegexTimeout);
|
||||||
|
|
||||||
public NearbyPendingService(ILogger<NearbyPendingService> logger, MareMediator mediator, ApiController api, AutoDetectRequestService requestService)
|
public NearbyPendingService(ILogger<NearbyPendingService> logger, MareMediator mediator, ApiController api, AutoDetectRequestService requestService)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public sealed class CharaDataNearbyManager : DisposableMediatorSubscriberBase
|
|||||||
private Task? _filterEntriesRunningTask;
|
private Task? _filterEntriesRunningTask;
|
||||||
private (Guid VfxId, PoseEntryExtended Pose)? _hoveredVfx = null;
|
private (Guid VfxId, PoseEntryExtended Pose)? _hoveredVfx = null;
|
||||||
private DateTime _lastExecutionTime = DateTime.UtcNow;
|
private DateTime _lastExecutionTime = DateTime.UtcNow;
|
||||||
private SemaphoreSlim _sharedDataUpdateSemaphore = new(1, 1);
|
private readonly SemaphoreSlim _sharedDataUpdateSemaphore = new(1, 1);
|
||||||
public CharaDataNearbyManager(ILogger<CharaDataNearbyManager> logger, MareMediator mediator,
|
public CharaDataNearbyManager(ILogger<CharaDataNearbyManager> logger, MareMediator mediator,
|
||||||
DalamudUtilService dalamudUtilService, VfxSpawnManager vfxSpawnManager,
|
DalamudUtilService dalamudUtilService, VfxSpawnManager vfxSpawnManager,
|
||||||
ServerConfigurationManager serverConfigurationManager,
|
ServerConfigurationManager serverConfigurationManager,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using Lumina.Data.Files;
|
using Lumina.Data.Files;
|
||||||
using MareSynchronos.API.Data;
|
using MareSynchronos.API.Data;
|
||||||
using MareSynchronos.API.Data.Enum;
|
using MareSynchronos.API.Data.Enum;
|
||||||
using MareSynchronos.FileCache;
|
using MareSynchronos.FileCache;
|
||||||
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.MareConfiguration.Models;
|
using MareSynchronos.MareConfiguration.Models;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.UI;
|
using MareSynchronos.UI;
|
||||||
@@ -16,7 +18,7 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
private readonly FileCacheManager _fileCacheManager;
|
private readonly FileCacheManager _fileCacheManager;
|
||||||
private readonly XivDataAnalyzer _xivDataAnalyzer;
|
private readonly XivDataAnalyzer _xivDataAnalyzer;
|
||||||
private CancellationTokenSource? _analysisCts;
|
private CancellationTokenSource? _analysisCts;
|
||||||
private CancellationTokenSource _baseAnalysisCts = new();
|
private CancellationTokenSource? _baseAnalysisCts = new();
|
||||||
private string _lastDataHash = string.Empty;
|
private string _lastDataHash = string.Empty;
|
||||||
private CharacterAnalysisSummary _previousSummary = CharacterAnalysisSummary.Empty;
|
private CharacterAnalysisSummary _previousSummary = CharacterAnalysisSummary.Empty;
|
||||||
private DateTime _lastAutoAnalysis = DateTime.MinValue;
|
private DateTime _lastAutoAnalysis = DateTime.MinValue;
|
||||||
@@ -28,18 +30,20 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
private const long NotificationTriangleThreshold = 150_000;
|
private const long NotificationTriangleThreshold = 150_000;
|
||||||
private bool _sizeWarningShown;
|
private bool _sizeWarningShown;
|
||||||
private bool _triangleWarningShown;
|
private bool _triangleWarningShown;
|
||||||
|
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
|
||||||
|
|
||||||
public CharacterAnalyzer(ILogger<CharacterAnalyzer> logger, MareMediator mediator, FileCacheManager fileCacheManager, XivDataAnalyzer modelAnalyzer)
|
public CharacterAnalyzer(ILogger<CharacterAnalyzer> logger, MareMediator mediator, FileCacheManager fileCacheManager, XivDataAnalyzer modelAnalyzer, PlayerPerformanceConfigService playerPerformanceConfigService)
|
||||||
: base(logger, mediator)
|
: base(logger, mediator)
|
||||||
{
|
{
|
||||||
Mediator.Subscribe<CharacterDataCreatedMessage>(this, (msg) =>
|
Mediator.Subscribe<CharacterDataCreatedMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
_baseAnalysisCts = _baseAnalysisCts.CancelRecreate();
|
var tokenSource = EnsureFreshCts(ref _baseAnalysisCts);
|
||||||
var token = _baseAnalysisCts.Token;
|
var token = tokenSource.Token;
|
||||||
_ = BaseAnalysis(msg.CharacterData, token);
|
_ = BaseAnalysis(msg.CharacterData, token);
|
||||||
});
|
});
|
||||||
_fileCacheManager = fileCacheManager;
|
_fileCacheManager = fileCacheManager;
|
||||||
_xivDataAnalyzer = modelAnalyzer;
|
_xivDataAnalyzer = modelAnalyzer;
|
||||||
|
_playerPerformanceConfigService = playerPerformanceConfigService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CurrentFile { get; internal set; }
|
public int CurrentFile { get; internal set; }
|
||||||
@@ -51,17 +55,15 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
public void CancelAnalyze()
|
public void CancelAnalyze()
|
||||||
{
|
{
|
||||||
_analysisCts?.CancelDispose();
|
CancelAndDispose(ref _analysisCts);
|
||||||
_analysisCts = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ComputeAnalysis(bool print = true, bool recalculate = false)
|
public async Task ComputeAnalysis(bool print = true, bool recalculate = false)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("=== Calculating Character Analysis ===");
|
Logger.LogDebug("=== Calculating Character Analysis ===");
|
||||||
|
|
||||||
_analysisCts = _analysisCts?.CancelRecreate() ?? new();
|
var analysisCts = EnsureFreshCts(ref _analysisCts);
|
||||||
|
var cancelToken = analysisCts.Token;
|
||||||
var cancelToken = _analysisCts.Token;
|
|
||||||
|
|
||||||
var allFiles = LastAnalysis.SelectMany(v => v.Value.Select(d => d.Value)).ToList();
|
var allFiles = LastAnalysis.SelectMany(v => v.Value.Select(d => d.Value)).ToList();
|
||||||
if (allFiles.Exists(c => !c.IsComputed || recalculate))
|
if (allFiles.Exists(c => !c.IsComputed || recalculate))
|
||||||
@@ -103,8 +105,7 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
LastCompletedAnalysis = DateTime.UtcNow;
|
LastCompletedAnalysis = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
_analysisCts.CancelDispose();
|
CancelAndDispose(ref _analysisCts);
|
||||||
_analysisCts = null;
|
|
||||||
|
|
||||||
if (print) PrintAnalysis();
|
if (print) PrintAnalysis();
|
||||||
}
|
}
|
||||||
@@ -115,8 +116,8 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
if (!disposing) return;
|
if (!disposing) return;
|
||||||
|
|
||||||
_analysisCts?.CancelDispose();
|
CancelAndDispose(ref _analysisCts);
|
||||||
_baseAnalysisCts.CancelDispose();
|
CancelAndDispose(ref _baseAnalysisCts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task BaseAnalysis(CharacterData charaData, CancellationToken token)
|
private async Task BaseAnalysis(CharacterData charaData, CancellationToken token)
|
||||||
@@ -315,6 +316,12 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_playerPerformanceConfigService.Current.ShowSelfAnalysisWarnings)
|
||||||
|
{
|
||||||
|
ResetThresholdFlagsIfNeeded(summary);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool sizeExceeded = summary.TotalCompressedSize >= NotificationSizeThreshold;
|
bool sizeExceeded = summary.TotalCompressedSize >= NotificationSizeThreshold;
|
||||||
bool trianglesExceeded = summary.TotalTriangles >= NotificationTriangleThreshold;
|
bool trianglesExceeded = summary.TotalTriangles >= NotificationTriangleThreshold;
|
||||||
List<string> exceededReasons = new();
|
List<string> exceededReasons = new();
|
||||||
@@ -366,6 +373,7 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public readonly record struct CharacterAnalysisSummary(int TotalFiles, long TotalOriginalSize, long TotalCompressedSize, long TotalTriangles, bool HasUncomputedEntries)
|
public readonly record struct CharacterAnalysisSummary(int TotalFiles, long TotalOriginalSize, long TotalCompressedSize, long TotalTriangles, bool HasUncomputedEntries)
|
||||||
{
|
{
|
||||||
public static CharacterAnalysisSummary Empty => new();
|
public static CharacterAnalysisSummary Empty => new();
|
||||||
@@ -418,4 +426,26 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CancellationTokenSource EnsureFreshCts(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref cts);
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.Dispose();
|
||||||
|
cts = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,37 +16,26 @@ namespace MareSynchronos.Services;
|
|||||||
|
|
||||||
public class GuiHookService : DisposableMediatorSubscriberBase
|
public class GuiHookService : DisposableMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
private readonly ILogger<GuiHookService> _logger;
|
|
||||||
private readonly DalamudUtilService _dalamudUtil;
|
private readonly DalamudUtilService _dalamudUtil;
|
||||||
private readonly MareConfigService _configService;
|
private readonly MareConfigService _configService;
|
||||||
private readonly INamePlateGui _namePlateGui;
|
private readonly INamePlateGui _namePlateGui;
|
||||||
private readonly IGameConfig _gameConfig;
|
private readonly IGameConfig _gameConfig;
|
||||||
private readonly IPartyList _partyList;
|
private readonly IPartyList _partyList;
|
||||||
private readonly PairManager _pairManager;
|
private readonly PairManager _pairManager;
|
||||||
private readonly IClientState _clientState;
|
|
||||||
private readonly ApiController _apiController;
|
|
||||||
private readonly TypingIndicatorStateService _typingStateService;
|
|
||||||
|
|
||||||
private static readonly TimeSpan TypingDisplayTime = TimeSpan.FromSeconds(2);
|
|
||||||
|
|
||||||
private bool _isModified = false;
|
private bool _isModified = false;
|
||||||
private bool _namePlateRoleColorsEnabled = false;
|
private bool _namePlateRoleColorsEnabled = false;
|
||||||
|
|
||||||
public GuiHookService(ILogger<GuiHookService> logger, DalamudUtilService dalamudUtil, MareMediator mediator, MareConfigService configService,
|
public GuiHookService(ILogger<GuiHookService> logger, DalamudUtilService dalamudUtil, MareMediator mediator, MareConfigService configService,
|
||||||
INamePlateGui namePlateGui, IGameConfig gameConfig, IPartyList partyList, PairManager pairManager, ApiController apiController,
|
INamePlateGui namePlateGui, IGameConfig gameConfig, IPartyList partyList, PairManager pairManager)
|
||||||
IClientState clientState, TypingIndicatorStateService typingStateService)
|
|
||||||
: base(logger, mediator)
|
: base(logger, mediator)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_namePlateGui = namePlateGui;
|
_namePlateGui = namePlateGui;
|
||||||
_gameConfig = gameConfig;
|
_gameConfig = gameConfig;
|
||||||
_partyList = partyList;
|
_partyList = partyList;
|
||||||
_pairManager = pairManager;
|
_pairManager = pairManager;
|
||||||
_apiController = apiController;
|
|
||||||
_clientState = clientState;
|
|
||||||
_typingStateService = typingStateService;
|
|
||||||
|
|
||||||
_namePlateGui.OnNamePlateUpdate += OnNamePlateUpdate;
|
_namePlateGui.OnNamePlateUpdate += OnNamePlateUpdate;
|
||||||
_namePlateGui.RequestRedraw();
|
_namePlateGui.RequestRedraw();
|
||||||
@@ -60,18 +49,13 @@ public class GuiHookService : DisposableMediatorSubscriberBase
|
|||||||
public void RequestRedraw(bool force = false)
|
public void RequestRedraw(bool force = false)
|
||||||
{
|
{
|
||||||
var useColors = _configService.Current.UseNameColors;
|
var useColors = _configService.Current.UseNameColors;
|
||||||
var showTyping = _configService.Current.TypingIndicatorShowOnNameplates;
|
|
||||||
|
|
||||||
if (!useColors && !showTyping)
|
if (!useColors)
|
||||||
{
|
{
|
||||||
if (!_isModified && !force)
|
if (!_isModified && !force)
|
||||||
return;
|
return;
|
||||||
_isModified = false;
|
_isModified = false;
|
||||||
}
|
}
|
||||||
else if (!useColors)
|
|
||||||
{
|
|
||||||
_isModified = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = Task.Run(async () => {
|
_ = Task.Run(async () => {
|
||||||
await _dalamudUtil.RunOnFrameworkThread(() => _namePlateGui.RequestRedraw()).ConfigureAwait(false);
|
await _dalamudUtil.RunOnFrameworkThread(() => _namePlateGui.RequestRedraw()).ConfigureAwait(false);
|
||||||
@@ -91,8 +75,7 @@ public class GuiHookService : DisposableMediatorSubscriberBase
|
|||||||
private void OnNamePlateUpdate(INamePlateUpdateContext context, IReadOnlyList<INamePlateUpdateHandler> handlers)
|
private void OnNamePlateUpdate(INamePlateUpdateContext context, IReadOnlyList<INamePlateUpdateHandler> handlers)
|
||||||
{
|
{
|
||||||
var applyColors = _configService.Current.UseNameColors;
|
var applyColors = _configService.Current.UseNameColors;
|
||||||
var showTypingIndicator = _configService.Current.TypingIndicatorShowOnNameplates;
|
if (!applyColors)
|
||||||
if (!applyColors && !showTypingIndicator)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var visibleUsers = _pairManager.GetOnlineUserPairs().Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue);
|
var visibleUsers = _pairManager.GetOnlineUserPairs().Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue);
|
||||||
@@ -105,11 +88,6 @@ public class GuiHookService : DisposableMediatorSubscriberBase
|
|||||||
for (int i = 0; i < _partyList.Count; ++i)
|
for (int i = 0; i < _partyList.Count; ++i)
|
||||||
partyMembers[i] = _partyList[i]?.GameObject?.Address ?? nint.MaxValue;
|
partyMembers[i] = _partyList[i]?.GameObject?.Address ?? nint.MaxValue;
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
var activeTypers = _typingStateService.GetActiveTypers(TypingDisplayTime);
|
|
||||||
var selfTypingActive = showTypingIndicator && _typingStateService.TryGetSelfTyping(TypingDisplayTime, out _, out _);
|
|
||||||
var localPlayerAddress = selfTypingActive ? _clientState.LocalPlayer?.Address ?? nint.Zero : nint.Zero;
|
|
||||||
|
|
||||||
foreach (var handler in handlers)
|
foreach (var handler in handlers)
|
||||||
{
|
{
|
||||||
if (handler != null && visibleUsersIds.Contains(handler.GameObjectId))
|
if (handler != null && visibleUsersIds.Contains(handler.GameObjectId))
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using MareSynchronos.API.Data.Comparer;
|
using MareSynchronos.API.Data.Comparer;
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Services.ServerConfiguration;
|
|
||||||
using MareSynchronos.WebAPI;
|
using MareSynchronos.WebAPI;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@@ -15,7 +14,6 @@ public class MareProfileManager : MediatorSubscriberBase
|
|||||||
private const string _nsfw = "Profile not displayed - NSFW";
|
private const string _nsfw = "Profile not displayed - NSFW";
|
||||||
private readonly ApiController _apiController;
|
private readonly ApiController _apiController;
|
||||||
private readonly MareConfigService _mareConfigService;
|
private readonly MareConfigService _mareConfigService;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
|
||||||
private readonly ConcurrentDictionary<UserData, MareProfileData> _mareProfiles = new(UserDataComparer.Instance);
|
private readonly ConcurrentDictionary<UserData, MareProfileData> _mareProfiles = new(UserDataComparer.Instance);
|
||||||
|
|
||||||
private readonly MareProfileData _defaultProfileData = new(IsFlagged: false, IsNSFW: false, string.Empty, _noDescription);
|
private readonly MareProfileData _defaultProfileData = new(IsFlagged: false, IsNSFW: false, string.Empty, _noDescription);
|
||||||
@@ -23,11 +21,10 @@ public class MareProfileManager : MediatorSubscriberBase
|
|||||||
private readonly MareProfileData _nsfwProfileData = new(IsFlagged: false, IsNSFW: false, string.Empty, _nsfw);
|
private readonly MareProfileData _nsfwProfileData = new(IsFlagged: false, IsNSFW: false, string.Empty, _nsfw);
|
||||||
|
|
||||||
public MareProfileManager(ILogger<MareProfileManager> logger, MareConfigService mareConfigService,
|
public MareProfileManager(ILogger<MareProfileManager> logger, MareConfigService mareConfigService,
|
||||||
MareMediator mediator, ApiController apiController, ServerConfigurationManager serverConfigurationManager) : base(logger, mediator)
|
MareMediator mediator, ApiController apiController) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
_mareConfigService = mareConfigService;
|
_mareConfigService = mareConfigService;
|
||||||
_apiController = apiController;
|
_apiController = apiController;
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
|
||||||
|
|
||||||
Mediator.Subscribe<ClearProfileDataMessage>(this, (msg) =>
|
Mediator.Subscribe<ClearProfileDataMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
@@ -75,4 +72,4 @@ public class MareProfileManager : MediatorSubscriberBase
|
|||||||
_mareProfiles[data] = _defaultProfileData;
|
_mareProfiles[data] = _defaultProfileData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.Text;
|
|||||||
|
|
||||||
namespace MareSynchronos.Services.Mediator;
|
namespace MareSynchronos.Services.Mediator;
|
||||||
|
|
||||||
public sealed class MareMediator : IHostedService
|
public sealed class MareMediator : IHostedService, IDisposable
|
||||||
{
|
{
|
||||||
private readonly Lock _addRemoveLock = new();
|
private readonly Lock _addRemoveLock = new();
|
||||||
private readonly ConcurrentDictionary<SubscriberAction, DateTime> _lastErrorTime = [];
|
private readonly ConcurrentDictionary<SubscriberAction, DateTime> _lastErrorTime = [];
|
||||||
@@ -109,6 +109,12 @@ public sealed class MareMediator : IHostedService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_loopCts.Cancel();
|
||||||
|
_loopCts.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
public void SubscribeKeyed<T>(IMediatorSubscriber subscriber, string key, Action<T> action) where T : MessageBase
|
public void SubscribeKeyed<T>(IMediatorSubscriber subscriber, string key, Action<T> action) where T : MessageBase
|
||||||
{
|
{
|
||||||
lock (_addRemoveLock)
|
lock (_addRemoveLock)
|
||||||
@@ -219,4 +225,4 @@ public sealed class MareMediator : IHostedService
|
|||||||
public object Action { get; }
|
public object Action { get; }
|
||||||
public IMediatorSubscriber Subscriber { get; }
|
public IMediatorSubscriber Subscriber { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MareSynchronos.API.Data;
|
using System;
|
||||||
|
using MareSynchronos.API.Data;
|
||||||
using MareSynchronos.API.Data.Enum;
|
using MareSynchronos.API.Data.Enum;
|
||||||
using MareSynchronos.FileCache;
|
using MareSynchronos.FileCache;
|
||||||
using MareSynchronos.PlayerData.Pairs;
|
using MareSynchronos.PlayerData.Pairs;
|
||||||
@@ -14,7 +15,7 @@ public sealed class PairAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
private readonly FileCacheManager _fileCacheManager;
|
private readonly FileCacheManager _fileCacheManager;
|
||||||
private readonly XivDataAnalyzer _xivDataAnalyzer;
|
private readonly XivDataAnalyzer _xivDataAnalyzer;
|
||||||
private CancellationTokenSource? _analysisCts;
|
private CancellationTokenSource? _analysisCts;
|
||||||
private CancellationTokenSource _baseAnalysisCts = new();
|
private CancellationTokenSource? _baseAnalysisCts = new();
|
||||||
private string _lastDataHash = string.Empty;
|
private string _lastDataHash = string.Empty;
|
||||||
|
|
||||||
public PairAnalyzer(ILogger<PairAnalyzer> logger, Pair pair, MareMediator mediator, FileCacheManager fileCacheManager, XivDataAnalyzer modelAnalyzer)
|
public PairAnalyzer(ILogger<PairAnalyzer> logger, Pair pair, MareMediator mediator, FileCacheManager fileCacheManager, XivDataAnalyzer modelAnalyzer)
|
||||||
@@ -24,8 +25,8 @@ public sealed class PairAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
Mediator.SubscribeKeyed<PairDataAppliedMessage>(this, pair.UserData.UID, (msg) =>
|
Mediator.SubscribeKeyed<PairDataAppliedMessage>(this, pair.UserData.UID, (msg) =>
|
||||||
{
|
{
|
||||||
_baseAnalysisCts = _baseAnalysisCts.CancelRecreate();
|
var tokenSource = EnsureFreshCts(ref _baseAnalysisCts);
|
||||||
var token = _baseAnalysisCts.Token;
|
var token = tokenSource.Token;
|
||||||
if (msg.CharacterData != null)
|
if (msg.CharacterData != null)
|
||||||
{
|
{
|
||||||
_ = BaseAnalysis(msg.CharacterData, token);
|
_ = BaseAnalysis(msg.CharacterData, token);
|
||||||
@@ -56,17 +57,15 @@ public sealed class PairAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
public void CancelAnalyze()
|
public void CancelAnalyze()
|
||||||
{
|
{
|
||||||
_analysisCts?.CancelDispose();
|
CancelAndDispose(ref _analysisCts);
|
||||||
_analysisCts = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ComputeAnalysis(bool print = true, bool recalculate = false)
|
public async Task ComputeAnalysis(bool print = true, bool recalculate = false)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("=== Calculating Character Analysis ===");
|
Logger.LogDebug("=== Calculating Character Analysis ===");
|
||||||
|
|
||||||
_analysisCts = _analysisCts?.CancelRecreate() ?? new();
|
var analysisCts = EnsureFreshCts(ref _analysisCts);
|
||||||
|
var cancelToken = analysisCts.Token;
|
||||||
var cancelToken = _analysisCts.Token;
|
|
||||||
|
|
||||||
var allFiles = LastAnalysis.SelectMany(v => v.Value.Select(d => d.Value)).ToList();
|
var allFiles = LastAnalysis.SelectMany(v => v.Value.Select(d => d.Value)).ToList();
|
||||||
if (allFiles.Exists(c => !c.IsComputed || recalculate))
|
if (allFiles.Exists(c => !c.IsComputed || recalculate))
|
||||||
@@ -102,8 +101,7 @@ public sealed class PairAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
LastPlayerName = Pair.PlayerName ?? string.Empty;
|
LastPlayerName = Pair.PlayerName ?? string.Empty;
|
||||||
Mediator.Publish(new PairDataAnalyzedMessage(Pair.UserData.UID));
|
Mediator.Publish(new PairDataAnalyzedMessage(Pair.UserData.UID));
|
||||||
|
|
||||||
_analysisCts.CancelDispose();
|
CancelAndDispose(ref _analysisCts);
|
||||||
_analysisCts = null;
|
|
||||||
|
|
||||||
if (print) PrintAnalysis();
|
if (print) PrintAnalysis();
|
||||||
}
|
}
|
||||||
@@ -114,8 +112,8 @@ public sealed class PairAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
if (!disposing) return;
|
if (!disposing) return;
|
||||||
|
|
||||||
_analysisCts?.CancelDispose();
|
CancelAndDispose(ref _analysisCts);
|
||||||
_baseAnalysisCts.CancelDispose();
|
CancelAndDispose(ref _baseAnalysisCts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task BaseAnalysis(CharacterData charaData, CancellationToken token)
|
private async Task BaseAnalysis(CharacterData charaData, CancellationToken token)
|
||||||
@@ -211,4 +209,26 @@ public sealed class PairAnalyzer : DisposableMediatorSubscriberBase
|
|||||||
UiSharedService.ByteToString(LastAnalysis.Values.Sum(c => c.Values.Sum(v => v.OriginalSize))),
|
UiSharedService.ByteToString(LastAnalysis.Values.Sum(c => c.Values.Sum(v => v.OriginalSize))),
|
||||||
UiSharedService.ByteToString(LastAnalysis.Values.Sum(c => c.Values.Sum(v => v.CompressedSize))));
|
UiSharedService.ByteToString(LastAnalysis.Values.Sum(c => c.Values.Sum(v => v.CompressedSize))));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static CancellationTokenSource EnsureFreshCts(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref cts);
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.Dispose();
|
||||||
|
cts = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public class PartyListTypingService : DisposableMediatorSubscriberBase
|
|||||||
private readonly PairManager _pairManager;
|
private readonly PairManager _pairManager;
|
||||||
private readonly TypingIndicatorStateService _typingStateService;
|
private readonly TypingIndicatorStateService _typingStateService;
|
||||||
private static readonly TimeSpan TypingDisplayTime = TimeSpan.FromSeconds(2);
|
private static readonly TimeSpan TypingDisplayTime = TimeSpan.FromSeconds(2);
|
||||||
private static readonly TimeSpan TypingDisplayDelay = TimeSpan.FromMilliseconds(500);
|
|
||||||
private static readonly TimeSpan TypingDisplayFade = TypingDisplayTime;
|
private static readonly TimeSpan TypingDisplayFade = TypingDisplayTime;
|
||||||
|
|
||||||
public PartyListTypingService(ILogger<PartyListTypingService> logger,
|
public PartyListTypingService(ILogger<PartyListTypingService> logger,
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ public class PlayerPerformanceService : DisposableMediatorSubscriberBase
|
|||||||
private readonly MareMediator _mediator;
|
private readonly MareMediator _mediator;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
|
private readonly PlayerPerformanceConfigService _playerPerformanceConfigService;
|
||||||
private readonly Dictionary<string, bool> _warnedForPlayers = new(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
public PlayerPerformanceService(ILogger<PlayerPerformanceService> logger, MareMediator mediator,
|
public PlayerPerformanceService(ILogger<PlayerPerformanceService> logger, MareMediator mediator,
|
||||||
ServerConfigurationManager serverConfigurationManager,
|
ServerConfigurationManager serverConfigurationManager,
|
||||||
@@ -327,4 +326,4 @@ public class PlayerPerformanceService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
return shrunken;
|
return shrunken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class UiFactory
|
|||||||
public StandaloneProfileUi CreateStandaloneProfileUi(Pair pair)
|
public StandaloneProfileUi CreateStandaloneProfileUi(Pair pair)
|
||||||
{
|
{
|
||||||
return new StandaloneProfileUi(_loggerFactory.CreateLogger<StandaloneProfileUi>(), _mareMediator,
|
return new StandaloneProfileUi(_loggerFactory.CreateLogger<StandaloneProfileUi>(), _mareMediator,
|
||||||
_uiSharedService, _serverConfigManager, _mareProfileManager, _pairManager, pair, _performanceCollectorService);
|
_uiSharedService, _serverConfigManager, _mareProfileManager, pair, _performanceCollectorService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PermissionWindowUI CreatePermissionPopupUi(Pair pair)
|
public PermissionWindowUI CreatePermissionPopupUi(Pair pair)
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.PlayerData.Pairs;
|
using MareSynchronos.PlayerData.Pairs;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
@@ -25,25 +23,28 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
private readonly MareConfigService _configService;
|
private readonly MareConfigService _configService;
|
||||||
private readonly DalamudUtilService _dalamud;
|
private readonly DalamudUtilService _dalamud;
|
||||||
private readonly IObjectTable _objectTable;
|
|
||||||
private readonly AutoDetectRequestService _requestService;
|
private readonly AutoDetectRequestService _requestService;
|
||||||
|
private readonly NearbyDiscoveryService _discoveryService;
|
||||||
private readonly NearbyPendingService _pendingService;
|
private readonly NearbyPendingService _pendingService;
|
||||||
private readonly PairManager _pairManager;
|
private readonly PairManager _pairManager;
|
||||||
private List<Services.Mediator.NearbyEntry> _entries = new();
|
private List<Services.Mediator.NearbyEntry> _entries;
|
||||||
private readonly HashSet<string> _acceptInFlight = new(StringComparer.Ordinal);
|
private readonly HashSet<string> _acceptInFlight = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
public AutoDetectUi(ILogger<AutoDetectUi> logger, MareMediator mediator,
|
public AutoDetectUi(ILogger<AutoDetectUi> logger, MareMediator mediator,
|
||||||
MareConfigService configService, DalamudUtilService dalamudUtilService, IObjectTable objectTable,
|
MareConfigService configService, DalamudUtilService dalamudUtilService,
|
||||||
AutoDetectRequestService requestService, NearbyPendingService pendingService, PairManager pairManager,
|
AutoDetectRequestService requestService, NearbyPendingService pendingService, PairManager pairManager,
|
||||||
|
NearbyDiscoveryService discoveryService,
|
||||||
PerformanceCollectorService performanceCollectorService)
|
PerformanceCollectorService performanceCollectorService)
|
||||||
: base(logger, mediator, "AutoDetect", performanceCollectorService)
|
: base(logger, mediator, "AutoDetect", performanceCollectorService)
|
||||||
{
|
{
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_dalamud = dalamudUtilService;
|
_dalamud = dalamudUtilService;
|
||||||
_objectTable = objectTable;
|
|
||||||
_requestService = requestService;
|
_requestService = requestService;
|
||||||
_pendingService = pendingService;
|
_pendingService = pendingService;
|
||||||
_pairManager = pairManager;
|
_pairManager = pairManager;
|
||||||
|
_discoveryService = discoveryService;
|
||||||
|
Mediator.Subscribe<Services.Mediator.DiscoveryListUpdated>(this, OnDiscoveryUpdated);
|
||||||
|
_entries = _discoveryService.SnapshotEntries();
|
||||||
|
|
||||||
Flags |= ImGuiWindowFlags.NoScrollbar;
|
Flags |= ImGuiWindowFlags.NoScrollbar;
|
||||||
SizeConstraints = new WindowSizeConstraints()
|
SizeConstraints = new WindowSizeConstraints()
|
||||||
@@ -90,6 +91,11 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DrawInline()
|
||||||
|
{
|
||||||
|
DrawInternal();
|
||||||
|
}
|
||||||
|
|
||||||
private static void DrawStyledTab(string label, Vector4 accent, Vector4 inactive, Vector4 hover, Action draw, bool disabled = false)
|
private static void DrawStyledTab(string label, Vector4 accent, Vector4 inactive, Vector4 hover, Action draw, bool disabled = false)
|
||||||
{
|
{
|
||||||
var tabColor = disabled ? ImGuiColors.DalamudGrey3 : inactive;
|
var tabColor = disabled ? ImGuiColors.DalamudGrey3 : inactive;
|
||||||
@@ -213,61 +219,102 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(6);
|
ImGuiHelpers.ScaledDummy(6);
|
||||||
|
|
||||||
// Table header
|
var sourceEntries = _entries.Count > 0 ? _entries : _discoveryService.SnapshotEntries();
|
||||||
if (ImGui.BeginTable("autodetect-nearby", 5, ImGuiTableFlags.SizingStretchProp))
|
var orderedEntries = sourceEntries
|
||||||
{
|
.OrderBy(e => float.IsNaN(e.Distance) ? float.MaxValue : e.Distance)
|
||||||
ImGui.TableSetupColumn("Name");
|
.ToList();
|
||||||
ImGui.TableSetupColumn("World");
|
|
||||||
ImGui.TableSetupColumn("Distance");
|
|
||||||
ImGui.TableSetupColumn("Status");
|
|
||||||
ImGui.TableSetupColumn("Action");
|
|
||||||
ImGui.TableHeadersRow();
|
|
||||||
|
|
||||||
var data = _entries.Count > 0 ? _entries.Where(e => e.IsMatch).ToList() : new List<Services.Mediator.NearbyEntry>();
|
if (orderedEntries.Count == 0)
|
||||||
foreach (var e in data)
|
{
|
||||||
|
UiSharedService.ColorTextWrapped("Aucune présence UmbraSync détectée à proximité pour le moment.", ImGuiColors.DalamudGrey3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ImGui.BeginTable("autodetect-nearby", 5, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.RowBg))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableSetupColumn("Nom");
|
||||||
|
ImGui.TableSetupColumn("Monde");
|
||||||
|
ImGui.TableSetupColumn("Distance");
|
||||||
|
ImGui.TableSetupColumn("Statut");
|
||||||
|
ImGui.TableSetupColumn("Action");
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
for (int i = 0; i < orderedEntries.Count; i++)
|
||||||
|
{
|
||||||
|
var entry = orderedEntries[i];
|
||||||
|
bool isMatch = entry.IsMatch;
|
||||||
|
bool alreadyPaired = IsAlreadyPairedByUidOrAlias(entry);
|
||||||
|
bool overDistance = !float.IsNaN(entry.Distance) && entry.Distance > maxDist;
|
||||||
|
bool canRequest = isMatch && entry.AcceptPairRequests && !string.IsNullOrEmpty(entry.Token) && !alreadyPaired;
|
||||||
|
|
||||||
|
string displayName = entry.DisplayName ?? entry.Name;
|
||||||
|
string worldName = entry.WorldId == 0
|
||||||
|
? "-"
|
||||||
|
: (_dalamud.WorldData.Value.TryGetValue(entry.WorldId, out var mappedWorld) ? mappedWorld : entry.WorldId.ToString(CultureInfo.InvariantCulture));
|
||||||
|
string distanceText = float.IsNaN(entry.Distance) ? "-" : $"{entry.Distance:0.0} m";
|
||||||
|
|
||||||
|
string status = alreadyPaired
|
||||||
|
? "Déjà appairé"
|
||||||
|
: overDistance
|
||||||
|
? $"Hors portée (> {maxDist} m)"
|
||||||
|
: !isMatch
|
||||||
|
? "Umbra non activé"
|
||||||
|
: !entry.AcceptPairRequests
|
||||||
|
? "Invitations refusées"
|
||||||
|
: string.IsNullOrEmpty(entry.Token)
|
||||||
|
? "Indisponible"
|
||||||
|
: "Disponible";
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(displayName);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(worldName);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(distanceText);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(status);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
using (ImRaii.PushId(i))
|
||||||
{
|
{
|
||||||
ImGui.TableNextColumn();
|
if (canRequest && !overDistance)
|
||||||
ImGui.TextUnformatted(e.Name);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.TextUnformatted(e.WorldId == 0 ? "-" : (_dalamud.WorldData.Value.TryGetValue(e.WorldId, out var w) ? w : e.WorldId.ToString()));
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.TextUnformatted(float.IsNaN(e.Distance) ? "-" : $"{e.Distance:0.0} m");
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
bool alreadyPaired = IsAlreadyPairedByUidOrAlias(e);
|
|
||||||
string status = alreadyPaired ? "Paired" : (string.IsNullOrEmpty(e.Token) ? "Requests disabled" : "On Umbra");
|
|
||||||
ImGui.TextUnformatted(status);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
using (ImRaii.Disabled(alreadyPaired || string.IsNullOrEmpty(e.Token)))
|
|
||||||
{
|
{
|
||||||
if (alreadyPaired)
|
if (ImGui.Button("Envoyer invitation"))
|
||||||
{
|
{
|
||||||
ImGui.Button($"Already sync##{e.Name}");
|
_ = _requestService.SendRequestAsync(entry.Token!, entry.Uid, entry.DisplayName);
|
||||||
}
|
}
|
||||||
else if (string.IsNullOrEmpty(e.Token))
|
UiSharedService.AttachToolTip("Envoie une demande d'appairage via AutoDetect.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string reason = alreadyPaired
|
||||||
|
? "Vous êtes déjà appairé avec ce joueur."
|
||||||
|
: overDistance
|
||||||
|
? $"Ce joueur est au-delà de la distance maximale configurée ({maxDist} m)."
|
||||||
|
: !isMatch
|
||||||
|
? "Ce joueur n'utilise pas UmbraSync ou ne s'est pas rendu détectable."
|
||||||
|
: !entry.AcceptPairRequests
|
||||||
|
? "Ce joueur a désactivé la réception automatique des invitations."
|
||||||
|
: string.IsNullOrEmpty(entry.Token)
|
||||||
|
? "Impossible d'obtenir un jeton d'invitation pour ce joueur."
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
ImGui.TextDisabled(status);
|
||||||
|
if (!string.IsNullOrEmpty(reason))
|
||||||
{
|
{
|
||||||
ImGui.Button($"Requests disabled##{e.Name}");
|
UiSharedService.AttachToolTip(reason);
|
||||||
}
|
|
||||||
else if (ImGui.Button($"Send request##{e.Name}"))
|
|
||||||
{
|
|
||||||
_ = _requestService.SendRequestAsync(e.Token!, e.Uid, e.DisplayName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndTable();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnOpen()
|
ImGui.EndTable();
|
||||||
{
|
|
||||||
base.OnOpen();
|
|
||||||
Mediator.Subscribe<Services.Mediator.DiscoveryListUpdated>(this, OnDiscoveryUpdated);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnClose()
|
|
||||||
{
|
|
||||||
Mediator.Unsubscribe<Services.Mediator.DiscoveryListUpdated>(this);
|
|
||||||
base.OnClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDiscoveryUpdated(Services.Mediator.DiscoveryListUpdated msg)
|
private void OnDiscoveryUpdated(Services.Mediator.DiscoveryListUpdated msg)
|
||||||
|
|||||||
@@ -544,7 +544,8 @@ internal sealed partial class CharaDataHubUi
|
|||||||
{
|
{
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Download your Online Character Data from Server"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Download your Online Character Data from Server"))
|
||||||
{
|
{
|
||||||
_ = _charaDataManager.GetAllData(_disposalCts.Token);
|
var cts = EnsureFreshCts(ref _disposalCts);
|
||||||
|
_ = _charaDataManager.GetAllData(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_charaDataManager.DataGetTimeoutTask != null && !_charaDataManager.DataGetTimeoutTask.IsCompleted)
|
if (_charaDataManager.DataGetTimeoutTask != null && !_charaDataManager.DataGetTimeoutTask.IsCompleted)
|
||||||
@@ -654,7 +655,8 @@ internal sealed partial class CharaDataHubUi
|
|||||||
{
|
{
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "New Character Data Entry"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "New Character Data Entry"))
|
||||||
{
|
{
|
||||||
_charaDataManager.CreateCharaDataEntry(_closalCts.Token);
|
var cts = EnsureFreshCts(ref _closalCts);
|
||||||
|
_charaDataManager.CreateCharaDataEntry(cts.Token);
|
||||||
_selectNewEntry = true;
|
_selectNewEntry = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -848,4 +850,4 @@ internal sealed partial class CharaDataHubUi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,8 @@ internal partial class CharaDataHubUi
|
|||||||
{
|
{
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Update Data Shared With You"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Update Data Shared With You"))
|
||||||
{
|
{
|
||||||
_ = _charaDataManager.GetAllSharedData(_disposalCts.Token).ContinueWith(u => UpdateFilteredItems());
|
var cts = EnsureFreshCts(ref _disposalCts);
|
||||||
|
_ = _charaDataManager.GetAllSharedData(cts.Token).ContinueWith(u => UpdateFilteredItems());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_charaDataManager.GetSharedWithYouTimeoutTask != null && !_charaDataManager.GetSharedWithYouTimeoutTask.IsCompleted)
|
if (_charaDataManager.GetSharedWithYouTimeoutTask != null && !_charaDataManager.GetSharedWithYouTimeoutTask.IsCompleted)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using System;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Interface.ImGuiFileDialog;
|
using Dalamud.Interface.ImGuiFileDialog;
|
||||||
@@ -30,9 +31,9 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
private readonly CharaDataGposeTogetherManager _charaDataGposeTogetherManager;
|
private readonly CharaDataGposeTogetherManager _charaDataGposeTogetherManager;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private CancellationTokenSource _closalCts = new();
|
private CancellationTokenSource? _closalCts = new();
|
||||||
private bool _disableUI = false;
|
private bool _disableUI = false;
|
||||||
private CancellationTokenSource _disposalCts = new();
|
private CancellationTokenSource? _disposalCts = new();
|
||||||
private string _exportDescription = string.Empty;
|
private string _exportDescription = string.Empty;
|
||||||
private string _filterCodeNote = string.Empty;
|
private string _filterCodeNote = string.Empty;
|
||||||
private string _filterDescription = string.Empty;
|
private string _filterDescription = string.Empty;
|
||||||
@@ -123,7 +124,14 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_closalCts.Cancel();
|
try
|
||||||
|
{
|
||||||
|
_closalCts?.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
EnsureFreshCts(ref _closalCts);
|
||||||
SelectedDtoId = string.Empty;
|
SelectedDtoId = string.Empty;
|
||||||
_filteredDict = null;
|
_filteredDict = null;
|
||||||
_sharedWithYouOwnerFilter = string.Empty;
|
_sharedWithYouOwnerFilter = string.Empty;
|
||||||
@@ -135,15 +143,15 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
public override void OnOpen()
|
public override void OnOpen()
|
||||||
{
|
{
|
||||||
_closalCts = _closalCts.CancelRecreate();
|
EnsureFreshCts(ref _closalCts);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
_closalCts.CancelDispose();
|
CancelAndDispose(ref _closalCts);
|
||||||
_disposalCts.CancelDispose();
|
CancelAndDispose(ref _disposalCts);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
@@ -689,7 +697,8 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Download your Character Data"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Download your Character Data"))
|
||||||
{
|
{
|
||||||
_ = _charaDataManager.GetAllData(_disposalCts.Token);
|
var cts = EnsureFreshCts(ref _disposalCts);
|
||||||
|
_ = _charaDataManager.GetAllData(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_charaDataManager.DataGetTimeoutTask != null && !_charaDataManager.DataGetTimeoutTask.IsCompleted)
|
if (_charaDataManager.DataGetTimeoutTask != null && !_charaDataManager.DataGetTimeoutTask.IsCompleted)
|
||||||
@@ -1104,4 +1113,26 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
drawAction();
|
drawAction();
|
||||||
if (_disableUI) ImGui.BeginDisabled();
|
if (_disableUI) ImGui.BeginDisabled();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static CancellationTokenSource EnsureFreshCts(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref cts);
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cts.Dispose();
|
||||||
|
cts = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,43 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override float GetRightSideExtraWidth()
|
||||||
|
{
|
||||||
|
float width = 0f;
|
||||||
|
float spacing = ImGui.GetStyle().ItemSpacing.X;
|
||||||
|
|
||||||
|
var soundsDisabled = _fullInfoDto.GroupUserPermissions.IsDisableSounds();
|
||||||
|
var animDisabled = _fullInfoDto.GroupUserPermissions.IsDisableAnimations();
|
||||||
|
var vfxDisabled = _fullInfoDto.GroupUserPermissions.IsDisableVFX();
|
||||||
|
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
|
||||||
|
var individualAnimDisabled = (_pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
|
||||||
|
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
|
||||||
|
|
||||||
|
bool showInfo = individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled || animDisabled || soundsDisabled || vfxDisabled;
|
||||||
|
bool showShared = _charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData);
|
||||||
|
bool showPlus = _pair.UserPair == null && _pair.IsOnline;
|
||||||
|
|
||||||
|
if (showShared)
|
||||||
|
{
|
||||||
|
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X + spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showInfo)
|
||||||
|
{
|
||||||
|
var icon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled)
|
||||||
|
? FontAwesomeIcon.ExclamationTriangle
|
||||||
|
: FontAwesomeIcon.InfoCircle;
|
||||||
|
width += UiSharedService.GetIconSize(icon).X + spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showPlus)
|
||||||
|
{
|
||||||
|
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X + spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void DrawLeftSide(float textPosY, float originalY)
|
protected override void DrawLeftSide(float textPosY, float originalY)
|
||||||
{
|
{
|
||||||
var entryUID = _pair.UserData.AliasOrUID;
|
var entryUID = _pair.UserData.AliasOrUID;
|
||||||
@@ -164,7 +201,7 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
|
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
|
||||||
|
|
||||||
bool showShared = _charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData);
|
bool showShared = _charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData);
|
||||||
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled);
|
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled || animDisabled || soundsDisabled || vfxDisabled);
|
||||||
bool showPlus = _pair.UserPair == null && _pair.IsOnline;
|
bool showPlus = _pair.UserPair == null && _pair.IsOnline;
|
||||||
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
|
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
|
||||||
bool showPause = true;
|
bool showPause = true;
|
||||||
@@ -173,23 +210,47 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle
|
var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle
|
||||||
: ((soundsDisabled || animDisabled || vfxDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None);
|
: ((soundsDisabled || animDisabled || vfxDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None);
|
||||||
var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X;
|
var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X;
|
||||||
var infoIconWidth = UiSharedService.GetIconSize(permIcon).X;
|
var infoIconWidth = showInfo && permIcon != FontAwesomeIcon.None ? UiSharedService.GetIconSize(permIcon).X : 0f;
|
||||||
var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
|
var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
|
||||||
var pauseIcon = _fullInfoDto.GroupUserPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
var pauseIcon = _fullInfoDto.GroupUserPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||||
var pauseButtonWidth = _uiSharedService.GetIconButtonSize(pauseIcon).X;
|
var pauseButtonWidth = _uiSharedService.GetIconButtonSize(pauseIcon).X;
|
||||||
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
|
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
|
||||||
|
|
||||||
var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing
|
float totalWidth = 0f;
|
||||||
- (showShared ? (runningIconWidth + spacing) : 0)
|
void Accumulate(bool condition, float width)
|
||||||
- (showInfo ? (infoIconWidth + spacing) : 0)
|
{
|
||||||
- (showPlus ? (plusButtonWidth + spacing) : 0)
|
if (!condition || width <= 0f) return;
|
||||||
- (showPause ? (pauseButtonWidth + spacing) : 0)
|
if (totalWidth > 0f) totalWidth += spacing;
|
||||||
- (showBars ? (barButtonWidth + spacing) : 0);
|
totalWidth += width;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.SameLine(pos);
|
Accumulate(showShared, runningIconWidth);
|
||||||
|
Accumulate(showInfo && infoIconWidth > 0f, infoIconWidth);
|
||||||
|
Accumulate(showPlus, plusButtonWidth);
|
||||||
|
Accumulate(showPause, pauseButtonWidth);
|
||||||
|
if (showBars)
|
||||||
|
{
|
||||||
|
if (totalWidth > 0f) totalWidth += spacing;
|
||||||
|
totalWidth += barButtonWidth;
|
||||||
|
}
|
||||||
|
if (showPause && showBars)
|
||||||
|
{
|
||||||
|
totalWidth -= spacing * 0.5f;
|
||||||
|
if (totalWidth < 0f) totalWidth = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float cardPaddingX = UiSharedService.GetCardContentPaddingX();
|
||||||
|
float rightMargin = cardPaddingX + 6f * ImGuiHelpers.GlobalScale;
|
||||||
|
float baseX = MathF.Max(ImGui.GetCursorPosX(),
|
||||||
|
ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - rightMargin - totalWidth);
|
||||||
|
float currentX = baseX;
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetCursorPosX(baseX);
|
||||||
|
|
||||||
if (showShared)
|
if (showShared)
|
||||||
{
|
{
|
||||||
|
ImGui.SetCursorPosY(textPosY);
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.Running);
|
_uiSharedService.IconText(FontAwesomeIcon.Running);
|
||||||
|
|
||||||
UiSharedService.AttachToolTip($"This user has shared {sharedData!.Count} Character Data Sets with you." + UiSharedService.TooltipSeparator
|
UiSharedService.AttachToolTip($"This user has shared {sharedData!.Count} Character Data Sets with you." + UiSharedService.TooltipSeparator
|
||||||
@@ -199,95 +260,99 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
{
|
{
|
||||||
_mediator.Publish(new OpenCharaDataHubWithFilterMessage(_pair.UserData));
|
_mediator.Publish(new OpenCharaDataHubWithFilterMessage(_pair.UserData));
|
||||||
}
|
}
|
||||||
ImGui.SameLine();
|
currentX += runningIconWidth + spacing;
|
||||||
|
ImGui.SetCursorPosX(currentX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (individualAnimDisabled || individualSoundsDisabled)
|
if (showInfo && infoIconWidth > 0f)
|
||||||
{
|
{
|
||||||
ImGui.SetCursorPosY(textPosY);
|
ImGui.SetCursorPosY(textPosY);
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
|
if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled)
|
||||||
_uiSharedService.IconText(permIcon);
|
|
||||||
ImGui.PopStyleColor();
|
|
||||||
if (ImGui.IsItemHovered())
|
|
||||||
{
|
{
|
||||||
ImGui.BeginTooltip();
|
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
|
||||||
|
_uiSharedService.IconText(permIcon);
|
||||||
ImGui.TextUnformatted("Individual User permissions");
|
ImGui.PopStyleColor();
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
if (individualSoundsDisabled)
|
|
||||||
{
|
{
|
||||||
var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID;
|
ImGui.BeginTooltip();
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.VolumeMute);
|
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TextUnformatted(userSoundsText);
|
|
||||||
ImGui.NewLine();
|
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (individualAnimDisabled)
|
ImGui.TextUnformatted("Individual User permissions");
|
||||||
{
|
|
||||||
var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID;
|
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.WindowClose);
|
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TextUnformatted(userAnimText);
|
|
||||||
ImGui.NewLine();
|
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (individualVFXDisabled)
|
if (individualSoundsDisabled)
|
||||||
{
|
{
|
||||||
var userVFXText = "VFX sync disabled with " + _pair.UserData.AliasOrUID;
|
var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID;
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.TimesCircle);
|
_uiSharedService.IconText(FontAwesomeIcon.VolumeMute);
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
ImGui.TextUnformatted(userVFXText);
|
ImGui.TextUnformatted(userSoundsText);
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableVFX() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableVFX() ? "Disabled" : "Enabled"));
|
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableSounds() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableSounds() ? "Disabled" : "Enabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndTooltip();
|
if (individualAnimDisabled)
|
||||||
|
{
|
||||||
|
var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID;
|
||||||
|
_uiSharedService.IconText(FontAwesomeIcon.WindowClose);
|
||||||
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.TextUnformatted(userAnimText);
|
||||||
|
ImGui.NewLine();
|
||||||
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? "Disabled" : "Enabled"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (individualVFXDisabled)
|
||||||
|
{
|
||||||
|
var userVFXText = "VFX sync disabled with " + _pair.UserData.AliasOrUID;
|
||||||
|
_uiSharedService.IconText(FontAwesomeIcon.TimesCircle);
|
||||||
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.TextUnformatted(userVFXText);
|
||||||
|
ImGui.NewLine();
|
||||||
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.TextUnformatted("You: " + (_pair.UserPair!.OwnPermissions.IsDisableVFX() ? "Disabled" : "Enabled") + ", They: " + (_pair.UserPair!.OtherPermissions.IsDisableVFX() ? "Disabled" : "Enabled"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui.SameLine();
|
else
|
||||||
}
|
|
||||||
else if ((animDisabled || soundsDisabled))
|
|
||||||
{
|
|
||||||
ImGui.SetCursorPosY(textPosY);
|
|
||||||
_uiSharedService.IconText(permIcon);
|
|
||||||
if (ImGui.IsItemHovered())
|
|
||||||
{
|
{
|
||||||
ImGui.BeginTooltip();
|
_uiSharedService.IconText(permIcon);
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
ImGui.TextUnformatted("Syncshell User permissions");
|
|
||||||
|
|
||||||
if (soundsDisabled)
|
|
||||||
{
|
{
|
||||||
var userSoundsText = "Sound sync disabled by " + _pair.UserData.AliasOrUID;
|
ImGui.BeginTooltip();
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.VolumeMute);
|
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TextUnformatted(userSoundsText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (animDisabled)
|
ImGui.TextUnformatted("Syncshell User permissions");
|
||||||
{
|
|
||||||
var userAnimText = "Animation sync disabled by " + _pair.UserData.AliasOrUID;
|
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.WindowClose);
|
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TextUnformatted(userAnimText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vfxDisabled)
|
if (soundsDisabled)
|
||||||
{
|
{
|
||||||
var userVFXText = "VFX sync disabled by " + _pair.UserData.AliasOrUID;
|
var userSoundsText = "Sound sync disabled by " + _pair.UserData.AliasOrUID;
|
||||||
_uiSharedService.IconText(FontAwesomeIcon.TimesCircle);
|
_uiSharedService.IconText(FontAwesomeIcon.VolumeMute);
|
||||||
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
ImGui.TextUnformatted(userVFXText);
|
ImGui.TextUnformatted(userSoundsText);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndTooltip();
|
if (animDisabled)
|
||||||
|
{
|
||||||
|
var userAnimText = "Animation sync disabled by " + _pair.UserData.AliasOrUID;
|
||||||
|
_uiSharedService.IconText(FontAwesomeIcon.WindowClose);
|
||||||
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.TextUnformatted(userAnimText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vfxDisabled)
|
||||||
|
{
|
||||||
|
var userVFXText = "VFX sync disabled by " + _pair.UserData.AliasOrUID;
|
||||||
|
_uiSharedService.IconText(FontAwesomeIcon.TimesCircle);
|
||||||
|
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.TextUnformatted(userVFXText);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui.SameLine();
|
|
||||||
|
currentX += infoIconWidth + spacing;
|
||||||
|
ImGui.SetCursorPosX(currentX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showPlus)
|
if (showPlus)
|
||||||
@@ -303,13 +368,14 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UiSharedService.AttachToolTip(AppendSeenInfo("Send pairing invite to " + entryUID));
|
UiSharedService.AttachToolTip(AppendSeenInfo("Send pairing invite to " + entryUID));
|
||||||
ImGui.SameLine();
|
currentX += plusButtonWidth + spacing;
|
||||||
|
ImGui.SetCursorPosX(currentX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showPause)
|
if (showPause)
|
||||||
{
|
{
|
||||||
|
float gapToBars = showBars ? spacing * 0.5f : spacing;
|
||||||
ImGui.SetCursorPosY(originalY);
|
ImGui.SetCursorPosY(originalY);
|
||||||
|
|
||||||
if (_uiSharedService.IconButton(pauseIcon))
|
if (_uiSharedService.IconButton(pauseIcon))
|
||||||
{
|
{
|
||||||
var newPermissions = _fullInfoDto.GroupUserPermissions ^ GroupUserPermissions.Paused;
|
var newPermissions = _fullInfoDto.GroupUserPermissions ^ GroupUserPermissions.Paused;
|
||||||
@@ -318,19 +384,20 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
UiSharedService.AttachToolTip(AppendSeenInfo((_fullInfoDto.GroupUserPermissions.IsPaused() ? "Resume" : "Pause") + " syncing with " + entryUID));
|
UiSharedService.AttachToolTip(AppendSeenInfo((_fullInfoDto.GroupUserPermissions.IsPaused() ? "Resume" : "Pause") + " syncing with " + entryUID));
|
||||||
ImGui.SameLine();
|
currentX += pauseButtonWidth + gapToBars;
|
||||||
|
ImGui.SetCursorPosX(currentX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showBars)
|
if (showBars)
|
||||||
{
|
{
|
||||||
ImGui.SetCursorPosY(originalY);
|
ImGui.SetCursorPosY(originalY);
|
||||||
|
|
||||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars))
|
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars))
|
||||||
{
|
{
|
||||||
ImGui.OpenPopup("Popup");
|
ImGui.OpenPopup("Syncshell Flyout Menu");
|
||||||
}
|
}
|
||||||
|
currentX += barButtonWidth;
|
||||||
|
ImGui.SetCursorPosX(currentX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.BeginPopup("Popup"))
|
if (ImGui.BeginPopup("Popup"))
|
||||||
{
|
{
|
||||||
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))
|
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))
|
||||||
@@ -416,7 +483,7 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
ImGui.EndPopup();
|
ImGui.EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
return pos - spacing;
|
return baseX - spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string AppendSeenInfo(string tooltip)
|
private string AppendSeenInfo(string tooltip)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
using MareSynchronos.PlayerData.Pairs;
|
using MareSynchronos.PlayerData.Pairs;
|
||||||
using MareSynchronos.UI.Handlers;
|
using MareSynchronos.UI.Handlers;
|
||||||
using MareSynchronos.WebAPI;
|
using MareSynchronos.WebAPI;
|
||||||
@@ -28,38 +31,77 @@ public abstract class DrawPairBase
|
|||||||
|
|
||||||
public void DrawPairedClient()
|
public void DrawPairedClient()
|
||||||
{
|
{
|
||||||
var originalY = ImGui.GetCursorPosY();
|
var style = ImGui.GetStyle();
|
||||||
var pauseIconSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Play);
|
var padding = style.FramePadding;
|
||||||
var textSize = ImGui.CalcTextSize(_pair.UserData.AliasOrUID);
|
var spacing = style.ItemSpacing;
|
||||||
|
var rowStartCursor = ImGui.GetCursorPos();
|
||||||
|
var rowStartScreen = ImGui.GetCursorScreenPos();
|
||||||
|
|
||||||
var startPos = ImGui.GetCursorStartPos();
|
var pauseButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause);
|
||||||
|
var playButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Play);
|
||||||
|
var menuButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
||||||
|
|
||||||
var framePadding = ImGui.GetStyle().FramePadding;
|
float pauseClusterWidth = Math.Max(pauseButtonSize.X, playButtonSize.X);
|
||||||
var lineHeight = textSize.Y + framePadding.Y * 2;
|
float pauseClusterHeight = Math.Max(pauseButtonSize.Y, playButtonSize.Y);
|
||||||
|
float reservedSpacing = style.ItemSpacing.X * 2.4f;
|
||||||
|
float rightButtonWidth =
|
||||||
|
menuButtonSize.X +
|
||||||
|
pauseClusterWidth +
|
||||||
|
reservedSpacing +
|
||||||
|
GetRightSideExtraWidth();
|
||||||
|
|
||||||
var off = startPos.Y;
|
float availableWidth = Math.Max(ImGui.GetContentRegionAvail().X - rightButtonWidth, 1f);
|
||||||
var height = UiSharedService.GetWindowContentRegionHeight();
|
float textHeight = ImGui.GetFontSize();
|
||||||
|
var presenceIconSize = UiSharedService.GetIconSize(FontAwesomeIcon.Moon);
|
||||||
|
float iconHeight = presenceIconSize.Y;
|
||||||
|
float contentHeight = Math.Max(textHeight, Math.Max(iconHeight, pauseClusterHeight));
|
||||||
|
float rowHeight = contentHeight + padding.Y * 2f;
|
||||||
|
float totalHeight = rowHeight + spacing.Y;
|
||||||
|
|
||||||
if ((originalY + off) < -lineHeight || (originalY + off) > height)
|
var origin = ImGui.GetCursorStartPos();
|
||||||
|
var top = origin.Y + rowStartCursor.Y;
|
||||||
|
var bottom = top + totalHeight;
|
||||||
|
var visibleHeight = UiSharedService.GetWindowContentRegionHeight();
|
||||||
|
if (bottom < 0 || top > visibleHeight)
|
||||||
{
|
{
|
||||||
ImGui.Dummy(new System.Numerics.Vector2(0f, lineHeight));
|
ImGui.SetCursorPos(new Vector2(rowStartCursor.X, rowStartCursor.Y + totalHeight));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var textPosY = originalY + pauseIconSize.Y / 2 - textSize.Y / 2;
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
DrawLeftSide(textPosY, originalY);
|
var backgroundColor = new Vector4(0.10f, 0.10f, 0.14f, 0.95f);
|
||||||
|
var borderColor = new Vector4(0f, 0f, 0f, 0.9f);
|
||||||
|
float rounding = Math.Max(style.FrameRounding, 7f * ImGuiHelpers.GlobalScale);
|
||||||
|
|
||||||
|
var panelMin = rowStartScreen + new Vector2(0f, spacing.Y * 0.15f);
|
||||||
|
var panelMax = panelMin + new Vector2(availableWidth, rowHeight - spacing.Y * 0.3f);
|
||||||
|
drawList.AddRectFilled(panelMin, panelMax, ImGui.ColorConvertFloat4ToU32(backgroundColor), rounding);
|
||||||
|
drawList.AddRect(panelMin, panelMax, ImGui.ColorConvertFloat4ToU32(borderColor), rounding);
|
||||||
|
|
||||||
|
float iconTop = rowStartCursor.Y + (rowHeight - iconHeight) / 2f;
|
||||||
|
float textTop = rowStartCursor.Y + (rowHeight - textHeight) / 2f - padding.Y * 0.6f;
|
||||||
|
float buttonTop = rowStartCursor.Y + (rowHeight - pauseClusterHeight) / 2f;
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(new Vector2(rowStartCursor.X + padding.X, iconTop));
|
||||||
|
DrawLeftSide(iconTop, iconTop);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
ImGui.SetCursorPosY(textTop);
|
||||||
var posX = ImGui.GetCursorPosX();
|
var posX = ImGui.GetCursorPosX();
|
||||||
var rightSide = DrawRightSide(textPosY, originalY);
|
var rightSide = DrawRightSide(buttonTop, buttonTop);
|
||||||
DrawName(originalY, posX, rightSide);
|
DrawName(textTop + padding.Y * 0.15f, posX, rightSide);
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(new Vector2(rowStartCursor.X, rowStartCursor.Y + totalHeight));
|
||||||
|
ImGui.SetCursorPosX(rowStartCursor.X);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void DrawLeftSide(float textPosY, float originalY);
|
protected abstract void DrawLeftSide(float textPosY, float originalY);
|
||||||
|
|
||||||
protected abstract float DrawRightSide(float textPosY, float originalY);
|
protected abstract float DrawRightSide(float textPosY, float originalY);
|
||||||
|
|
||||||
|
protected virtual float GetRightSideExtraWidth() => 0f;
|
||||||
|
|
||||||
private void DrawName(float originalY, float leftSide, float rightSide)
|
private void DrawName(float originalY, float leftSide, float rightSide)
|
||||||
{
|
{
|
||||||
_displayHandler.DrawPairText(_id, _pair, leftSide, originalY, () => rightSide - leftSide);
|
_displayHandler.DrawPairText(_id, _pair, leftSide, originalY, () => rightSide - leftSide);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,28 @@ public class DrawUserPair : DrawPairBase
|
|||||||
public bool IsVisible => _pair.IsVisible;
|
public bool IsVisible => _pair.IsVisible;
|
||||||
public UserPairDto UserPair => _pair.UserPair!;
|
public UserPairDto UserPair => _pair.UserPair!;
|
||||||
|
|
||||||
|
protected override float GetRightSideExtraWidth()
|
||||||
|
{
|
||||||
|
float width = 0f;
|
||||||
|
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||||
|
|
||||||
|
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
|
||||||
|
var individualAnimDisabled = (_pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
|
||||||
|
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
|
||||||
|
|
||||||
|
if (individualSoundsDisabled || individualAnimDisabled || individualVFXDisabled)
|
||||||
|
{
|
||||||
|
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.ExclamationTriangle).X + spacingX * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData))
|
||||||
|
{
|
||||||
|
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X + spacingX * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void DrawLeftSide(float textPosY, float originalY)
|
protected override void DrawLeftSide(float textPosY, float originalY)
|
||||||
{
|
{
|
||||||
var online = _pair.IsOnline;
|
var online = _pair.IsOnline;
|
||||||
@@ -110,7 +132,8 @@ public class DrawUserPair : DrawPairBase
|
|||||||
var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
||||||
var entryUID = _pair.UserData.AliasOrUID;
|
var entryUID = _pair.UserData.AliasOrUID;
|
||||||
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||||
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
|
var edgePadding = UiSharedService.GetCardContentPaddingX() + 6f * ImGuiHelpers.GlobalScale;
|
||||||
|
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - edgePadding;
|
||||||
var rightSidePos = windowEndX - barButtonSize.X;
|
var rightSidePos = windowEndX - barButtonSize.X;
|
||||||
|
|
||||||
// Flyout Menu
|
// Flyout Menu
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ internal sealed class GroupPanel
|
|||||||
private readonly CompactUi _mainUi;
|
private readonly CompactUi _mainUi;
|
||||||
private readonly PairManager _pairManager;
|
private readonly PairManager _pairManager;
|
||||||
private readonly ChatService _chatService;
|
private readonly ChatService _chatService;
|
||||||
private readonly MareConfigService _mareConfig;
|
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly CharaDataManager _charaDataManager;
|
private readonly CharaDataManager _charaDataManager;
|
||||||
private readonly AutoDetectRequestService _autoDetectRequestService;
|
private readonly AutoDetectRequestService _autoDetectRequestService;
|
||||||
@@ -75,7 +74,7 @@ internal sealed class GroupPanel
|
|||||||
private string _syncShellToJoin = string.Empty;
|
private string _syncShellToJoin = string.Empty;
|
||||||
|
|
||||||
public GroupPanel(CompactUi mainUi, UiSharedService uiShared, PairManager pairManager, ChatService chatServivce,
|
public GroupPanel(CompactUi mainUi, UiSharedService uiShared, PairManager pairManager, ChatService chatServivce,
|
||||||
UidDisplayHandler uidDisplayHandler, MareConfigService mareConfig, ServerConfigurationManager serverConfigurationManager,
|
UidDisplayHandler uidDisplayHandler, ServerConfigurationManager serverConfigurationManager,
|
||||||
CharaDataManager charaDataManager, AutoDetectRequestService autoDetectRequestService)
|
CharaDataManager charaDataManager, AutoDetectRequestService autoDetectRequestService)
|
||||||
{
|
{
|
||||||
_mainUi = mainUi;
|
_mainUi = mainUi;
|
||||||
@@ -83,7 +82,6 @@ internal sealed class GroupPanel
|
|||||||
_pairManager = pairManager;
|
_pairManager = pairManager;
|
||||||
_chatService = chatServivce;
|
_chatService = chatServivce;
|
||||||
_uidDisplayHandler = uidDisplayHandler;
|
_uidDisplayHandler = uidDisplayHandler;
|
||||||
_mareConfig = mareConfig;
|
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_charaDataManager = charaDataManager;
|
_charaDataManager = charaDataManager;
|
||||||
_autoDetectRequestService = autoDetectRequestService;
|
_autoDetectRequestService = autoDetectRequestService;
|
||||||
@@ -93,6 +91,7 @@ internal sealed class GroupPanel
|
|||||||
|
|
||||||
public void DrawSyncshells()
|
public void DrawSyncshells()
|
||||||
{
|
{
|
||||||
|
using var fontScale = UiSharedService.PushFontScale(UiSharedService.ContentFontScale);
|
||||||
using (ImRaii.PushId("addsyncshell")) DrawAddSyncshell();
|
using (ImRaii.PushId("addsyncshell")) DrawAddSyncshell();
|
||||||
using (ImRaii.PushId("syncshelllist")) DrawSyncshellList();
|
using (ImRaii.PushId("syncshelllist")) DrawSyncshellList();
|
||||||
_mainUi.TransferPartHeight = ImGui.GetCursorPosY();
|
_mainUi.TransferPartHeight = ImGui.GetCursorPosY();
|
||||||
@@ -313,19 +312,20 @@ internal sealed class GroupPanel
|
|||||||
int shellNumber = _serverConfigurationManager.GetShellNumberForGid(groupDto.GID);
|
int shellNumber = _serverConfigurationManager.GetShellNumberForGid(groupDto.GID);
|
||||||
|
|
||||||
var name = groupDto.Group.Alias ?? groupDto.GID;
|
var name = groupDto.Group.Alias ?? groupDto.GID;
|
||||||
if (!_expandedGroupState.TryGetValue(groupDto.GID, out bool isExpanded))
|
if (!_expandedGroupState.ContainsKey(groupDto.GID))
|
||||||
{
|
{
|
||||||
isExpanded = false;
|
_expandedGroupState[groupDto.GID] = false;
|
||||||
_expandedGroupState.Add(groupDto.GID, isExpanded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var icon = isExpanded ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
|
UiSharedService.DrawCard($"syncshell-card-{groupDto.GID}", () =>
|
||||||
_uiShared.IconText(icon);
|
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
|
||||||
{
|
{
|
||||||
_expandedGroupState[groupDto.GID] = !_expandedGroupState[groupDto.GID];
|
bool expandedState = _expandedGroupState[groupDto.GID];
|
||||||
|
UiSharedService.DrawArrowToggle(ref expandedState, $"##syncshell-toggle-{groupDto.GID}");
|
||||||
|
if (expandedState != _expandedGroupState[groupDto.GID])
|
||||||
|
{
|
||||||
|
_expandedGroupState[groupDto.GID] = expandedState;
|
||||||
}
|
}
|
||||||
ImGui.SameLine();
|
ImGui.SameLine(0f, 6f * ImGuiHelpers.GlobalScale);
|
||||||
|
|
||||||
var textIsGid = true;
|
var textIsGid = true;
|
||||||
string groupName = groupDto.GroupAliasOrGID;
|
string groupName = groupDto.GroupAliasOrGID;
|
||||||
@@ -547,7 +547,7 @@ internal sealed class GroupPanel
|
|||||||
bool hideOfflineUsers = pairsInGroup.Count > 1000;
|
bool hideOfflineUsers = pairsInGroup.Count > 1000;
|
||||||
|
|
||||||
ImGui.Indent(20);
|
ImGui.Indent(20);
|
||||||
if (_expandedGroupState[groupDto.GID])
|
if (expandedState)
|
||||||
{
|
{
|
||||||
var sortedPairs = pairsInGroup
|
var sortedPairs = pairsInGroup
|
||||||
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
|
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
|
||||||
@@ -614,6 +614,9 @@ internal sealed class GroupPanel
|
|||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
}
|
}
|
||||||
ImGui.Unindent(20);
|
ImGui.Unindent(20);
|
||||||
|
}, stretchWidth: true);
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(4f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawSyncShellButtons(GroupFullInfoDto groupDto, List<Pair> groupPairs)
|
private void DrawSyncShellButtons(GroupFullInfoDto groupDto, List<Pair> groupPairs)
|
||||||
@@ -644,7 +647,8 @@ internal sealed class GroupPanel
|
|||||||
var isOwner = string.Equals(groupDto.OwnerUID, ApiController.UID, StringComparison.Ordinal);
|
var isOwner = string.Equals(groupDto.OwnerUID, ApiController.UID, StringComparison.Ordinal);
|
||||||
|
|
||||||
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||||
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
|
var cardPaddingX = UiSharedService.GetCardContentPaddingX();
|
||||||
|
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - cardPaddingX - 6f * ImGuiHelpers.GlobalScale;
|
||||||
var pauseIcon = groupDto.GroupUserPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
var pauseIcon = groupDto.GroupUserPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||||
var pauseIconSize = _uiShared.GetIconButtonSize(pauseIcon);
|
var pauseIconSize = _uiShared.GetIconButtonSize(pauseIcon);
|
||||||
|
|
||||||
@@ -828,9 +832,22 @@ internal sealed class GroupPanel
|
|||||||
|
|
||||||
private void DrawSyncshellList()
|
private void DrawSyncshellList()
|
||||||
{
|
{
|
||||||
var ySize = _mainUi.TransferPartHeight == 0
|
float availableHeight = ImGui.GetContentRegionAvail().Y;
|
||||||
? 1
|
float ySize;
|
||||||
: (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - _mainUi.TransferPartHeight - ImGui.GetCursorPosY();
|
if (_mainUi.TransferPartHeight <= 0)
|
||||||
|
{
|
||||||
|
float reserve = ImGui.GetFrameHeightWithSpacing() * 2f;
|
||||||
|
ySize = availableHeight - reserve;
|
||||||
|
if (ySize <= 0)
|
||||||
|
{
|
||||||
|
ySize = System.Math.Max(availableHeight, 1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ySize = (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - _mainUi.TransferPartHeight - ImGui.GetCursorPosY();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.BeginChild("list", new Vector2(_mainUi.WindowContentWidth, ySize), border: false);
|
ImGui.BeginChild("list", new Vector2(_mainUi.WindowContentWidth, ySize), border: false);
|
||||||
foreach (var entry in _pairManager.GroupPairs.OrderBy(g => g.Key.Group.AliasOrGID, StringComparer.OrdinalIgnoreCase).ToList())
|
foreach (var entry in _pairManager.GroupPairs.OrderBy(g => g.Key.Group.AliasOrGID, StringComparer.OrdinalIgnoreCase).ToList())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
using MareSynchronos.API.Data.Extensions;
|
using MareSynchronos.API.Data.Extensions;
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.UI.Handlers;
|
using MareSynchronos.UI.Handlers;
|
||||||
using MareSynchronos.WebAPI;
|
using MareSynchronos.WebAPI;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace MareSynchronos.UI.Components;
|
namespace MareSynchronos.UI.Components;
|
||||||
|
|
||||||
@@ -28,7 +32,7 @@ public class PairGroupsUi
|
|||||||
_uiSharedService = uiSharedService;
|
_uiSharedService = uiSharedService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> offlineUsers) where T : DrawPairBase
|
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> offlineUsers, Action? drawVisibleExtras = null) where T : DrawPairBase
|
||||||
{
|
{
|
||||||
// Only render those tags that actually have pairs in them, otherwise
|
// Only render those tags that actually have pairs in them, otherwise
|
||||||
// we can end up with a bunch of useless pair groups
|
// we can end up with a bunch of useless pair groups
|
||||||
@@ -36,7 +40,7 @@ public class PairGroupsUi
|
|||||||
var allUsers = onlineUsers.Concat(offlineUsers).ToList();
|
var allUsers = onlineUsers.Concat(offlineUsers).ToList();
|
||||||
if (typeof(T) == typeof(DrawUserPair))
|
if (typeof(T) == typeof(DrawUserPair))
|
||||||
{
|
{
|
||||||
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>());
|
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>(), drawVisibleExtras);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,14 +48,15 @@ public class PairGroupsUi
|
|||||||
{
|
{
|
||||||
var allArePaused = availablePairsInThisTag.All(pair => pair.UserPair!.OwnPermissions.IsPaused());
|
var allArePaused = availablePairsInThisTag.All(pair => pair.UserPair!.OwnPermissions.IsPaused());
|
||||||
var pauseButton = allArePaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
var pauseButton = allArePaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||||
var flyoutMenuX = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
|
var flyoutMenuSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
||||||
var pauseButtonX = _uiSharedService.GetIconButtonSize(pauseButton).X;
|
var pauseButtonSize = _uiSharedService.GetIconButtonSize(pauseButton);
|
||||||
var windowX = ImGui.GetWindowContentRegionMin().X;
|
|
||||||
var windowWidth = UiSharedService.GetWindowContentRegionWidth();
|
|
||||||
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||||
|
var currentX = ImGui.GetCursorPosX();
|
||||||
|
var availableWidth = ImGui.GetContentRegionAvail().X;
|
||||||
|
var buttonsWidth = pauseButtonSize.X + flyoutMenuSize.X + spacingX;
|
||||||
|
var pauseStart = Math.Max(currentX, currentX + availableWidth - buttonsWidth);
|
||||||
|
|
||||||
var buttonPauseOffset = windowX + windowWidth - flyoutMenuX - spacingX - pauseButtonX;
|
ImGui.SameLine(pauseStart);
|
||||||
ImGui.SameLine(buttonPauseOffset);
|
|
||||||
if (_uiSharedService.IconButton(pauseButton))
|
if (_uiSharedService.IconButton(pauseButton))
|
||||||
{
|
{
|
||||||
if (allArePaused)
|
if (allArePaused)
|
||||||
@@ -72,8 +77,8 @@ public class PairGroupsUi
|
|||||||
UiSharedService.AttachToolTip($"Pause pairing with all pairs in {tag}");
|
UiSharedService.AttachToolTip($"Pause pairing with all pairs in {tag}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var buttonDeleteOffset = windowX + windowWidth - flyoutMenuX;
|
var menuStart = Math.Max(pauseStart + pauseButtonSize.X + spacingX, currentX);
|
||||||
ImGui.SameLine(buttonDeleteOffset);
|
ImGui.SameLine(menuStart);
|
||||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars))
|
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars))
|
||||||
{
|
{
|
||||||
ImGui.OpenPopup("Group Flyout Menu");
|
ImGui.OpenPopup("Group Flyout Menu");
|
||||||
@@ -86,7 +91,7 @@ public class PairGroupsUi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null)
|
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null, Action? drawExtraContent = null)
|
||||||
{
|
{
|
||||||
IEnumerable<DrawPairBase> usersInThisTag;
|
IEnumerable<DrawPairBase> usersInThisTag;
|
||||||
HashSet<string>? otherUidsTaggedWithTag = null;
|
HashSet<string>? otherUidsTaggedWithTag = null;
|
||||||
@@ -108,26 +113,25 @@ public class PairGroupsUi
|
|||||||
|
|
||||||
if (isSpecialTag && !usersInThisTag.Any()) return;
|
if (isSpecialTag && !usersInThisTag.Any()) return;
|
||||||
|
|
||||||
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), otherUidsTaggedWithTag?.Count);
|
UiSharedService.DrawCard($"pair-group-{tag}", () =>
|
||||||
if (!isSpecialTag)
|
|
||||||
{
|
{
|
||||||
using (ImRaii.PushId($"group-{tag}-buttons")) DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList());
|
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), otherUidsTaggedWithTag?.Count);
|
||||||
}
|
if (!isSpecialTag)
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!_tagHandler.IsTagOpen(tag))
|
|
||||||
{
|
{
|
||||||
var size = ImGui.CalcTextSize("").Y + ImGui.GetStyle().FramePadding.Y * 2f;
|
using (ImRaii.PushId($"group-{tag}-buttons")) DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList());
|
||||||
ImGui.SameLine();
|
|
||||||
ImGui.Dummy(new(size, size));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!_tagHandler.IsTagOpen(tag)) return;
|
if (!_tagHandler.IsTagOpen(tag)) return;
|
||||||
|
|
||||||
ImGui.Indent(20);
|
ImGuiHelpers.ScaledDummy(4f);
|
||||||
DrawPairs(tag, usersInThisTag);
|
var indent = 18f * ImGuiHelpers.GlobalScale;
|
||||||
ImGui.Unindent(20);
|
ImGui.Indent(indent);
|
||||||
|
DrawPairs(tag, usersInThisTag);
|
||||||
|
drawExtraContent?.Invoke();
|
||||||
|
ImGui.Unindent(indent);
|
||||||
|
}, stretchWidth: true);
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(4f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawGroupMenu(string tag)
|
private void DrawGroupMenu(string tag)
|
||||||
@@ -157,17 +161,21 @@ public class PairGroupsUi
|
|||||||
};
|
};
|
||||||
|
|
||||||
string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{total} Pairs)" : $"{displayedName} ({online} Pairs)";
|
string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{total} Pairs)" : $"{displayedName} ({online} Pairs)";
|
||||||
var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
|
bool isOpen = _tagHandler.IsTagOpen(tag);
|
||||||
_uiSharedService.IconText(icon);
|
bool previousState = isOpen;
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
UiSharedService.DrawArrowToggle(ref isOpen, $"##group-toggle-{tag}");
|
||||||
|
if (isOpen != previousState)
|
||||||
{
|
{
|
||||||
ToggleTagOpen(tag);
|
_tagHandler.SetTagOpen(tag, isOpen);
|
||||||
}
|
}
|
||||||
ImGui.SameLine();
|
ImGui.SameLine(0f, 6f * ImGuiHelpers.GlobalScale);
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted(resultFolderName);
|
ImGui.TextUnformatted(resultFolderName);
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||||
{
|
{
|
||||||
ToggleTagOpen(tag);
|
bool newState = !_tagHandler.IsTagOpen(tag);
|
||||||
|
_tagHandler.SetTagOpen(tag, newState);
|
||||||
|
isOpen = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSpecialTag && ImGui.IsItemHovered())
|
if (!isSpecialTag && ImGui.IsItemHovered())
|
||||||
@@ -186,15 +194,11 @@ public class PairGroupsUi
|
|||||||
{
|
{
|
||||||
// These are all the OtherUIDs that are tagged with this tag
|
// These are all the OtherUIDs that are tagged with this tag
|
||||||
_uidDisplayHandler.RenderPairList(availablePairsInThisCategory);
|
_uidDisplayHandler.RenderPairList(availablePairsInThisCategory);
|
||||||
ImGui.Separator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> offlineUsers)
|
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> offlineUsers, Action? drawVisibleExtras)
|
||||||
{
|
{
|
||||||
if (_mareConfig.Current.ShowVisibleUsersSeparately)
|
// Visible section intentionally omitted for Individual Pairs view.
|
||||||
{
|
|
||||||
using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers);
|
|
||||||
}
|
|
||||||
foreach (var tag in tagsWithPairsInThem)
|
foreach (var tag in tagsWithPairsInThem)
|
||||||
{
|
{
|
||||||
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
||||||
@@ -242,9 +246,4 @@ public class PairGroupsUi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleTagOpen(string tag)
|
}
|
||||||
{
|
|
||||||
bool open = !_tagHandler.IsTagOpen(tag);
|
|
||||||
_tagHandler.SetTagOpen(tag, open);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using MareSynchronos.Services.Mediator;
|
|||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace MareSynchronos.UI;
|
namespace MareSynchronos.UI;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private readonly Dictionary<string, string[]> _texturesToConvert = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, string[]> _texturesToConvert = new(StringComparer.Ordinal);
|
||||||
private Dictionary<ObjectKind, Dictionary<string, CharacterAnalyzer.FileDataEntry>>? _cachedAnalysis;
|
private Dictionary<ObjectKind, Dictionary<string, CharacterAnalyzer.FileDataEntry>>? _cachedAnalysis;
|
||||||
private CancellationTokenSource _conversionCancellationTokenSource = new();
|
private CancellationTokenSource? _conversionCancellationTokenSource = new();
|
||||||
private string _conversionCurrentFileName = string.Empty;
|
private string _conversionCurrentFileName = string.Empty;
|
||||||
private int _conversionCurrentFileProgress = 0;
|
private int _conversionCurrentFileProgress = 0;
|
||||||
private Task? _conversionTask;
|
private Task? _conversionTask;
|
||||||
@@ -74,7 +75,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
UiSharedService.TextWrapped("Current file: " + _conversionCurrentFileName);
|
UiSharedService.TextWrapped("Current file: " + _conversionCurrentFileName);
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion"))
|
||||||
{
|
{
|
||||||
_conversionCancellationTokenSource.Cancel();
|
TryCancel(_conversionCancellationTokenSource);
|
||||||
}
|
}
|
||||||
UiSharedService.SetScaledWindowSize(500);
|
UiSharedService.SetScaledWindowSize(500);
|
||||||
ImGui.EndPopup();
|
ImGui.EndPopup();
|
||||||
@@ -294,8 +295,8 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
, ImGuiColors.DalamudYellow);
|
, ImGuiColors.DalamudYellow);
|
||||||
if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start conversion of " + _texturesToConvert.Count + " texture(s)"))
|
if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start conversion of " + _texturesToConvert.Count + " texture(s)"))
|
||||||
{
|
{
|
||||||
_conversionCancellationTokenSource = _conversionCancellationTokenSource.CancelRecreate();
|
var conversionCts = EnsureFreshCts(ref _conversionCancellationTokenSource);
|
||||||
_conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, _conversionCancellationTokenSource.Token);
|
_conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, conversionCts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,8 +355,13 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref _conversionCancellationTokenSource);
|
||||||
|
_conversionProgress.ProgressChanged -= ConversionProgress_ProgressChanged;
|
||||||
|
}
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
_conversionProgress.ProgressChanged -= ConversionProgress_ProgressChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConversionProgress_ProgressChanged(object? sender, (string, int) e)
|
private void ConversionProgress_ProgressChanged(object? sender, (string, int) e)
|
||||||
@@ -489,4 +495,31 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static CancellationTokenSource EnsureFreshCts(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
CancelAndDispose(ref cts);
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
TryCancel(cts);
|
||||||
|
cts.Dispose();
|
||||||
|
cts = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TryCancel(CancellationTokenSource? cts)
|
||||||
|
{
|
||||||
|
if (cts == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
private readonly FileDialogManager _fileDialogManager;
|
private readonly FileDialogManager _fileDialogManager;
|
||||||
private readonly MareProfileManager _mareProfileManager;
|
private readonly MareProfileManager _mareProfileManager;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
|
||||||
private bool _adjustedForScollBarsLocalProfile = false;
|
private bool _adjustedForScollBarsLocalProfile = false;
|
||||||
private bool _adjustedForScollBarsOnlineProfile = false;
|
private bool _adjustedForScollBarsOnlineProfile = false;
|
||||||
private string _descriptionText = string.Empty;
|
private string _descriptionText = string.Empty;
|
||||||
@@ -34,7 +33,6 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
public EditProfileUi(ILogger<EditProfileUi> logger, MareMediator mediator,
|
public EditProfileUi(ILogger<EditProfileUi> logger, MareMediator mediator,
|
||||||
ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager,
|
ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager,
|
||||||
ServerConfigurationManager serverConfigurationManager,
|
|
||||||
MareProfileManager mareProfileManager, PerformanceCollectorService performanceCollectorService)
|
MareProfileManager mareProfileManager, PerformanceCollectorService performanceCollectorService)
|
||||||
: base(logger, mediator, "Umbra Edit Profile###UmbraSyncEditProfileUI", performanceCollectorService)
|
: base(logger, mediator, "Umbra Edit Profile###UmbraSyncEditProfileUI", performanceCollectorService)
|
||||||
{
|
{
|
||||||
@@ -47,7 +45,6 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
_apiController = apiController;
|
_apiController = apiController;
|
||||||
_uiSharedService = uiSharedService;
|
_uiSharedService = uiSharedService;
|
||||||
_fileDialogManager = fileDialogManager;
|
_fileDialogManager = fileDialogManager;
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
|
||||||
_mareProfileManager = mareProfileManager;
|
_mareProfileManager = mareProfileManager;
|
||||||
|
|
||||||
Mediator.Subscribe<GposeStartMessage>(this, (_) => { _wasOpen = IsOpen; IsOpen = false; });
|
Mediator.Subscribe<GposeStartMessage>(this, (_) => { _wasOpen = IsOpen; IsOpen = false; });
|
||||||
@@ -64,6 +61,16 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override void DrawInternal()
|
protected override void DrawInternal()
|
||||||
|
{
|
||||||
|
DrawProfileContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawInline()
|
||||||
|
{
|
||||||
|
DrawProfileContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawProfileContent()
|
||||||
{
|
{
|
||||||
_uiSharedService.BigText("Current Profile (as saved on server)");
|
_uiSharedService.BigText("Current Profile (as saved on server)");
|
||||||
ImGuiHelpers.ScaledDummy(new Vector2(0f, ImGui.GetStyle().ItemSpacing.Y / 2));
|
ImGuiHelpers.ScaledDummy(new Vector2(0f, ImGui.GetStyle().ItemSpacing.Y / 2));
|
||||||
|
|||||||
@@ -144,12 +144,12 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGui.SetWindowFontScale(1.5f);
|
UiSharedService.SetFontScale(1.5f);
|
||||||
string readThis = "MERCI DE LIRE ATTENTIVEMENT";
|
string readThis = "MERCI DE LIRE ATTENTIVEMENT";
|
||||||
Vector2 textSize = ImGui.CalcTextSize(readThis);
|
Vector2 textSize = ImGui.CalcTextSize(readThis);
|
||||||
ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2);
|
ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2);
|
||||||
UiSharedService.ColorText(readThis, UiSharedService.AccentColor);
|
UiSharedService.ColorText(readThis, UiSharedService.AccentColor);
|
||||||
ImGui.SetWindowFontScale(1.0f);
|
UiSharedService.SetFontScale(1.0f);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
UiSharedService.TextWrapped("""
|
UiSharedService.TextWrapped("""
|
||||||
Pour utiliser les services UmbraSync, vous devez être âgé de plus de 18 ans, où plus de 21 ans dans certaines juridictions.
|
Pour utiliser les services UmbraSync, vous devez être âgé de plus de 18 ans, où plus de 21 ans dans certaines juridictions.
|
||||||
|
|||||||
@@ -16,25 +16,22 @@ namespace MareSynchronos.UI;
|
|||||||
public class PopoutProfileUi : WindowMediatorSubscriberBase
|
public class PopoutProfileUi : WindowMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
private readonly MareProfileManager _mareProfileManager;
|
private readonly MareProfileManager _mareProfileManager;
|
||||||
private readonly PairManager _pairManager;
|
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private Vector2 _lastMainPos = Vector2.Zero;
|
private Vector2 _lastMainPos = Vector2.Zero;
|
||||||
private Vector2 _lastMainSize = Vector2.Zero;
|
private Vector2 _lastMainSize = Vector2.Zero;
|
||||||
private byte[] _lastProfilePicture = [];
|
private byte[] _lastProfilePicture = [];
|
||||||
private byte[] _lastSupporterPicture = [];
|
|
||||||
private Pair? _pair;
|
private Pair? _pair;
|
||||||
private IDalamudTextureWrap? _supporterTextureWrap;
|
private IDalamudTextureWrap? _supporterTextureWrap;
|
||||||
private IDalamudTextureWrap? _textureWrap;
|
private IDalamudTextureWrap? _textureWrap;
|
||||||
|
|
||||||
public PopoutProfileUi(ILogger<PopoutProfileUi> logger, MareMediator mediator, UiSharedService uiSharedService,
|
public PopoutProfileUi(ILogger<PopoutProfileUi> logger, MareMediator mediator, UiSharedService uiSharedService,
|
||||||
ServerConfigurationManager serverManager, MareConfigService mareConfigService,
|
ServerConfigurationManager serverManager, MareConfigService mareConfigService,
|
||||||
MareProfileManager mareProfileManager, PairManager pairManager, PerformanceCollectorService performanceCollectorService) : base(logger, mediator, "###UmbraSyncPopoutProfileUI", performanceCollectorService)
|
MareProfileManager mareProfileManager, PerformanceCollectorService performanceCollectorService) : base(logger, mediator, "###UmbraSyncPopoutProfileUI", performanceCollectorService)
|
||||||
{
|
{
|
||||||
_uiSharedService = uiSharedService;
|
_uiSharedService = uiSharedService;
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_mareProfileManager = mareProfileManager;
|
_mareProfileManager = mareProfileManager;
|
||||||
_pairManager = pairManager;
|
|
||||||
Flags = ImGuiWindowFlags.NoDecoration;
|
Flags = ImGuiWindowFlags.NoDecoration;
|
||||||
|
|
||||||
Mediator.Subscribe<ProfilePopoutToggle>(this, (msg) =>
|
Mediator.Subscribe<ProfilePopoutToggle>(this, (msg) =>
|
||||||
@@ -42,7 +39,6 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase
|
|||||||
IsOpen = msg.Pair != null;
|
IsOpen = msg.Pair != null;
|
||||||
_pair = msg.Pair;
|
_pair = msg.Pair;
|
||||||
_lastProfilePicture = [];
|
_lastProfilePicture = [];
|
||||||
_lastSupporterPicture = [];
|
|
||||||
_textureWrap?.Dispose();
|
_textureWrap?.Dispose();
|
||||||
_textureWrap = null;
|
_textureWrap = null;
|
||||||
_supporterTextureWrap?.Dispose();
|
_supporterTextureWrap?.Dispose();
|
||||||
@@ -182,4 +178,4 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase
|
|||||||
_logger.LogWarning(ex, "Error during draw tooltip");
|
_logger.LogWarning(ex, "Error during draw tooltip");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,11 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
DrawSettingsContent();
|
DrawSettingsContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DrawInline()
|
||||||
|
{
|
||||||
|
DrawSettingsContent();
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnClose()
|
public override void OnClose()
|
||||||
{
|
{
|
||||||
_uiShared.EditTrackerPosition = false;
|
_uiShared.EditTrackerPosition = false;
|
||||||
@@ -529,9 +534,9 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
}, globalChatTypeIdx);
|
}, globalChatTypeIdx);
|
||||||
_uiShared.DrawHelpText("FFXIV chat channel to output chat messages on.");
|
_uiShared.DrawHelpText("FFXIV chat channel to output chat messages on.");
|
||||||
|
|
||||||
ImGui.SetWindowFontScale(0.6f);
|
UiSharedService.SetFontScale(0.6f);
|
||||||
_uiShared.BigText("\"Chat 2\" Plugin Integration");
|
_uiShared.BigText("\"Chat 2\" Plugin Integration");
|
||||||
ImGui.SetWindowFontScale(1.0f);
|
UiSharedService.SetFontScale(1.0f);
|
||||||
|
|
||||||
var extraChatTags = _configService.Current.ExtraChatTags;
|
var extraChatTags = _configService.Current.ExtraChatTags;
|
||||||
if (ImGui.Checkbox("Tag messages as ExtraChat", ref extraChatTags))
|
if (ImGui.Checkbox("Tag messages as ExtraChat", ref extraChatTags))
|
||||||
@@ -572,9 +577,9 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
if (shellEnabled)
|
if (shellEnabled)
|
||||||
shellName = $"[{shellNumber}] {shellName}";
|
shellName = $"[{shellNumber}] {shellName}";
|
||||||
|
|
||||||
ImGui.SetWindowFontScale(0.6f);
|
UiSharedService.SetFontScale(0.6f);
|
||||||
_uiShared.BigText(shellName);
|
_uiShared.BigText(shellName);
|
||||||
ImGui.SetWindowFontScale(1.0f);
|
UiSharedService.SetFontScale(1.0f);
|
||||||
|
|
||||||
using var pushIndent = ImRaii.PushIndent();
|
using var pushIndent = ImRaii.PushIndent();
|
||||||
|
|
||||||
@@ -1002,7 +1007,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
_lastTab = "General";
|
_lastTab = "General";
|
||||||
|
|
||||||
_uiShared.BigText("Notes");
|
_uiShared.BigText("Notes");
|
||||||
if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Export all your user notes to clipboard"))
|
if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Export all your user notes to clipboard"))
|
||||||
{
|
{
|
||||||
ImGui.SetClipboardText(UiSharedService.GetNotes(_pairManager.DirectPairs.UnionBy(_pairManager.GroupPairs.SelectMany(p => p.Value), p => p.UserData, UserDataComparer.Instance).ToList()));
|
ImGui.SetClipboardText(UiSharedService.GetNotes(_pairManager.DirectPairs.UnionBy(_pairManager.GroupPairs.SelectMany(p => p.Value), p => p.UserData, UserDataComparer.Instance).ToList()));
|
||||||
@@ -1328,6 +1333,14 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
_uiShared.BigText("Global Configuration");
|
_uiShared.BigText("Global Configuration");
|
||||||
|
|
||||||
|
bool showSelfAnalysisWarnings = _playerPerformanceConfigService.Current.ShowSelfAnalysisWarnings;
|
||||||
|
if (ImGui.Checkbox("Display self-analysis warnings", ref showSelfAnalysisWarnings))
|
||||||
|
{
|
||||||
|
_playerPerformanceConfigService.Current.ShowSelfAnalysisWarnings = showSelfAnalysisWarnings;
|
||||||
|
_playerPerformanceConfigService.Save();
|
||||||
|
}
|
||||||
|
_uiShared.DrawHelpText("Disable to suppress UmbraSync chat warnings when your character exceeds the self-analysis thresholds.");
|
||||||
|
|
||||||
bool alwaysShrinkTextures = _playerPerformanceConfigService.Current.TextureShrinkMode == TextureShrinkMode.Always;
|
bool alwaysShrinkTextures = _playerPerformanceConfigService.Current.TextureShrinkMode == TextureShrinkMode.Always;
|
||||||
bool deleteOriginalTextures = _playerPerformanceConfigService.Current.TextureShrinkDeleteOriginal;
|
bool deleteOriginalTextures = _playerPerformanceConfigService.Current.TextureShrinkDeleteOriginal;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ namespace MareSynchronos.UI;
|
|||||||
public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
private readonly MareProfileManager _mareProfileManager;
|
private readonly MareProfileManager _mareProfileManager;
|
||||||
private readonly PairManager _pairManager;
|
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private bool _adjustedForScrollBars = false;
|
private bool _adjustedForScrollBars = false;
|
||||||
@@ -24,7 +23,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|||||||
private IDalamudTextureWrap? _textureWrap;
|
private IDalamudTextureWrap? _textureWrap;
|
||||||
|
|
||||||
public StandaloneProfileUi(ILogger<StandaloneProfileUi> logger, MareMediator mediator, UiSharedService uiBuilder,
|
public StandaloneProfileUi(ILogger<StandaloneProfileUi> logger, MareMediator mediator, UiSharedService uiBuilder,
|
||||||
ServerConfigurationManager serverManager, MareProfileManager mareProfileManager, PairManager pairManager, Pair pair,
|
ServerConfigurationManager serverManager, MareProfileManager mareProfileManager, Pair pair,
|
||||||
PerformanceCollectorService performanceCollector)
|
PerformanceCollectorService performanceCollector)
|
||||||
: base(logger, mediator, "Profile of " + pair.UserData.AliasOrUID + "##UmbraSyncStandaloneProfileUI" + pair.UserData.AliasOrUID, performanceCollector)
|
: base(logger, mediator, "Profile of " + pair.UserData.AliasOrUID + "##UmbraSyncStandaloneProfileUI" + pair.UserData.AliasOrUID, performanceCollector)
|
||||||
{
|
{
|
||||||
@@ -32,7 +31,6 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_mareProfileManager = mareProfileManager;
|
_mareProfileManager = mareProfileManager;
|
||||||
Pair = pair;
|
Pair = pair;
|
||||||
_pairManager = pairManager;
|
|
||||||
Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize;
|
Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize;
|
||||||
|
|
||||||
var spacing = ImGui.GetStyle().ItemSpacing;
|
var spacing = ImGui.GetStyle().ItemSpacing;
|
||||||
@@ -164,4 +162,4 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Mediator.Publish(new RemoveWindowMessage(this));
|
Mediator.Publish(new RemoveWindowMessage(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
private static readonly TimeSpan TypingDisplayDelay = TimeSpan.FromMilliseconds(500);
|
private static readonly TimeSpan TypingDisplayDelay = TimeSpan.FromMilliseconds(500);
|
||||||
private static readonly TimeSpan TypingDisplayFade = TypingDisplayTime;
|
private static readonly TimeSpan TypingDisplayFade = TypingDisplayTime;
|
||||||
|
|
||||||
private readonly ILogger<TypingIndicatorOverlay> _logger;
|
private readonly ILogger<TypingIndicatorOverlay> _typedLogger;
|
||||||
private readonly MareConfigService _configService;
|
private readonly MareConfigService _configService;
|
||||||
private readonly IGameGui _gameGui;
|
private readonly IGameGui _gameGui;
|
||||||
private readonly ITextureProvider _textureProvider;
|
private readonly ITextureProvider _textureProvider;
|
||||||
@@ -47,7 +47,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
TypingIndicatorStateService typingStateService, ApiController apiController)
|
TypingIndicatorStateService typingStateService, ApiController apiController)
|
||||||
: base(logger, mediator, nameof(TypingIndicatorOverlay), performanceCollectorService)
|
: base(logger, mediator, nameof(TypingIndicatorOverlay), performanceCollectorService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_typedLogger = logger;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_gameGui = gameGui;
|
_gameGui = gameGui;
|
||||||
_textureProvider = textureProvider;
|
_textureProvider = textureProvider;
|
||||||
@@ -216,7 +216,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
if (objectId != uint.MaxValue && objectId != 0 && TryDrawNameplateBubble(drawList, iconWrap, objectId))
|
if (objectId != uint.MaxValue && objectId != 0 && TryDrawNameplateBubble(drawList, iconWrap, objectId))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TypingIndicator: drew nameplate bubble for {uid} (objectId={objectId})", uid, objectId);
|
_typedLogger.LogTrace("TypingIndicator: drew nameplate bubble for {uid} (objectId={objectId})", uid, objectId);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,20 +228,20 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
if (pair == null)
|
if (pair == null)
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TypingIndicator: no pair found for {uid}, attempting fallback", uid);
|
_typedLogger.LogTrace("TypingIndicator: no pair found for {uid}, attempting fallback", uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogTrace("TypingIndicator: fallback draw for {uid} (objectId={objectId}, name={name}, ident={ident})",
|
_typedLogger.LogTrace("TypingIndicator: fallback draw for {uid} (objectId={objectId}, name={name}, ident={ident})",
|
||||||
uid, objectId, pairName, pairIdent);
|
uid, objectId, pairName, pairIdent);
|
||||||
|
|
||||||
if (hasWorldPosition)
|
if (hasWorldPosition)
|
||||||
{
|
{
|
||||||
DrawWorldFallbackIcon(drawList, iconWrap, worldPos);
|
DrawWorldFallbackIcon(drawList, iconWrap, worldPos);
|
||||||
_logger.LogTrace("TypingIndicator: fallback world draw for {uid} at {pos}", uid, worldPos);
|
_typedLogger.LogTrace("TypingIndicator: fallback world draw for {uid} at {pos}", uid, worldPos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TypingIndicator: could not resolve position for {uid}", uid);
|
_typedLogger.LogTrace("TypingIndicator: could not resolve position for {uid}", uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +393,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
if (TryGetWorldPosition(objectId, out position))
|
if (TryGetWorldPosition(objectId, out position))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TypingIndicator: resolved by objectId {objectId}", objectId);
|
_typedLogger.LogTrace("TypingIndicator: resolved by objectId {objectId}", objectId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,7 +402,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
var name = pair.PlayerName;
|
var name = pair.PlayerName;
|
||||||
if (!string.IsNullOrEmpty(name) && TryGetWorldPositionByName(name!, out position))
|
if (!string.IsNullOrEmpty(name) && TryGetWorldPositionByName(name!, out position))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TypingIndicator: resolved by pair name {name}", name);
|
_typedLogger.LogTrace("TypingIndicator: resolved by pair name {name}", name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +412,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
var cached = _dalamudUtil.FindPlayerByNameHash(ident);
|
var cached = _dalamudUtil.FindPlayerByNameHash(ident);
|
||||||
if (!string.IsNullOrEmpty(cached.Name) && TryGetWorldPositionByName(cached.Name, out position))
|
if (!string.IsNullOrEmpty(cached.Name) && TryGetWorldPositionByName(cached.Name, out position))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TypingIndicator: resolved by cached name {name}", cached.Name);
|
_typedLogger.LogTrace("TypingIndicator: resolved by cached name {name}", cached.Name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +422,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
if (objRef != null)
|
if (objRef != null)
|
||||||
{
|
{
|
||||||
position = objRef.Position;
|
position = objRef.Position;
|
||||||
_logger.LogTrace("TypingIndicator: resolved by cached address {addr}", cached.Address);
|
_typedLogger.LogTrace("TypingIndicator: resolved by cached address {addr}", cached.Address);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,7 +432,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase
|
|||||||
var alias = userData.AliasOrUID;
|
var alias = userData.AliasOrUID;
|
||||||
if (!string.IsNullOrEmpty(alias) && TryGetWorldPositionByName(alias, out position))
|
if (!string.IsNullOrEmpty(alias) && TryGetWorldPositionByName(alias, out position))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TypingIndicator: resolved by user alias {alias}", alias);
|
_typedLogger.LogTrace("TypingIndicator: resolved by user alias {alias}", alias);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ using MareSynchronos.Services.Mediator;
|
|||||||
using MareSynchronos.Services.ServerConfiguration;
|
using MareSynchronos.Services.ServerConfiguration;
|
||||||
using MareSynchronos.WebAPI;
|
using MareSynchronos.WebAPI;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -36,6 +38,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
ImGuiWindowFlags.NoScrollbar |
|
ImGuiWindowFlags.NoScrollbar |
|
||||||
ImGuiWindowFlags.NoScrollWithMouse;
|
ImGuiWindowFlags.NoScrollWithMouse;
|
||||||
|
|
||||||
|
public const float ContentFontScale = 0.92f;
|
||||||
|
|
||||||
public static Vector4 AccentColor { get; set; } = ImGuiColors.DalamudViolet;
|
public static Vector4 AccentColor { get; set; } = ImGuiColors.DalamudViolet;
|
||||||
public static Vector4 AccentHoverColor { get; set; } = new Vector4(0x3A / 255f, 0x15 / 255f, 0x50 / 255f, 1f);
|
public static Vector4 AccentHoverColor { get; set; } = new Vector4(0x3A / 255f, 0x15 / 255f, 0x50 / 255f, 1f);
|
||||||
public static Vector4 AccentActiveColor { get; set; } = AccentHoverColor;
|
public static Vector4 AccentActiveColor { get; set; } = AccentHoverColor;
|
||||||
@@ -59,6 +63,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
private readonly Dictionary<string, object> _selectedComboItems = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, object> _selectedComboItems = new(StringComparer.Ordinal);
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
private bool _cacheDirectoryHasOtherFilesThanCache = false;
|
private bool _cacheDirectoryHasOtherFilesThanCache = false;
|
||||||
|
private static readonly Stack<float> _fontScaleStack = new();
|
||||||
|
private static float _currentWindowFontScale = 1f;
|
||||||
|
|
||||||
private bool _cacheDirectoryIsValidPath = true;
|
private bool _cacheDirectoryIsValidPath = true;
|
||||||
|
|
||||||
@@ -117,7 +123,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
e.OnPreBuild(tk => tk.AddDalamudAssetFont(Dalamud.DalamudAsset.NotoSansJpMedium, new()
|
e.OnPreBuild(tk => tk.AddDalamudAssetFont(Dalamud.DalamudAsset.NotoSansJpMedium, new()
|
||||||
{
|
{
|
||||||
SizePx = 35,
|
SizePx = 27,
|
||||||
GlyphRanges = [0x20, 0x7E, 0]
|
GlyphRanges = [0x20, 0x7E, 0]
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@@ -216,7 +222,38 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
public static bool CtrlPressed() => (GetKeyState(0xA2) & 0x8000) != 0 || (GetKeyState(0xA3) & 0x8000) != 0;
|
public static bool CtrlPressed() => (GetKeyState(0xA2) & 0x8000) != 0 || (GetKeyState(0xA3) & 0x8000) != 0;
|
||||||
|
|
||||||
public static void DrawGrouped(Action imguiDrawAction, float rounding = 5f, float? expectedWidth = null)
|
public static IDisposable PushFontScale(float scale)
|
||||||
|
{
|
||||||
|
var previous = _currentWindowFontScale;
|
||||||
|
_fontScaleStack.Push(previous);
|
||||||
|
if (Math.Abs(previous - scale) > float.Epsilon)
|
||||||
|
{
|
||||||
|
SetFontScale(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FontScaleScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FontScaleScope : IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_fontScaleStack.Count == 0) return;
|
||||||
|
var previous = _fontScaleStack.Pop();
|
||||||
|
if (Math.Abs(previous - _currentWindowFontScale) > float.Epsilon)
|
||||||
|
{
|
||||||
|
SetFontScale(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetFontScale(float scale)
|
||||||
|
{
|
||||||
|
ImGui.SetWindowFontScale(scale);
|
||||||
|
_currentWindowFontScale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawGrouped(Action imguiDrawAction, float rounding = 5f, float? expectedWidth = null, bool drawBorder = true)
|
||||||
{
|
{
|
||||||
var cursorPos = ImGui.GetCursorPos();
|
var cursorPos = ImGui.GetCursorPos();
|
||||||
using (ImRaii.Group())
|
using (ImRaii.Group())
|
||||||
@@ -230,10 +267,128 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
imguiDrawAction.Invoke();
|
imguiDrawAction.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.GetWindowDrawList().AddRect(
|
if (drawBorder)
|
||||||
ImGui.GetItemRectMin() - ImGui.GetStyle().ItemInnerSpacing,
|
{
|
||||||
ImGui.GetItemRectMax() + ImGui.GetStyle().ItemInnerSpacing,
|
ImGui.GetWindowDrawList().AddRect(
|
||||||
Color(ImGuiColors.DalamudGrey2), rounding);
|
ImGui.GetItemRectMin() - ImGui.GetStyle().ItemInnerSpacing,
|
||||||
|
ImGui.GetItemRectMax() + ImGui.GetStyle().ItemInnerSpacing,
|
||||||
|
Color(ImGuiColors.DalamudGrey2), rounding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawCard(string id, Action draw, Vector2? padding = null, Vector4? background = null,
|
||||||
|
Vector4? border = null, float? rounding = null, bool stretchWidth = false)
|
||||||
|
{
|
||||||
|
var style = ImGui.GetStyle();
|
||||||
|
var padBase = style.FramePadding;
|
||||||
|
var pad = padding ?? new Vector2(
|
||||||
|
padBase.X + 4f * ImGuiHelpers.GlobalScale,
|
||||||
|
padBase.Y + 3f * ImGuiHelpers.GlobalScale);
|
||||||
|
var cardBg = background ?? new Vector4(0.08f, 0.08f, 0.10f, 0.94f);
|
||||||
|
var cardBorder = border ?? new Vector4(0f, 0f, 0f, 0.85f);
|
||||||
|
float cardRounding = rounding ?? Math.Max(style.FrameRounding, 8f * ImGuiHelpers.GlobalScale);
|
||||||
|
float borderThickness = Math.Max(1f, Math.Max(style.FrameBorderSize, 1f) * ImGuiHelpers.GlobalScale);
|
||||||
|
float borderInset = borderThickness;
|
||||||
|
|
||||||
|
var originalCursor = ImGui.GetCursorPos();
|
||||||
|
if (stretchWidth)
|
||||||
|
{
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetWindowContentRegionMin().X);
|
||||||
|
}
|
||||||
|
|
||||||
|
var startCursor = ImGui.GetCursorPos();
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
drawList.ChannelsSplit(2);
|
||||||
|
drawList.ChannelsSetCurrent(1);
|
||||||
|
|
||||||
|
ImGui.PushID(id);
|
||||||
|
ImGui.SetCursorPos(new Vector2(startCursor.X + pad.X, startCursor.Y + pad.Y));
|
||||||
|
ImGui.BeginGroup();
|
||||||
|
draw();
|
||||||
|
ImGui.EndGroup();
|
||||||
|
ImGui.PopID();
|
||||||
|
|
||||||
|
var contentMin = ImGui.GetItemRectMin();
|
||||||
|
var contentMax = ImGui.GetItemRectMax();
|
||||||
|
var cardMin = contentMin - pad;
|
||||||
|
var cardMax = contentMax + pad;
|
||||||
|
var outerMin = cardMin;
|
||||||
|
var outerMax = cardMax;
|
||||||
|
|
||||||
|
if (stretchWidth)
|
||||||
|
{
|
||||||
|
var windowPos = ImGui.GetWindowPos();
|
||||||
|
var regionMin = ImGui.GetWindowContentRegionMin();
|
||||||
|
var regionMax = ImGui.GetWindowContentRegionMax();
|
||||||
|
var scrollX = ImGui.GetScrollX();
|
||||||
|
cardMin.X = windowPos.X + regionMin.X + scrollX;
|
||||||
|
cardMax.X = windowPos.X + regionMax.X + scrollX;
|
||||||
|
outerMin.X = cardMin.X;
|
||||||
|
outerMax.X = cardMax.X;
|
||||||
|
startCursor.X = ImGui.GetWindowContentRegionMin().X;
|
||||||
|
}
|
||||||
|
|
||||||
|
var drawMin = new Vector2(cardMin.X + borderInset, cardMin.Y + borderInset);
|
||||||
|
var drawMax = new Vector2(cardMax.X - borderInset, cardMax.Y - borderInset);
|
||||||
|
var clipMin = drawList.GetClipRectMin();
|
||||||
|
var clipMax = drawList.GetClipRectMax();
|
||||||
|
var clipInset = new Vector2(borderThickness * 0.5f + 0.5f, borderThickness * 0.5f + 0.5f);
|
||||||
|
drawMin = Vector2.Max(drawMin, clipMin + clipInset);
|
||||||
|
drawMax = Vector2.Min(drawMax, clipMax - clipInset);
|
||||||
|
if (drawMax.X <= drawMin.X)
|
||||||
|
{
|
||||||
|
drawMax.X = drawMin.X + borderThickness;
|
||||||
|
}
|
||||||
|
if (drawMax.Y <= drawMin.Y)
|
||||||
|
{
|
||||||
|
drawMax.Y = drawMin.Y + borderThickness;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawList.ChannelsSetCurrent(0);
|
||||||
|
drawList.AddRectFilled(drawMin, drawMax, ImGui.ColorConvertFloat4ToU32(cardBg), cardRounding);
|
||||||
|
if (cardBorder.W > 0f && borderThickness > 0f)
|
||||||
|
{
|
||||||
|
drawList.AddRect(drawMin, drawMax, ImGui.ColorConvertFloat4ToU32(cardBorder), cardRounding, ImDrawFlags.None, borderThickness);
|
||||||
|
}
|
||||||
|
drawList.ChannelsMerge();
|
||||||
|
|
||||||
|
ImGui.SetCursorPos(startCursor);
|
||||||
|
var dummyWidth = outerMax.X - outerMin.X;
|
||||||
|
var dummyHeight = outerMax.Y - outerMin.Y;
|
||||||
|
ImGui.Dummy(new Vector2(dummyWidth, dummyHeight));
|
||||||
|
ImGui.SetCursorPos(new Vector2(startCursor.X, startCursor.Y + dummyHeight));
|
||||||
|
|
||||||
|
if (!stretchWidth)
|
||||||
|
{
|
||||||
|
ImGui.SetCursorPosX(originalCursor.X);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.SetCursorPosX(startCursor.X);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawArrowToggle(ref bool state, string id)
|
||||||
|
{
|
||||||
|
var framePadding = ImGui.GetStyle().FramePadding;
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(framePadding.X, framePadding.Y * 0.85f));
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(1f, 1f, 1f, 0.08f));
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(1f, 1f, 1f, 0.16f));
|
||||||
|
bool clicked = ImGui.ArrowButton(id, state ? ImGuiDir.Down : ImGuiDir.Right);
|
||||||
|
ImGui.PopStyleColor(3);
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
if (clicked)
|
||||||
|
{
|
||||||
|
state = !state;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetCardContentPaddingX()
|
||||||
|
{
|
||||||
|
var style = ImGui.GetStyle();
|
||||||
|
return style.FramePadding.X + 4f * ImGuiHelpers.GlobalScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DrawGroupedCenteredColorText(string text, Vector4 color, float? maxWidth = null)
|
public static void DrawGroupedCenteredColorText(string text, Vector4 color, float? maxWidth = null)
|
||||||
@@ -775,9 +930,9 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
if (intro)
|
if (intro)
|
||||||
{
|
{
|
||||||
ImGui.SetWindowFontScale(0.8f);
|
SetFontScale(0.8f);
|
||||||
BigText("Mandatory Plugins");
|
BigText("Mandatory Plugins");
|
||||||
ImGui.SetWindowFontScale(1.0f);
|
SetFontScale(1.0f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -798,9 +953,9 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
if (intro)
|
if (intro)
|
||||||
{
|
{
|
||||||
ImGui.SetWindowFontScale(0.8f);
|
SetFontScale(0.8f);
|
||||||
BigText("Optional Addons");
|
BigText("Optional Addons");
|
||||||
ImGui.SetWindowFontScale(1.0f);
|
SetFontScale(1.0f);
|
||||||
UiSharedService.TextWrapped("These addons are not required for basic operation, but without them you may not see others as intended.");
|
UiSharedService.TextWrapped("These addons are not required for basic operation, but without them you may not see others as intended.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace MareSynchronos.Utils;
|
namespace MareSynchronos.Utils;
|
||||||
|
|
||||||
public class PngHdr
|
public static class PngHdr
|
||||||
{
|
{
|
||||||
private static readonly byte[] _magicSignature = [137, 80, 78, 71, 13, 10, 26, 10];
|
private static readonly byte[] _magicSignature = [137, 80, 78, 71, 13, 10, 26, 10];
|
||||||
private static readonly byte[] _IHDR = [(byte)'I', (byte)'H', (byte)'D', (byte)'R'];
|
private static readonly byte[] _IHDR = [(byte)'I', (byte)'H', (byte)'D', (byte)'R'];
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using MareSynchronos.Services;
|
|||||||
using MareSynchronos.Services.ServerConfiguration;
|
using MareSynchronos.Services.ServerConfiguration;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using MareSynchronos.WebAPI.SignalR;
|
using MareSynchronos.WebAPI.SignalR;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -15,17 +14,15 @@ namespace MareSynchronos.WebAPI;
|
|||||||
public sealed class AccountRegistrationService : IDisposable
|
public sealed class AccountRegistrationService : IDisposable
|
||||||
{
|
{
|
||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<AccountRegistrationService> _logger;
|
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
|
|
||||||
private string GenerateSecretKey()
|
private static string GenerateSecretKey()
|
||||||
{
|
{
|
||||||
return Convert.ToHexString(SHA256.HashData(RandomNumberGenerator.GetBytes(64)));
|
return Convert.ToHexString(SHA256.HashData(RandomNumberGenerator.GetBytes(64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccountRegistrationService(ILogger<AccountRegistrationService> logger, ServerConfigurationManager serverManager)
|
public AccountRegistrationService(ServerConfigurationManager serverManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_httpClient = new(
|
_httpClient = new(
|
||||||
new HttpClientHandler
|
new HttpClientHandler
|
||||||
@@ -67,4 +64,4 @@ public sealed class AccountRegistrationService : IDisposable
|
|||||||
SecretKey = secretKey
|
SecretKey = secretKey
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,16 @@ namespace MareSynchronos.WebAPI.Files;
|
|||||||
public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
private readonly FileCacheManager _fileDbManager;
|
private readonly FileCacheManager _fileDbManager;
|
||||||
private readonly MareConfigService _mareConfigService;
|
|
||||||
private readonly FileTransferOrchestrator _orchestrator;
|
private readonly FileTransferOrchestrator _orchestrator;
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly Dictionary<string, DateTime> _verifiedUploadedHashes = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, DateTime> _verifiedUploadedHashes = new(StringComparer.Ordinal);
|
||||||
private CancellationTokenSource? _uploadCancellationTokenSource = new();
|
private CancellationTokenSource? _uploadCancellationTokenSource = new();
|
||||||
|
|
||||||
public FileUploadManager(ILogger<FileUploadManager> logger, MareMediator mediator,
|
public FileUploadManager(ILogger<FileUploadManager> logger, MareMediator mediator,
|
||||||
MareConfigService mareConfigService,
|
|
||||||
FileTransferOrchestrator orchestrator,
|
FileTransferOrchestrator orchestrator,
|
||||||
FileCacheManager fileDbManager,
|
FileCacheManager fileDbManager,
|
||||||
ServerConfigurationManager serverManager) : base(logger, mediator)
|
ServerConfigurationManager serverManager) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
_mareConfigService = mareConfigService;
|
|
||||||
_orchestrator = orchestrator;
|
_orchestrator = orchestrator;
|
||||||
_fileDbManager = fileDbManager;
|
_fileDbManager = fileDbManager;
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
@@ -286,4 +283,4 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
CurrentUploads.Clear();
|
CurrentUploads.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ public class DownloadFileTransfer : FileTransfer
|
|||||||
get => Dto.Size;
|
get => Dto.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long TotalRaw => 0; // XXX
|
public long TotalRaw => Dto.Size;
|
||||||
private DownloadFileDto Dto => (DownloadFileDto)TransferDto;
|
private DownloadFileDto Dto => (DownloadFileDto)TransferDto;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ public partial class ApiController
|
|||||||
|
|
||||||
public Task Client_GposeLobbyPushWorldData(UserData userData, WorldData worldData)
|
public Task Client_GposeLobbyPushWorldData(UserData userData, WorldData worldData)
|
||||||
{
|
{
|
||||||
//Logger.LogDebug("Client_GposeLobbyPushWorldData: {dto}", userData);
|
Logger.LogDebug("Client_GposeLobbyPushWorldData: {dto}", userData);
|
||||||
ExecuteSafely(() => Mediator.Publish(new GPoseLobbyReceiveWorldData(userData, worldData)));
|
ExecuteSafely(() => Mediator.Publish(new GPoseLobbyReceiveWorldData(userData, worldData)));
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -415,4 +415,4 @@ public partial class ApiController
|
|||||||
Logger.LogCritical(ex, "Error on executing safely");
|
Logger.LogCritical(ex, "Error on executing safely");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule Penumbra.Api updated: 97fe622e4e...c23ee05c1e
Reference in New Issue
Block a user