MCDO fixes
fix ipc probably add individual syncshells and shit don't show shared data from paused people change text fix reverting Use InputText/Combo hybrids for MCDO ACLs (#81) * Use InputText/Combo hybrids for MCDO ACLs * Hybrid combo factoring, filtering, ordering, caching fix selecting latest created data on creation rename close to direct pairs add toggle to keep nearby poses active constantly fix gpose hanging fix potential cancelaltion on updateshareddata
This commit is contained in:
2
MareAPI
2
MareAPI
Submodule MareAPI updated: c8cc217d66...4d8c380dab
@@ -15,7 +15,7 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
private readonly ILogger<IpcProvider> _logger;
|
private readonly ILogger<IpcProvider> _logger;
|
||||||
private readonly IDalamudPluginInterface _pi;
|
private readonly IDalamudPluginInterface _pi;
|
||||||
private readonly MareConfigService _mareConfig;
|
private readonly MareConfigService _mareConfig;
|
||||||
private readonly DalamudUtilService _dalamudUtil;
|
private readonly CharaDataManager _charaDataManager;
|
||||||
private ICallGateProvider<string, IGameObject, bool>? _loadFileProvider;
|
private ICallGateProvider<string, IGameObject, bool>? _loadFileProvider;
|
||||||
private ICallGateProvider<string, IGameObject, Task<bool>>? _loadFileAsyncProvider;
|
private ICallGateProvider<string, IGameObject, Task<bool>>? _loadFileAsyncProvider;
|
||||||
private ICallGateProvider<List<nint>>? _handledGameAddresses;
|
private ICallGateProvider<List<nint>>? _handledGameAddresses;
|
||||||
@@ -34,17 +34,14 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
public MareMediator Mediator { get; init; }
|
public MareMediator Mediator { get; init; }
|
||||||
|
|
||||||
public IpcProvider(ILogger<IpcProvider> logger, IDalamudPluginInterface pi, MareConfigService mareConfig,
|
public IpcProvider(ILogger<IpcProvider> logger, IDalamudPluginInterface pi, MareConfigService mareConfig,
|
||||||
DalamudUtilService dalamudUtil,
|
CharaDataManager charaDataManager, MareMediator mareMediator)
|
||||||
MareMediator mareMediator)
|
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_pi = pi;
|
_pi = pi;
|
||||||
_mareConfig = mareConfig;
|
_mareConfig = mareConfig;
|
||||||
_dalamudUtil = dalamudUtil;
|
_charaDataManager = charaDataManager;
|
||||||
Mediator = mareMediator;
|
Mediator = mareMediator;
|
||||||
|
|
||||||
// todo: fix ipc to use CharaDataManager
|
|
||||||
|
|
||||||
Mediator.Subscribe<GameObjectHandlerCreatedMessage>(this, (msg) =>
|
Mediator.Subscribe<GameObjectHandlerCreatedMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
if (msg.OwnedObject) return;
|
if (msg.OwnedObject) return;
|
||||||
@@ -135,9 +132,6 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
private async Task<bool> LoadMcdfAsync(string path, IGameObject target)
|
private async Task<bool> LoadMcdfAsync(string path, IGameObject target)
|
||||||
{
|
{
|
||||||
//if (_mareCharaFileManager.CurrentlyWorking || !_dalamudUtil.IsInGpose)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
await ApplyFileAsync(path, target).ConfigureAwait(false);
|
await ApplyFileAsync(path, target).ConfigureAwait(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -145,9 +139,6 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
private bool LoadMcdf(string path, IGameObject target)
|
private bool LoadMcdf(string path, IGameObject target)
|
||||||
{
|
{
|
||||||
//if (_mareCharaFileManager.CurrentlyWorking || !_dalamudUtil.IsInGpose)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_ = Task.Run(async () => await ApplyFileAsync(path, target).ConfigureAwait(false)).ConfigureAwait(false);
|
_ = Task.Run(async () => await ApplyFileAsync(path, target).ConfigureAwait(false)).ConfigureAwait(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -155,20 +146,9 @@ public class IpcProvider : IHostedService, IMediatorSubscriber
|
|||||||
|
|
||||||
private async Task ApplyFileAsync(string path, IGameObject target)
|
private async Task ApplyFileAsync(string path, IGameObject target)
|
||||||
{
|
{
|
||||||
/*
|
_charaDataManager.LoadMcdf(path);
|
||||||
try
|
await (_charaDataManager.LoadedMcdfHeader ?? Task.CompletedTask).ConfigureAwait(false);
|
||||||
{
|
_charaDataManager.McdfApplyToTarget(target.Name.TextValue);
|
||||||
var expectedLength = _mareCharaFileManager.LoadMareCharaFile(path);
|
|
||||||
await _mareCharaFileManager.ApplyMareCharaFile(target, expectedLength).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_logger.LogError(e, "Failure of IPC call");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_mareCharaFileManager.ClearMareCharaFile();
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<nint> GetHandledAddresses()
|
private List<nint> GetHandledAddresses()
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ public class CharaDataConfig : IMareConfiguration
|
|||||||
public int NearbyDistanceFilter { get; set; } = 100;
|
public int NearbyDistanceFilter { get; set; } = 100;
|
||||||
public bool NearbyShowOwnData { get; set; } = false;
|
public bool NearbyShowOwnData { get; set; } = false;
|
||||||
public bool ShowHelpTexts { get; set; } = true;
|
public bool ShowHelpTexts { get; set; } = true;
|
||||||
|
public bool NearbyShowAlways { get; set; } = false;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,12 @@
|
|||||||
<PackageProjectUrl>https://github.com/loporrit/MareClient/</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/loporrit/MareClient/</PackageProjectUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="PlayerData\Export\**" />
|
||||||
|
<EmbeddedResource Remove="PlayerData\Export\**" />
|
||||||
|
<None Remove="PlayerData\Export\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Downloader" Version="3.3.4" />
|
<PackageReference Include="Downloader" Version="3.3.4" />
|
||||||
<PackageReference Include="K4os.Compression.LZ4.Legacy" Version="1.3.8" />
|
<PackageReference Include="K4os.Compression.LZ4.Legacy" Version="1.3.8" />
|
||||||
@@ -69,8 +75,4 @@
|
|||||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="PlayerData\Export\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -61,6 +61,17 @@ public sealed class PairManager : DisposableMediatorSubscriberBase
|
|||||||
RecreateLazy();
|
RecreateLazy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Pair? GetPairByUID(string uid)
|
||||||
|
{
|
||||||
|
var existingPair = _allClientPairs.FirstOrDefault(f => f.Key.UID == uid);
|
||||||
|
if (!Equals(existingPair, default(KeyValuePair<UserData, Pair>)))
|
||||||
|
{
|
||||||
|
return existingPair.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddUserPair(UserPairDto dto, bool addToLastAddedUser = true)
|
public void AddUserPair(UserPairDto dto, bool addToLastAddedUser = true)
|
||||||
{
|
{
|
||||||
if (!_allClientPairs.ContainsKey(dto.User))
|
if (!_allClientPairs.ContainsKey(dto.User))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace MareSynchronos.Services;
|
namespace MareSynchronos.Services;
|
||||||
|
|
||||||
internal sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
@@ -71,22 +71,8 @@ internal sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBa
|
|||||||
using var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player,
|
using var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player,
|
||||||
() => _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, _dalamudUtilService.IsInGpose)?.Address ?? IntPtr.Zero, false)
|
() => _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, _dalamudUtilService.IsInGpose)?.Address ?? IntPtr.Zero, false)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
if (handler.Address != IntPtr.Zero)
|
if (handler.Address != nint.Zero)
|
||||||
{
|
|
||||||
var poseData = string.Empty;
|
|
||||||
API.Dto.CharaData.WorldData? worldData = null;
|
|
||||||
if (_dalamudUtilService.IsInGpose && reapplyPose)
|
|
||||||
{
|
|
||||||
poseData = await _ipcManager.Brio.GetPoseAsync(handler.Address).ConfigureAwait(false);
|
|
||||||
worldData = await _ipcManager.Brio.GetTransformAsync(handler.Address).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
await _ipcManager.Penumbra.RedrawAsync(Logger, handler, applicationId, CancellationToken.None).ConfigureAwait(false);
|
await _ipcManager.Penumbra.RedrawAsync(Logger, handler, applicationId, CancellationToken.None).ConfigureAwait(false);
|
||||||
if (_dalamudUtilService.IsInGpose && reapplyPose)
|
|
||||||
{
|
|
||||||
await _ipcManager.Brio.SetPoseAsync(handler.Address, poseData ?? "{}").ConfigureAwait(false);
|
|
||||||
await _ipcManager.Brio.ApplyTransformAsync(handler.Address, worldData!.Value).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> RevertHandledChara(string name, bool reapplyPose = true)
|
public async Task<bool> RevertHandledChara(string name, bool reapplyPose = true)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace MareSynchronos.Services;
|
namespace MareSynchronos.Services;
|
||||||
|
|
||||||
internal sealed class CharaDataFileHandler : IDisposable
|
public sealed class CharaDataFileHandler : IDisposable
|
||||||
{
|
{
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
private readonly FileCacheManager _fileCacheManager;
|
private readonly FileCacheManager _fileCacheManager;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using MareSynchronos.Interop.Ipc;
|
|||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.PlayerData.Factories;
|
using MareSynchronos.PlayerData.Factories;
|
||||||
using MareSynchronos.PlayerData.Handlers;
|
using MareSynchronos.PlayerData.Handlers;
|
||||||
|
using MareSynchronos.PlayerData.Pairs;
|
||||||
using MareSynchronos.Services.CharaData.Models;
|
using MareSynchronos.Services.CharaData.Models;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
@@ -15,7 +16,7 @@ using System.Text;
|
|||||||
|
|
||||||
namespace MareSynchronos.Services;
|
namespace MareSynchronos.Services;
|
||||||
|
|
||||||
internal sealed partial class CharaDataManager : DisposableMediatorSubscriberBase
|
public sealed partial class CharaDataManager : DisposableMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
private readonly ApiController _apiController;
|
private readonly ApiController _apiController;
|
||||||
private readonly CharaDataConfigService _configService;
|
private readonly CharaDataConfigService _configService;
|
||||||
@@ -26,6 +27,7 @@ internal sealed partial class CharaDataManager : DisposableMediatorSubscriberBas
|
|||||||
private readonly List<CharaDataMetaInfoExtendedDto> _nearbyData = [];
|
private readonly List<CharaDataMetaInfoExtendedDto> _nearbyData = [];
|
||||||
private readonly CharaDataNearbyManager _nearbyManager;
|
private readonly CharaDataNearbyManager _nearbyManager;
|
||||||
private readonly CharaDataCharacterHandler _characterHandler;
|
private readonly CharaDataCharacterHandler _characterHandler;
|
||||||
|
private readonly PairManager _pairManager;
|
||||||
private readonly Dictionary<string, CharaDataFullExtendedDto> _ownCharaData = [];
|
private readonly Dictionary<string, CharaDataFullExtendedDto> _ownCharaData = [];
|
||||||
private readonly Dictionary<string, Task> _sharedMetaInfoTimeoutTasks = [];
|
private readonly Dictionary<string, Task> _sharedMetaInfoTimeoutTasks = [];
|
||||||
private readonly Dictionary<UserData, List<CharaDataMetaInfoExtendedDto>> _sharedWithYouData = [];
|
private readonly Dictionary<UserData, List<CharaDataMetaInfoExtendedDto>> _sharedWithYouData = [];
|
||||||
@@ -42,7 +44,7 @@ internal sealed partial class CharaDataManager : DisposableMediatorSubscriberBas
|
|||||||
MareMediator mareMediator, IpcManager ipcManager, DalamudUtilService dalamudUtilService,
|
MareMediator mareMediator, IpcManager ipcManager, DalamudUtilService dalamudUtilService,
|
||||||
FileDownloadManagerFactory fileDownloadManagerFactory,
|
FileDownloadManagerFactory fileDownloadManagerFactory,
|
||||||
CharaDataConfigService charaDataConfigService, CharaDataNearbyManager charaDataNearbyManager,
|
CharaDataConfigService charaDataConfigService, CharaDataNearbyManager charaDataNearbyManager,
|
||||||
CharaDataCharacterHandler charaDataCharacterHandler) : base(logger, mareMediator)
|
CharaDataCharacterHandler charaDataCharacterHandler, PairManager pairManager) : base(logger, mareMediator)
|
||||||
{
|
{
|
||||||
_apiController = apiController;
|
_apiController = apiController;
|
||||||
_fileHandler = charaDataFileHandler;
|
_fileHandler = charaDataFileHandler;
|
||||||
@@ -51,6 +53,7 @@ internal sealed partial class CharaDataManager : DisposableMediatorSubscriberBas
|
|||||||
_configService = charaDataConfigService;
|
_configService = charaDataConfigService;
|
||||||
_nearbyManager = charaDataNearbyManager;
|
_nearbyManager = charaDataNearbyManager;
|
||||||
_characterHandler = charaDataCharacterHandler;
|
_characterHandler = charaDataCharacterHandler;
|
||||||
|
_pairManager = pairManager;
|
||||||
mareMediator.Subscribe<ConnectedMessage>(this, (msg) =>
|
mareMediator.Subscribe<ConnectedMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
_connectCts?.Cancel();
|
_connectCts?.Cancel();
|
||||||
@@ -393,6 +396,8 @@ internal sealed partial class CharaDataManager : DisposableMediatorSubscriberBas
|
|||||||
var result = await GetSharedWithYouTask.ConfigureAwait(false);
|
var result = await GetSharedWithYouTask.ConfigureAwait(false);
|
||||||
foreach (var grouping in result.GroupBy(r => r.Uploader))
|
foreach (var grouping in result.GroupBy(r => r.Uploader))
|
||||||
{
|
{
|
||||||
|
var pair = _pairManager.GetPairByUID(grouping.Key.UID);
|
||||||
|
if (pair?.IsPaused ?? false) continue;
|
||||||
List<CharaDataMetaInfoExtendedDto> newList = new();
|
List<CharaDataMetaInfoExtendedDto> newList = new();
|
||||||
foreach (var item in grouping)
|
foreach (var item in grouping)
|
||||||
{
|
{
|
||||||
@@ -427,12 +432,12 @@ internal sealed partial class CharaDataManager : DisposableMediatorSubscriberBas
|
|||||||
LoadedMcdfHeader = _fileHandler.LoadCharaFileHeader(filePath);
|
LoadedMcdfHeader = _fileHandler.LoadCharaFileHeader(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void McdfApplyToGposeTarget()
|
public void McdfApplyToTarget(string charaName)
|
||||||
{
|
{
|
||||||
if (LoadedMcdfHeader == null || !LoadedMcdfHeader.IsCompletedSuccessfully) return;
|
if (LoadedMcdfHeader == null || !LoadedMcdfHeader.IsCompletedSuccessfully) return;
|
||||||
var charaName = _dalamudUtilService.GposeTargetGameObject?.Name.TextValue ?? string.Empty;
|
|
||||||
|
|
||||||
List<string> actuallyExtractedFiles = [];
|
List<string> actuallyExtractedFiles = [];
|
||||||
|
|
||||||
UiBlockingComputation = McdfApplicationTask = Task.Run(async () =>
|
UiBlockingComputation = McdfApplicationTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Guid applicationId = Guid.NewGuid();
|
Guid applicationId = Guid.NewGuid();
|
||||||
@@ -478,6 +483,14 @@ internal sealed partial class CharaDataManager : DisposableMediatorSubscriberBas
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void McdfApplyToGposeTarget()
|
||||||
|
{
|
||||||
|
if (CanApplyInGpose(out string target))
|
||||||
|
{
|
||||||
|
McdfApplyToTarget(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SaveMareCharaFile(string description, string filePath)
|
public void SaveMareCharaFile(string description, string filePath)
|
||||||
{
|
{
|
||||||
UiBlockingComputation = Task.Run(async () => await _fileHandler.SaveCharaFileAsync(description, filePath).ConfigureAwait(false));
|
UiBlockingComputation = Task.Run(async () => await _fileHandler.SaveCharaFileAsync(description, filePath).ConfigureAwait(false));
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ using MareSynchronos.Services.CharaData.Models;
|
|||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Services.ServerConfiguration;
|
using MareSynchronos.Services.ServerConfiguration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Diagnostics.Eventing.Reader;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace MareSynchronos.Services;
|
namespace MareSynchronos.Services;
|
||||||
|
|
||||||
internal sealed class CharaDataNearbyManager : DisposableMediatorSubscriberBase
|
public sealed class CharaDataNearbyManager : DisposableMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
internal record NearbyCharaDataEntry
|
public record NearbyCharaDataEntry
|
||||||
{
|
{
|
||||||
public float Direction { get; init; }
|
public float Direction { get; init; }
|
||||||
public float Distance { get; init; }
|
public float Distance { get; init; }
|
||||||
@@ -29,6 +28,7 @@ internal 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);
|
||||||
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,
|
||||||
@@ -51,17 +51,25 @@ internal sealed class CharaDataNearbyManager : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
public void UpdateSharedData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
public void UpdateSharedData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
||||||
{
|
{
|
||||||
_metaInfoCache.Clear();
|
_sharedDataUpdateSemaphore.Wait();
|
||||||
foreach (var kvp in newData)
|
try
|
||||||
{
|
{
|
||||||
if (kvp.Value == null) continue;
|
_metaInfoCache.Clear();
|
||||||
|
foreach (var kvp in newData)
|
||||||
if (!_metaInfoCache.TryGetValue(kvp.Value.Uploader, out var list))
|
|
||||||
{
|
{
|
||||||
_metaInfoCache[kvp.Value.Uploader] = list = [];
|
if (kvp.Value == null) continue;
|
||||||
}
|
|
||||||
|
|
||||||
list.Add(kvp.Value);
|
if (!_metaInfoCache.TryGetValue(kvp.Value.Uploader, out var list))
|
||||||
|
{
|
||||||
|
_metaInfoCache[kvp.Value.Uploader] = list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add(kvp.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sharedDataUpdateSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +236,7 @@ internal sealed class CharaDataNearbyManager : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_charaDataConfigService.Current.NearbyDrawWisps && !_dalamudUtilService.IsInGpose)
|
if (_charaDataConfigService.Current.NearbyDrawWisps && !_dalamudUtilService.IsInGpose && !_dalamudUtilService.IsInCombatOrPerforming)
|
||||||
await _dalamudUtilService.RunOnFrameworkThread(() => ManageWispsNearby(previousPoses)).ConfigureAwait(false);
|
await _dalamudUtilService.RunOnFrameworkThread(() => ManageWispsNearby(previousPoses)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +244,7 @@ internal sealed class CharaDataNearbyManager : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
if (_lastExecutionTime.AddSeconds(0.5) > DateTime.UtcNow) return;
|
if (_lastExecutionTime.AddSeconds(0.5) > DateTime.UtcNow) return;
|
||||||
_lastExecutionTime = DateTime.UtcNow;
|
_lastExecutionTime = DateTime.UtcNow;
|
||||||
if (!ComputeNearbyData)
|
if (!ComputeNearbyData && !_charaDataConfigService.Current.NearbyShowAlways)
|
||||||
{
|
{
|
||||||
if (_nearbyData.Any())
|
if (_nearbyData.Any())
|
||||||
_nearbyData.Clear();
|
_nearbyData.Clear();
|
||||||
@@ -245,14 +253,14 @@ internal sealed class CharaDataNearbyManager : DisposableMediatorSubscriberBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_charaDataConfigService.Current.NearbyDrawWisps || _dalamudUtilService.IsInGpose)
|
if (!_charaDataConfigService.Current.NearbyDrawWisps || _dalamudUtilService.IsInGpose || _dalamudUtilService.IsInCombatOrPerforming)
|
||||||
ClearAllVfx();
|
ClearAllVfx();
|
||||||
|
|
||||||
var camera = CameraManager.Instance()->CurrentCamera;
|
var camera = CameraManager.Instance()->CurrentCamera;
|
||||||
Vector3 cameraPos = new(camera->Position.X, camera->Position.Y, camera->Position.Z);
|
Vector3 cameraPos = new(camera->Position.X, camera->Position.Y, camera->Position.Z);
|
||||||
Vector3 lookAt = new(camera->LookAtVector.X, camera->LookAtVector.Y, camera->LookAtVector.Z);
|
Vector3 lookAt = new(camera->LookAtVector.X, camera->LookAtVector.Y, camera->LookAtVector.Z);
|
||||||
|
|
||||||
if (_filterEntriesRunningTask?.IsCompleted ?? true)
|
if (_filterEntriesRunningTask?.IsCompleted ?? true && _dalamudUtilService.IsLoggedIn)
|
||||||
_filterEntriesRunningTask = FilterEntriesAsync(cameraPos, lookAt);
|
_filterEntriesRunningTask = FilterEntriesAsync(cameraPos, lookAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using MareSynchronos.Services.CharaData.Models;
|
|||||||
|
|
||||||
namespace MareSynchronos.Services.CharaData;
|
namespace MareSynchronos.Services.CharaData;
|
||||||
|
|
||||||
internal sealed class MareCharaFileDataFactory
|
public sealed class MareCharaFileDataFactory
|
||||||
{
|
{
|
||||||
private readonly FileCacheManager _fileCacheManager;
|
private readonly FileCacheManager _fileCacheManager;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public sealed record CharaDataExtendedUpdateDto : CharaDataUpdateDto
|
|||||||
{
|
{
|
||||||
_charaDataFullDto = charaDataFullDto;
|
_charaDataFullDto = charaDataFullDto;
|
||||||
_userList = charaDataFullDto.AllowedUsers.ToList();
|
_userList = charaDataFullDto.AllowedUsers.ToList();
|
||||||
|
_groupList = charaDataFullDto.AllowedGroups.ToList();
|
||||||
_poseList = charaDataFullDto.PoseData.Select(k => new PoseEntry(k.Id)
|
_poseList = charaDataFullDto.PoseData.Select(k => new PoseEntry(k.Id)
|
||||||
{
|
{
|
||||||
Description = k.Description,
|
Description = k.Description,
|
||||||
@@ -22,6 +23,7 @@ public sealed record CharaDataExtendedUpdateDto : CharaDataUpdateDto
|
|||||||
public CharaDataUpdateDto BaseDto => new(Id)
|
public CharaDataUpdateDto BaseDto => new(Id)
|
||||||
{
|
{
|
||||||
AllowedUsers = AllowedUsers,
|
AllowedUsers = AllowedUsers,
|
||||||
|
AllowedGroups = AllowedGroups,
|
||||||
AccessType = base.AccessType,
|
AccessType = base.AccessType,
|
||||||
CustomizeData = base.CustomizeData,
|
CustomizeData = base.CustomizeData,
|
||||||
Description = base.Description,
|
Description = base.Description,
|
||||||
@@ -192,15 +194,25 @@ public sealed record CharaDataExtendedUpdateDto : CharaDataUpdateDto
|
|||||||
|
|
||||||
public IEnumerable<UserData> UserList => _userList;
|
public IEnumerable<UserData> UserList => _userList;
|
||||||
private readonly List<UserData> _userList;
|
private readonly List<UserData> _userList;
|
||||||
|
|
||||||
|
public IEnumerable<GroupData> GroupList => _groupList;
|
||||||
|
private readonly List<GroupData> _groupList;
|
||||||
|
|
||||||
public IEnumerable<PoseEntry> PoseList => _poseList;
|
public IEnumerable<PoseEntry> PoseList => _poseList;
|
||||||
private readonly List<PoseEntry> _poseList;
|
private readonly List<PoseEntry> _poseList;
|
||||||
|
|
||||||
public void AddToList(string user)
|
public void AddUserToList(string user)
|
||||||
{
|
{
|
||||||
_userList.Add(new(user, null));
|
_userList.Add(new(user, null));
|
||||||
UpdateAllowedUsers();
|
UpdateAllowedUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddGroupToList(string group)
|
||||||
|
{
|
||||||
|
_groupList.Add(new(group, null));
|
||||||
|
UpdateAllowedGroups();
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateAllowedUsers()
|
private void UpdateAllowedUsers()
|
||||||
{
|
{
|
||||||
AllowedUsers = [.. _userList.Select(u => u.UID)];
|
AllowedUsers = [.. _userList.Select(u => u.UID)];
|
||||||
@@ -211,12 +223,28 @@ public sealed record CharaDataExtendedUpdateDto : CharaDataUpdateDto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveFromList(string user)
|
private void UpdateAllowedGroups()
|
||||||
|
{
|
||||||
|
AllowedGroups = [.. _groupList.Select(u => u.GID)];
|
||||||
|
if (!AllowedGroups.Except(_charaDataFullDto.AllowedGroups.Select(u => u.GID), StringComparer.Ordinal).Any()
|
||||||
|
&& !_charaDataFullDto.AllowedGroups.Select(u => u.GID).Except(AllowedGroups, StringComparer.Ordinal).Any())
|
||||||
|
{
|
||||||
|
AllowedGroups = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveUserFromList(string user)
|
||||||
{
|
{
|
||||||
_userList.RemoveAll(u => string.Equals(u.UID, user, StringComparison.Ordinal));
|
_userList.RemoveAll(u => string.Equals(u.UID, user, StringComparison.Ordinal));
|
||||||
UpdateAllowedUsers();
|
UpdateAllowedUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoveGroupFromList(string group)
|
||||||
|
{
|
||||||
|
_groupList.RemoveAll(u => string.Equals(u.GID, group, StringComparison.Ordinal));
|
||||||
|
UpdateAllowedGroups();
|
||||||
|
}
|
||||||
|
|
||||||
public void AddPose()
|
public void AddPose()
|
||||||
{
|
{
|
||||||
_poseList.Add(new PoseEntry(null));
|
_poseList.Add(new PoseEntry(null));
|
||||||
@@ -279,6 +307,7 @@ public sealed record CharaDataExtendedUpdateDto : CharaDataUpdateDto
|
|||||||
base.CustomizeData = null;
|
base.CustomizeData = null;
|
||||||
base.ManipulationData = null;
|
base.ManipulationData = null;
|
||||||
AllowedUsers = null;
|
AllowedUsers = null;
|
||||||
|
AllowedGroups = null;
|
||||||
Poses = null;
|
Poses = null;
|
||||||
_poseList.Clear();
|
_poseList.Clear();
|
||||||
_poseList.AddRange(_charaDataFullDto.PoseData.Select(k => new PoseEntry(k.Id)
|
_poseList.AddRange(_charaDataFullDto.PoseData.Select(k => new PoseEntry(k.Id)
|
||||||
@@ -316,6 +345,7 @@ public sealed record CharaDataExtendedUpdateDto : CharaDataUpdateDto
|
|||||||
|| base.AccessType != null
|
|| base.AccessType != null
|
||||||
|| base.ShareType != null
|
|| base.ShareType != null
|
||||||
|| AllowedUsers != null
|
|| AllowedUsers != null
|
||||||
|
|| AllowedGroups != null
|
||||||
|| base.GlamourerData != null
|
|| base.GlamourerData != null
|
||||||
|| base.FileSwaps != null
|
|| base.FileSwaps != null
|
||||||
|| base.FileGamePaths != null
|
|| base.FileGamePaths != null
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ internal sealed partial class CharaDataHubUi
|
|||||||
private static string GetAccessTypeString(AccessTypeDto dto) => dto switch
|
private static string GetAccessTypeString(AccessTypeDto dto) => dto switch
|
||||||
{
|
{
|
||||||
AccessTypeDto.AllPairs => "All Pairs",
|
AccessTypeDto.AllPairs => "All Pairs",
|
||||||
AccessTypeDto.ClosePairs => "Close Pairs",
|
AccessTypeDto.ClosePairs => "Direct Pairs",
|
||||||
AccessTypeDto.Individuals => "Specified",
|
AccessTypeDto.Individuals => "Specified",
|
||||||
AccessTypeDto.Public => "Everyone"
|
AccessTypeDto.Public => "Everyone"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string GetShareTypeString(ShareTypeDto dto) => dto switch
|
private static string GetShareTypeString(ShareTypeDto dto) => dto switch
|
||||||
{
|
{
|
||||||
ShareTypeDto.Private => "Private",
|
ShareTypeDto.Private => "Code Only",
|
||||||
ShareTypeDto.Shared => "Shared"
|
ShareTypeDto.Shared => "Shared"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using ImGuiNET;
|
|||||||
using MareSynchronos.API.Dto.CharaData;
|
using MareSynchronos.API.Dto.CharaData;
|
||||||
using MareSynchronos.Services.CharaData.Models;
|
using MareSynchronos.Services.CharaData.Models;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using MareSynchronos.Services;
|
||||||
|
|
||||||
namespace MareSynchronos.UI;
|
namespace MareSynchronos.UI;
|
||||||
|
|
||||||
@@ -122,15 +123,15 @@ internal sealed partial class CharaDataHubUi
|
|||||||
ImGui.EndCombo();
|
ImGui.EndCombo();
|
||||||
}
|
}
|
||||||
_uiSharedService.DrawHelpText("You can control who has access to your character data based on the access restrictions." + UiSharedService.TooltipSeparator
|
_uiSharedService.DrawHelpText("You can control who has access to your character data based on the access restrictions." + UiSharedService.TooltipSeparator
|
||||||
+ "Specified: Only people you directly specify in 'Specific Individuals' can access this character data" + Environment.NewLine
|
+ "Specified: Only people and syncshells you directly specify in 'Specific Individuals / Syncshells' can access this character data" + Environment.NewLine
|
||||||
+ "Close Pairs: Only people you have directly paired can access this character data" + Environment.NewLine
|
+ "Direct Pairs: Only people you have directly paired can access this character data" + Environment.NewLine
|
||||||
+ "All Pairs: All people you have paired can access this character data" + Environment.NewLine
|
+ "All Pairs: All people you have paired can access this character data" + Environment.NewLine
|
||||||
+ "Everyone: Everyone can access this character data" + UiSharedService.TooltipSeparator
|
+ "Everyone: Everyone can access this character data" + UiSharedService.TooltipSeparator
|
||||||
+ "Note: To access your character data the person in question requires to have the code. Exceptions for 'Shared' data, see 'Sharing' below." + Environment.NewLine
|
+ "Note: To access your character data the person in question requires to have the code. Exceptions for 'Shared' data, see 'Sharing' below." + Environment.NewLine
|
||||||
+ "Note: For 'Close' and 'All Pairs' the pause state plays a role. Paused people will not be able to access your character data." + Environment.NewLine
|
+ "Note: For 'Direct' and 'All Pairs' the pause state plays a role. Paused people will not be able to access your character data." + Environment.NewLine
|
||||||
+ "Note: Directly specified individuals in the 'Specific Individuals' list will be able to access your character data regardless of pause or pair state.");
|
+ "Note: Directly specified Individuals or Syncshells in the 'Specific Individuals / Syncshells' list will be able to access your character data regardless of pause or pair state.");
|
||||||
|
|
||||||
DrawSpecificIndividuals(updateDto);
|
DrawSpecific(updateDto);
|
||||||
|
|
||||||
ImGui.SetNextItemWidth(200);
|
ImGui.SetNextItemWidth(200);
|
||||||
var dtoShareType = updateDto.ShareType;
|
var dtoShareType = updateDto.ShareType;
|
||||||
@@ -150,8 +151,8 @@ internal sealed partial class CharaDataHubUi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_uiSharedService.DrawHelpText("This regulates how you want to distribute this character data." + UiSharedService.TooltipSeparator
|
_uiSharedService.DrawHelpText("This regulates how you want to distribute this character data." + UiSharedService.TooltipSeparator
|
||||||
+ "Private: People require to have the code to download this character data" + Environment.NewLine
|
+ "Code Only: People require to have the code to download this character data" + Environment.NewLine
|
||||||
+ "Shared: People that are allowed through 'Access Restrictions' will have this character data entry displayed in 'Shared with You'" + UiSharedService.TooltipSeparator
|
+ "Shared: People that are allowed through 'Access Restrictions' will have this character data entry displayed in 'Shared with You' (it can also be accessed through the code)" + UiSharedService.TooltipSeparator
|
||||||
+ "Note: Shared is incompatible with Access Restriction 'Everyone'");
|
+ "Note: Shared is incompatible with Access Restriction 'Everyone'");
|
||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(10f);
|
ImGuiHelpers.ScaledDummy(10f);
|
||||||
@@ -533,7 +534,7 @@ internal sealed partial class CharaDataHubUi
|
|||||||
+ "Be mindful that when you share your Character Data with other people there is a chance that, with the help of unsanctioned 3rd party plugins, your appearance could be stolen irreversibly, just like when using MCDF.");
|
+ "Be mindful that when you share your Character Data with other people there is a chance that, with the help of unsanctioned 3rd party plugins, your appearance could be stolen irreversibly, just like when using MCDF.");
|
||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(5);
|
ImGuiHelpers.ScaledDummy(5);
|
||||||
using (ImRaii.Disabled(_charaDataManager.GetAllDataTask != null
|
using (ImRaii.Disabled((!_charaDataManager.GetAllDataTask?.IsCompleted ?? false)
|
||||||
|| (_charaDataManager.DataGetTimeoutTask != null && !_charaDataManager.DataGetTimeoutTask.IsCompleted)))
|
|| (_charaDataManager.DataGetTimeoutTask != null && !_charaDataManager.DataGetTimeoutTask.IsCompleted)))
|
||||||
{
|
{
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Download your Character Data from Server"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleDown, "Download your Character Data from Server"))
|
||||||
@@ -649,6 +650,7 @@ 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);
|
_charaDataManager.CreateCharaDataEntry(_closalCts.Token);
|
||||||
|
_selectNewEntry = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_charaDataManager.DataCreationTask != null)
|
if (_charaDataManager.DataCreationTask != null)
|
||||||
@@ -685,49 +687,113 @@ internal sealed partial class CharaDataHubUi
|
|||||||
ImGuiHelpers.ScaledDummy(10);
|
ImGuiHelpers.ScaledDummy(10);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
|
var charaDataEntries = _charaDataManager.OwnCharaData.Count;
|
||||||
|
if (charaDataEntries != _dataEntries && _selectNewEntry && _charaDataManager.OwnCharaData.Any())
|
||||||
|
{
|
||||||
|
_selectedDtoId = _charaDataManager.OwnCharaData.Last().Value.Id;
|
||||||
|
_selectNewEntry = false;
|
||||||
|
}
|
||||||
|
_dataEntries = _charaDataManager.OwnCharaData.Count;
|
||||||
|
|
||||||
_ = _charaDataManager.OwnCharaData.TryGetValue(_selectedDtoId, out var dto);
|
_ = _charaDataManager.OwnCharaData.TryGetValue(_selectedDtoId, out var dto);
|
||||||
DrawEditCharaData(dto);
|
DrawEditCharaData(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawSpecificIndividuals(CharaDataExtendedUpdateDto updateDto)
|
bool _selectNewEntry = false;
|
||||||
{
|
int _dataEntries = 0;
|
||||||
UiSharedService.DrawTree("Access for Specific Individuals", () =>
|
|
||||||
{
|
|
||||||
ImGui.SetNextItemWidth(200);
|
|
||||||
ImGui.InputText("##AliasToAdd", ref _specificIndividualAdd, 20);
|
|
||||||
ImGui.SameLine();
|
|
||||||
using (ImRaii.Disabled(string.IsNullOrEmpty(_specificIndividualAdd)
|
|
||||||
|| updateDto.UserList.Any(f => string.Equals(f.UID, _specificIndividualAdd, StringComparison.Ordinal) || string.Equals(f.Alias, _specificIndividualAdd, StringComparison.Ordinal))))
|
|
||||||
{
|
|
||||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Plus))
|
|
||||||
{
|
|
||||||
updateDto.AddToList(_specificIndividualAdd);
|
|
||||||
_specificIndividualAdd = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImGui.TextUnformatted("UID/Vanity ID to Add");
|
|
||||||
_uiSharedService.DrawHelpText("Users added to this list will be able to access this character data regardless of your pause or pair state with them." + UiSharedService.TooltipSeparator
|
|
||||||
+ "Note: Mistyped entries will be automatically removed on updating data to server.");
|
|
||||||
|
|
||||||
using (var lb = ImRaii.ListBox("Allowed Individuals", new(200, 200)))
|
private void DrawSpecific(CharaDataExtendedUpdateDto updateDto)
|
||||||
|
{
|
||||||
|
UiSharedService.DrawTree("Access for Specific Individuals / Syncshells", () =>
|
||||||
|
{
|
||||||
|
using (ImRaii.PushId("user"))
|
||||||
{
|
{
|
||||||
foreach (var user in updateDto.UserList)
|
using (ImRaii.Group())
|
||||||
{
|
{
|
||||||
var userString = string.IsNullOrEmpty(user.Alias) ? user.UID : $"{user.Alias} ({user.UID})";
|
InputComboHybrid("##AliasToAdd", "##AliasToAddPicker", ref _specificIndividualAdd, _pairManager.DirectPairs,
|
||||||
if (ImGui.Selectable(userString, string.Equals(user.UID, _selectedSpecificIndividual, StringComparison.Ordinal)))
|
static pair => (pair.UserData.UID, pair.UserData.Alias, pair.UserData.AliasOrUID, pair.GetNoteOrName()));
|
||||||
|
ImGui.SameLine();
|
||||||
|
using (ImRaii.Disabled(string.IsNullOrEmpty(_specificIndividualAdd)
|
||||||
|
|| updateDto.UserList.Any(f => string.Equals(f.UID, _specificIndividualAdd, StringComparison.Ordinal) || string.Equals(f.Alias, _specificIndividualAdd, StringComparison.Ordinal))))
|
||||||
{
|
{
|
||||||
_selectedSpecificIndividual = user.UID;
|
if (_uiSharedService.IconButton(FontAwesomeIcon.Plus))
|
||||||
|
{
|
||||||
|
updateDto.AddUserToList(_specificIndividualAdd);
|
||||||
|
_specificIndividualAdd = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted("UID/Vanity UID to Add");
|
||||||
|
_uiSharedService.DrawHelpText("Users added to this list will be able to access this character data regardless of your pause or pair state with them." + UiSharedService.TooltipSeparator
|
||||||
|
+ "Note: Mistyped entries will be automatically removed on updating data to server.");
|
||||||
|
|
||||||
|
using (var lb = ImRaii.ListBox("Allowed Individuals", new(200, 200)))
|
||||||
|
{
|
||||||
|
foreach (var user in updateDto.UserList)
|
||||||
|
{
|
||||||
|
var userString = string.IsNullOrEmpty(user.Alias) ? user.UID : $"{user.Alias} ({user.UID})";
|
||||||
|
if (ImGui.Selectable(userString, string.Equals(user.UID, _selectedSpecificUserIndividual, StringComparison.Ordinal)))
|
||||||
|
{
|
||||||
|
_selectedSpecificUserIndividual = user.UID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (ImRaii.Disabled(string.IsNullOrEmpty(_selectedSpecificUserIndividual)))
|
||||||
|
{
|
||||||
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Remove selected User"))
|
||||||
|
{
|
||||||
|
updateDto.RemoveUserFromList(_selectedSpecificUserIndividual);
|
||||||
|
_selectedSpecificUserIndividual = string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGuiHelpers.ScaledDummy(20);
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
using (ImRaii.Disabled(string.IsNullOrEmpty(_selectedSpecificIndividual)))
|
using (ImRaii.PushId("group"))
|
||||||
{
|
{
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Remove selected User"))
|
using (ImRaii.Group())
|
||||||
{
|
{
|
||||||
updateDto.RemoveFromList(_selectedSpecificIndividual);
|
InputComboHybrid("##GroupAliasToAdd", "##GroupAliasToAddPicker", ref _specificGroupAdd, _pairManager.Groups.Keys,
|
||||||
_selectedSpecificIndividual = string.Empty;
|
group => (group.GID, group.Alias, group.AliasOrGID, _serverConfigurationManager.GetNoteForGid(group.GID)));
|
||||||
|
ImGui.SameLine();
|
||||||
|
using (ImRaii.Disabled(string.IsNullOrEmpty(_specificGroupAdd)
|
||||||
|
|| updateDto.GroupList.Any(f => string.Equals(f.GID, _specificGroupAdd, StringComparison.Ordinal) || string.Equals(f.Alias, _specificGroupAdd, StringComparison.Ordinal))))
|
||||||
|
{
|
||||||
|
if (_uiSharedService.IconButton(FontAwesomeIcon.Plus))
|
||||||
|
{
|
||||||
|
updateDto.AddGroupToList(_specificGroupAdd);
|
||||||
|
_specificGroupAdd = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted("GID/Vanity GID to Add");
|
||||||
|
_uiSharedService.DrawHelpText("Users in Syncshells added to this list will be able to access this character data regardless of your pause or pair state with them." + UiSharedService.TooltipSeparator
|
||||||
|
+ "Note: Mistyped entries will be automatically removed on updating data to server.");
|
||||||
|
|
||||||
|
using (var lb = ImRaii.ListBox("Allowed Syncshells", new(200, 200)))
|
||||||
|
{
|
||||||
|
foreach (var group in updateDto.GroupList)
|
||||||
|
{
|
||||||
|
var userString = string.IsNullOrEmpty(group.Alias) ? group.GID : $"{group.Alias} ({group.GID})";
|
||||||
|
if (ImGui.Selectable(userString, string.Equals(group.GID, _selectedSpecificGroupIndividual, StringComparison.Ordinal)))
|
||||||
|
{
|
||||||
|
_selectedSpecificGroupIndividual = group.GID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (ImRaii.Disabled(string.IsNullOrEmpty(_selectedSpecificGroupIndividual)))
|
||||||
|
{
|
||||||
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Remove selected Syncshell"))
|
||||||
|
{
|
||||||
|
updateDto.RemoveGroupFromList(_selectedSpecificGroupIndividual);
|
||||||
|
_selectedSpecificGroupIndividual = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,4 +801,46 @@ internal sealed partial class CharaDataHubUi
|
|||||||
ImGuiHelpers.ScaledDummy(5);
|
ImGuiHelpers.ScaledDummy(5);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InputComboHybrid<T>(string inputId, string comboId, ref string value, IEnumerable<T> comboEntries,
|
||||||
|
Func<T, (string Id, string? Alias, string AliasOrId, string? Note)> parseEntry)
|
||||||
|
{
|
||||||
|
const float ComponentWidth = 200;
|
||||||
|
ImGui.SetNextItemWidth(ComponentWidth - ImGui.GetFrameHeight());
|
||||||
|
ImGui.InputText(inputId, ref value, 20);
|
||||||
|
ImGui.SameLine(0.0f, 0.0f);
|
||||||
|
|
||||||
|
using var combo = ImRaii.Combo(comboId, string.Empty, ImGuiComboFlags.NoPreview | ImGuiComboFlags.PopupAlignLeft);
|
||||||
|
if (!combo)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_openComboHybridEntries is null || !string.Equals(_openComboHybridId, comboId, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var valueSnapshot = value;
|
||||||
|
_openComboHybridEntries = comboEntries
|
||||||
|
.Select(parseEntry)
|
||||||
|
.Where(entry => entry.Id.Contains(valueSnapshot, StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| (entry.Alias is not null && entry.Alias.Contains(valueSnapshot, StringComparison.OrdinalIgnoreCase))
|
||||||
|
|| (entry.Note is not null && entry.Note.Contains(valueSnapshot, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
.OrderBy(entry => entry.Note is null ? entry.AliasOrId : $"{entry.Note} ({entry.AliasOrId})", StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
_openComboHybridId = comboId;
|
||||||
|
}
|
||||||
|
_comboHybridUsedLastFrame = true;
|
||||||
|
|
||||||
|
// Is there a better way to handle this?
|
||||||
|
var width = ComponentWidth - 2 * ImGui.GetStyle().FramePadding.X - (_openComboHybridEntries.Length > 8 ? ImGui.GetStyle().ScrollbarSize : 0);
|
||||||
|
foreach (var (id, alias, aliasOrId, note) in _openComboHybridEntries)
|
||||||
|
{
|
||||||
|
var selected = !string.IsNullOrEmpty(value)
|
||||||
|
&& (string.Equals(id, value, StringComparison.Ordinal) || string.Equals(alias, value, StringComparison.Ordinal));
|
||||||
|
using var font = ImRaii.PushFont(UiBuilder.MonoFont, note is null);
|
||||||
|
if (ImGui.Selectable(note is null ? aliasOrId : $"{note} ({aliasOrId})", selected, ImGuiSelectableFlags.None, new(width, 0)))
|
||||||
|
{
|
||||||
|
value = aliasOrId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -65,6 +65,14 @@ internal partial class CharaDataHubUi
|
|||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
_uiSharedService.DrawHelpText("This setting allows you to change the maximum distance in which poses will be shown. Set it to the maximum if you want to see all poses on the current map.");
|
_uiSharedService.DrawHelpText("This setting allows you to change the maximum distance in which poses will be shown. Set it to the maximum if you want to see all poses on the current map.");
|
||||||
|
bool alwaysShow = _configService.Current.NearbyShowAlways;
|
||||||
|
if (ImGui.Checkbox("Keep active outside Poses Nearby tab", ref alwaysShow))
|
||||||
|
{
|
||||||
|
_configService.Current.NearbyShowAlways = alwaysShow;
|
||||||
|
_configService.Save();
|
||||||
|
}
|
||||||
|
_uiSharedService.DrawHelpText("This will allow Mare to continue the calculation of position of wisps etc. active outside of the 'Poses Nearby' tab." + UiSharedService.TooltipSeparator
|
||||||
|
+ "Note: The wisps etc. will disappear during combat and performing.");
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!_uiSharedService.IsInGpose)
|
if (!_uiSharedService.IsInGpose)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using ImGuiNET;
|
|||||||
using MareSynchronos.API.Dto.CharaData;
|
using MareSynchronos.API.Dto.CharaData;
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
using MareSynchronos.MareConfiguration.Models;
|
using MareSynchronos.MareConfiguration.Models;
|
||||||
|
using MareSynchronos.PlayerData.Pairs;
|
||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
using MareSynchronos.Services.CharaData.Models;
|
using MareSynchronos.Services.CharaData.Models;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
@@ -24,6 +25,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
private readonly CharaDataConfigService _configService;
|
private readonly CharaDataConfigService _configService;
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
private readonly FileDialogManager _fileDialogManager;
|
private readonly FileDialogManager _fileDialogManager;
|
||||||
|
private readonly PairManager _pairManager;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly UiSharedService _uiSharedService;
|
private readonly UiSharedService _uiSharedService;
|
||||||
private CancellationTokenSource _closalCts = new();
|
private CancellationTokenSource _closalCts = new();
|
||||||
@@ -45,17 +47,22 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
private bool _openMcdOnlineOnNextRun = false;
|
private bool _openMcdOnlineOnNextRun = false;
|
||||||
private bool _readExport;
|
private bool _readExport;
|
||||||
private string _selectedDtoId = string.Empty;
|
private string _selectedDtoId = string.Empty;
|
||||||
private string _selectedSpecificIndividual = string.Empty;
|
private string _selectedSpecificUserIndividual = string.Empty;
|
||||||
|
private string _selectedSpecificGroupIndividual = string.Empty;
|
||||||
private string _sharedWithYouDescriptionFilter = string.Empty;
|
private string _sharedWithYouDescriptionFilter = string.Empty;
|
||||||
private bool _sharedWithYouDownloadableFilter = false;
|
private bool _sharedWithYouDownloadableFilter = false;
|
||||||
private string _sharedWithYouOwnerFilter = string.Empty;
|
private string _sharedWithYouOwnerFilter = string.Empty;
|
||||||
private string _specificIndividualAdd = string.Empty;
|
private string _specificIndividualAdd = string.Empty;
|
||||||
|
private string _specificGroupAdd = string.Empty;
|
||||||
private bool _abbreviateCharaName = false;
|
private bool _abbreviateCharaName = false;
|
||||||
|
private string? _openComboHybridId = null;
|
||||||
|
private (string Id, string? Alias, string AliasOrId, string? Note)[]? _openComboHybridEntries = null;
|
||||||
|
private bool _comboHybridUsedLastFrame = false;
|
||||||
|
|
||||||
public CharaDataHubUi(ILogger<CharaDataHubUi> logger, MareMediator mediator, PerformanceCollectorService performanceCollectorService,
|
public CharaDataHubUi(ILogger<CharaDataHubUi> logger, MareMediator mediator, PerformanceCollectorService performanceCollectorService,
|
||||||
CharaDataManager charaDataManager, CharaDataNearbyManager charaDataNearbyManager, CharaDataConfigService configService,
|
CharaDataManager charaDataManager, CharaDataNearbyManager charaDataNearbyManager, CharaDataConfigService configService,
|
||||||
UiSharedService uiSharedService, ServerConfigurationManager serverConfigurationManager,
|
UiSharedService uiSharedService, ServerConfigurationManager serverConfigurationManager,
|
||||||
DalamudUtilService dalamudUtilService, FileDialogManager fileDialogManager)
|
DalamudUtilService dalamudUtilService, FileDialogManager fileDialogManager, PairManager pairManager)
|
||||||
: base(logger, mediator, "Mare Synchronos Character Data Hub###MareSynchronosCharaDataUI", performanceCollectorService)
|
: base(logger, mediator, "Mare Synchronos Character Data Hub###MareSynchronosCharaDataUI", performanceCollectorService)
|
||||||
{
|
{
|
||||||
SetWindowSizeConstraints();
|
SetWindowSizeConstraints();
|
||||||
@@ -67,6 +74,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_dalamudUtilService = dalamudUtilService;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_fileDialogManager = fileDialogManager;
|
_fileDialogManager = fileDialogManager;
|
||||||
|
_pairManager = pairManager;
|
||||||
Mediator.Subscribe<GposeStartMessage>(this, (_) => IsOpen |= _configService.Current.OpenMareHubOnGposeStart);
|
Mediator.Subscribe<GposeStartMessage>(this, (_) => IsOpen |= _configService.Current.OpenMareHubOnGposeStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +103,8 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
_sharedWithYouOwnerFilter = string.Empty;
|
_sharedWithYouOwnerFilter = string.Empty;
|
||||||
_importCode = string.Empty;
|
_importCode = string.Empty;
|
||||||
_charaDataNearbyManager.ComputeNearbyData = false;
|
_charaDataNearbyManager.ComputeNearbyData = false;
|
||||||
|
_openComboHybridId = null;
|
||||||
|
_openComboHybridEntries = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnOpen()
|
public override void OnOpen()
|
||||||
@@ -115,6 +125,13 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
protected override void DrawInternal()
|
protected override void DrawInternal()
|
||||||
{
|
{
|
||||||
|
if (!_comboHybridUsedLastFrame)
|
||||||
|
{
|
||||||
|
_openComboHybridId = null;
|
||||||
|
_openComboHybridEntries = null;
|
||||||
|
}
|
||||||
|
_comboHybridUsedLastFrame = false;
|
||||||
|
|
||||||
_disableUI = !(_charaDataManager.UiBlockingComputation?.IsCompleted ?? true);
|
_disableUI = !(_charaDataManager.UiBlockingComputation?.IsCompleted ?? true);
|
||||||
if (DateTime.UtcNow.Subtract(_lastFavoriteUpdateTime).TotalSeconds > 2)
|
if (DateTime.UtcNow.Subtract(_lastFavoriteUpdateTime).TotalSeconds > 2)
|
||||||
{
|
{
|
||||||
@@ -588,6 +605,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
DrawAddOrRemoveFavorite(_charaDataManager.LastDownloadedMetaInfo);
|
DrawAddOrRemoveFavorite(_charaDataManager.LastDownloadedMetaInfo);
|
||||||
|
|
||||||
|
ImGui.NewLine();
|
||||||
if (!_charaDataManager.DownloadMetaInfoTask?.IsCompleted ?? false)
|
if (!_charaDataManager.DownloadMetaInfoTask?.IsCompleted ?? false)
|
||||||
{
|
{
|
||||||
UiSharedService.ColorTextWrapped("Downloading meta info. Please wait.", ImGuiColors.DalamudYellow);
|
UiSharedService.ColorTextWrapped("Downloading meta info. Please wait.", ImGuiColors.DalamudYellow);
|
||||||
@@ -666,7 +684,8 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
DrawHelpFoldout("You can apply character data shared with you implicitly in this tab. Shared Character Data are Character Data entries that have \"Sharing\" set to \"Shared\" and you have access through those by meeting the access restrictions, " +
|
DrawHelpFoldout("You can apply character data shared with you implicitly in this tab. Shared Character Data are Character Data entries that have \"Sharing\" set to \"Shared\" and you have access through those by meeting the access restrictions, " +
|
||||||
"i.e. you were specified by your UID to gain access or are paired with the other user according to the Access Restrictions setting." + Environment.NewLine + Environment.NewLine
|
"i.e. you were specified by your UID to gain access or are paired with the other user according to the Access Restrictions setting." + Environment.NewLine + Environment.NewLine
|
||||||
+ "Filter if needed to find a specific entry, then just press on \"Apply to <actor>\" and it will download and apply the Character Data to the currently targeted GPose actor.");
|
+ "Filter if needed to find a specific entry, then just press on \"Apply to <actor>\" and it will download and apply the Character Data to the currently targeted GPose actor." + Environment.NewLine + Environment.NewLine
|
||||||
|
+ "Note: Shared Data of Pairs you have paused will not be shown here.");
|
||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(5);
|
ImGuiHelpers.ScaledDummy(5);
|
||||||
|
|
||||||
|
|||||||
@@ -1367,7 +1367,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
using (ImRaii.Disabled(string.IsNullOrEmpty(_uidToAddForIgnore)))
|
using (ImRaii.Disabled(string.IsNullOrEmpty(_uidToAddForIgnore)))
|
||||||
{
|
{
|
||||||
ImGui.SetCursorPosX(240 * ImGuiHelpers.GlobalScale);
|
ImGui.SetCursorPosX(240 * ImGuiHelpers.GlobalScale);
|
||||||
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Add UID to whitelist"))
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Add UID/Vanity ID to whitelist"))
|
||||||
{
|
{
|
||||||
if (!_serverConfigurationManager.IsUidWhitelisted(_uidToAddForIgnore))
|
if (!_serverConfigurationManager.IsUidWhitelisted(_uidToAddForIgnore))
|
||||||
{
|
{
|
||||||
@@ -1432,7 +1432,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
using (ImRaii.Disabled(string.IsNullOrEmpty(_uidToAddForIgnoreBlacklist)))
|
using (ImRaii.Disabled(string.IsNullOrEmpty(_uidToAddForIgnoreBlacklist)))
|
||||||
{
|
{
|
||||||
ImGui.SetCursorPosX(240 * ImGuiHelpers.GlobalScale);
|
ImGui.SetCursorPosX(240 * ImGuiHelpers.GlobalScale);
|
||||||
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Add UID to blacklist"))
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Add UID/Vanity ID to blacklist"))
|
||||||
{
|
{
|
||||||
if (!_serverConfigurationManager.IsUidBlacklisted(_uidToAddForIgnoreBlacklist))
|
if (!_serverConfigurationManager.IsUidBlacklisted(_uidToAddForIgnoreBlacklist))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user