FINALY !!!
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,6 +9,7 @@
|
|||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|||||||
BIN
MareSynchronos/.DS_Store
vendored
BIN
MareSynchronos/.DS_Store
vendored
Binary file not shown.
@@ -236,7 +236,6 @@ public sealed class FileCacheManager : IHostedService
|
|||||||
|
|
||||||
foreach (var entry in cleanedPaths)
|
foreach (var entry in cleanedPaths)
|
||||||
{
|
{
|
||||||
//_logger.LogDebug("Checking {path}", entry.Value);
|
|
||||||
|
|
||||||
if (dict.TryGetValue(entry.Value, out var entity))
|
if (dict.TryGetValue(entry.Value, out var entity))
|
||||||
{
|
{
|
||||||
@@ -366,8 +365,7 @@ public sealed class FileCacheManager : IHostedService
|
|||||||
|
|
||||||
if (!entries.Exists(u => string.Equals(u.PrefixedFilePath, fileCache.PrefixedFilePath, StringComparison.OrdinalIgnoreCase)))
|
if (!entries.Exists(u => string.Equals(u.PrefixedFilePath, fileCache.PrefixedFilePath, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
//_logger.LogTrace("Adding to DB: {hash} => {path}", fileCache.Hash, fileCache.PrefixedFilePath);
|
entries.Add(fileCache);
|
||||||
entries.Add(fileCache);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +387,6 @@ public sealed class FileCacheManager : IHostedService
|
|||||||
private FileCacheEntity? GetValidatedFileCache(FileCacheEntity fileCache)
|
private FileCacheEntity? GetValidatedFileCache(FileCacheEntity fileCache)
|
||||||
{
|
{
|
||||||
var resultingFileCache = ReplacePathPrefixes(fileCache);
|
var resultingFileCache = ReplacePathPrefixes(fileCache);
|
||||||
//_logger.LogTrace("Validating {path}", fileCache.PrefixedFilePath);
|
|
||||||
resultingFileCache = Validate(resultingFileCache);
|
resultingFileCache = Validate(resultingFileCache);
|
||||||
return resultingFileCache;
|
return resultingFileCache;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,8 +95,6 @@ public sealed class IpcCallerBrio : IIpcCaller
|
|||||||
if (gameObject == null) return default;
|
if (gameObject == null) return default;
|
||||||
var data = await _dalamudUtilService.RunOnFrameworkThread(() => _brioGetModelTransform.InvokeFunc(gameObject)).ConfigureAwait(false);
|
var data = await _dalamudUtilService.RunOnFrameworkThread(() => _brioGetModelTransform.InvokeFunc(gameObject)).ConfigureAwait(false);
|
||||||
if (data.Item1 == null || data.Item2 == null || data.Item3 == null) return default;
|
if (data.Item1 == null || data.Item2 == null || data.Item3 == null) return default;
|
||||||
//_logger.LogDebug("Getting Transform from Actor {actor}", gameObject.Name.TextValue);
|
|
||||||
|
|
||||||
return new WorldData()
|
return new WorldData()
|
||||||
{
|
{
|
||||||
PositionX = data.Item1.Value.X,
|
PositionX = data.Item1.Value.X,
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ public sealed class IpcCallerMoodles : IIpcCaller
|
|||||||
|
|
||||||
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
|
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
|
||||||
_moodlesOnChange = pi.GetIpcSubscriber<IPlayerCharacter, object>("Moodles.StatusManagerModified");
|
_moodlesOnChange = pi.GetIpcSubscriber<IPlayerCharacter, object>("Moodles.StatusManagerModified");
|
||||||
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtr");
|
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtrV2");
|
||||||
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtr");
|
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtrV2");
|
||||||
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtr");
|
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtrV2");
|
||||||
|
|
||||||
_moodlesOnChange.Subscribe(OnMoodlesChange);
|
_moodlesOnChange.Subscribe(OnMoodlesChange);
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ public sealed class IpcCallerMoodles : IIpcCaller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
APIAvailable = _moodlesApiVersion.InvokeFunc() == 1;
|
APIAvailable = _moodlesApiVersion.InvokeFunc() == 3;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ public sealed class IpcCallerPetNames : IIpcCaller
|
|||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
_mareMediator = mareMediator;
|
_mareMediator = mareMediator;
|
||||||
|
|
||||||
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.Ready");
|
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.OnReady");
|
||||||
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.Disposing");
|
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.OnDisposing");
|
||||||
_apiVersion = pi.GetIpcSubscriber<(uint, uint)>("PetRenamer.ApiVersion");
|
_apiVersion = pi.GetIpcSubscriber<(uint, uint)>("PetRenamer.ApiVersion");
|
||||||
_enabled = pi.GetIpcSubscriber<bool>("PetRenamer.Enabled");
|
_enabled = pi.GetIpcSubscriber<bool>("PetRenamer.IsEnabled");
|
||||||
|
|
||||||
_playerDataChanged = pi.GetIpcSubscriber<string, object>("PetRenamer.PlayerDataChanged");
|
_playerDataChanged = pi.GetIpcSubscriber<string, object>("PetRenamer.OnPlayerDataChanged");
|
||||||
_getPlayerData = pi.GetIpcSubscriber<string>("PetRenamer.GetPlayerData");
|
_getPlayerData = pi.GetIpcSubscriber<string>("PetRenamer.GetPlayerData");
|
||||||
_setPlayerData = pi.GetIpcSubscriber<string, object>("PetRenamer.SetPlayerData");
|
_setPlayerData = pi.GetIpcSubscriber<string, object>("PetRenamer.SetPlayerData");
|
||||||
_clearPlayerData = pi.GetIpcSubscriber<ushort, object>("PetRenamer.ClearPlayerData");
|
_clearPlayerData = pi.GetIpcSubscriber<ushort, object>("PetRenamer.ClearPlayerData");
|
||||||
@@ -56,7 +56,7 @@ public sealed class IpcCallerPetNames : IIpcCaller
|
|||||||
APIAvailable = _enabled?.InvokeFunc() ?? false;
|
APIAvailable = _enabled?.InvokeFunc() ?? false;
|
||||||
if (APIAvailable)
|
if (APIAvailable)
|
||||||
{
|
{
|
||||||
APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 3, Item2: >= 1 };
|
APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 4, Item2: >= 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ public static class ConfigurationExtensions
|
|||||||
{
|
{
|
||||||
return configuration.AcceptedAgreement && configuration.InitialScanComplete
|
return configuration.AcceptedAgreement && configuration.InitialScanComplete
|
||||||
&& !string.IsNullOrEmpty(configuration.CacheFolder)
|
&& !string.IsNullOrEmpty(configuration.CacheFolder)
|
||||||
&& Directory.Exists(configuration.CacheFolder) && configuration.AcceptedTOSVersion == configuration.ExpectedTOSVersion;
|
&& Directory.Exists(configuration.CacheFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>UmbraSync</AssemblyName>
|
<AssemblyName>UmbraSync</AssemblyName>
|
||||||
<Version>0.1.0.0</Version>
|
<RootNamespace>UmbraSync</RootNamespace>
|
||||||
<PackageProjectUrl>https://git.umbra-sync.net/SirConstance/UmbraClient</PackageProjectUrl>
|
<Version>0.1.1.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="PlayerData\Export\**" />
|
<Compile Remove="PlayerData\Export\**" />
|
||||||
|
|||||||
@@ -27,14 +27,13 @@ public class PairHandlerFactory
|
|||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
|
|
||||||
public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager,
|
public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager,
|
||||||
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,
|
ServerConfigurationManager serverConfigManager, PairAnalyzerFactory pairAnalyzerFactory,
|
||||||
MareConfigService configService, VisibilityService visibilityService, NoSnapService noSnapService)
|
MareConfigService configService, VisibilityService visibilityService)
|
||||||
{
|
{
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
||||||
@@ -50,13 +49,12 @@ public class PairHandlerFactory
|
|||||||
_pairAnalyzerFactory = pairAnalyzerFactory;
|
_pairAnalyzerFactory = pairAnalyzerFactory;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PairHandler Create(Pair pair)
|
public PairHandler Create(Pair pair)
|
||||||
{
|
{
|
||||||
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, _noSnapService);
|
_fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
private readonly ServerConfigurationManager _serverConfigManager;
|
private readonly ServerConfigurationManager _serverConfigManager;
|
||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
||||||
private Guid _applicationId;
|
private Guid _applicationId;
|
||||||
private Task? _applicationTask;
|
private Task? _applicationTask;
|
||||||
@@ -55,8 +54,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
FileCacheManager fileDbManager, MareMediator mediator,
|
FileCacheManager fileDbManager, MareMediator mediator,
|
||||||
PlayerPerformanceService playerPerformanceService,
|
PlayerPerformanceService playerPerformanceService,
|
||||||
ServerConfigurationManager serverConfigManager,
|
ServerConfigurationManager serverConfigManager,
|
||||||
MareConfigService configService, VisibilityService visibilityService,
|
MareConfigService configService, VisibilityService visibilityService) : base(logger, mediator)
|
||||||
NoSnapService noSnapService) : base(logger, mediator)
|
|
||||||
{
|
{
|
||||||
Pair = pair;
|
Pair = pair;
|
||||||
PairAnalyzer = pairAnalyzer;
|
PairAnalyzer = pairAnalyzer;
|
||||||
@@ -70,7 +68,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
_serverConfigManager = serverConfigManager;
|
_serverConfigManager = serverConfigManager;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
|
|
||||||
_visibilityService.StartTracking(Pair.Ident);
|
_visibilityService.StartTracking(Pair.Ident);
|
||||||
|
|
||||||
@@ -319,24 +316,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterGposeClones()
|
|
||||||
{
|
|
||||||
var name = PlayerName;
|
|
||||||
if (name == null)
|
|
||||||
return;
|
|
||||||
_ = _dalamudUtil.RunOnFrameworkThread(() =>
|
|
||||||
{
|
|
||||||
foreach (var actor in _dalamudUtil.GetGposeCharactersFromObjectTable())
|
|
||||||
{
|
|
||||||
if (actor == null) continue;
|
|
||||||
var gposeName = actor.Name.TextValue;
|
|
||||||
if (!name.Equals(gposeName, StringComparison.Ordinal))
|
|
||||||
continue;
|
|
||||||
_noSnapService.AddGposer(actor.ObjectIndex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UndoApplicationAsync(Guid applicationId = default)
|
private async Task UndoApplicationAsync(Guid applicationId = default)
|
||||||
{
|
{
|
||||||
Logger.LogDebug($"Undoing application of {Pair.UserPair}");
|
Logger.LogDebug($"Undoing application of {Pair.UserPair}");
|
||||||
@@ -353,7 +332,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
await _ipcManager.Penumbra.RemoveTemporaryCollectionAsync(Logger, applicationId, _penumbraCollection).ConfigureAwait(false);
|
await _ipcManager.Penumbra.RemoveTemporaryCollectionAsync(Logger, applicationId, _penumbraCollection).ConfigureAwait(false);
|
||||||
_penumbraCollection = Guid.Empty;
|
_penumbraCollection = Guid.Empty;
|
||||||
RegisterGposeClones();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dalamudUtil is { IsZoning: false, IsInCutscene: false } && !string.IsNullOrEmpty(name))
|
if (_dalamudUtil is { IsZoning: false, IsInCutscene: false } && !string.IsNullOrEmpty(name))
|
||||||
@@ -385,10 +363,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_dalamudUtil.IsInCutscene && !string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
_noSnapService.AddGposerNamed(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -171,11 +171,6 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID))
|
if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID))
|
||||||
HoldApplication("Blacklist", maxValue: 1);
|
HoldApplication("Blacklist", maxValue: 1);
|
||||||
|
|
||||||
if (NoSnapService.AnyLoaded)
|
|
||||||
HoldApplication("NoSnap", maxValue: 1);
|
|
||||||
else
|
|
||||||
UnholdApplication("NoSnap", skipApplication: true);
|
|
||||||
|
|
||||||
CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced);
|
CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
public static Plugin Self;
|
public static Plugin Self;
|
||||||
#pragma warning restore CA2211, CS8618, MA0069, S1104, S2223
|
#pragma warning restore CA2211, CS8618, MA0069, S1104, S2223
|
||||||
public Action<IFramework>? RealOnFrameworkUpdate { get; set; }
|
public Action<IFramework>? RealOnFrameworkUpdate { get; set; }
|
||||||
|
|
||||||
// Proxy function in the UmbraSync namespace to avoid confusion in /xlstats
|
|
||||||
public void OnFrameworkUpdate(IFramework framework)
|
public void OnFrameworkUpdate(IFramework framework)
|
||||||
{
|
{
|
||||||
RealOnFrameworkUpdate?.Invoke(framework);
|
RealOnFrameworkUpdate?.Invoke(framework);
|
||||||
@@ -142,7 +140,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<IpcCallerMare>();
|
collection.AddSingleton<IpcCallerMare>();
|
||||||
collection.AddSingleton<IpcManager>();
|
collection.AddSingleton<IpcManager>();
|
||||||
collection.AddSingleton<NotificationService>();
|
collection.AddSingleton<NotificationService>();
|
||||||
collection.AddSingleton<NoSnapService>();
|
|
||||||
|
|
||||||
collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName));
|
collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName));
|
||||||
collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName));
|
collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName));
|
||||||
@@ -168,7 +165,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<IConfigService<IMareConfiguration>>(s => s.GetRequiredService<RemoteConfigCacheService>());
|
collection.AddSingleton<IConfigService<IMareConfiguration>>(s => s.GetRequiredService<RemoteConfigCacheService>());
|
||||||
collection.AddSingleton<ConfigurationMigrator>();
|
collection.AddSingleton<ConfigurationMigrator>();
|
||||||
collection.AddSingleton<ConfigurationSaveService>();
|
collection.AddSingleton<ConfigurationSaveService>();
|
||||||
collection.AddSingleton<RemoteConfigurationService>();
|
|
||||||
|
|
||||||
collection.AddSingleton<HubFactory>();
|
collection.AddSingleton<HubFactory>();
|
||||||
|
|
||||||
@@ -209,7 +205,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
|
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<NoSnapService>());
|
|
||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -13,20 +13,18 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
private readonly IpcManager _ipcManager;
|
private readonly IpcManager _ipcManager;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
private readonly Dictionary<string, HandledCharaDataEntry> _handledCharaData = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, HandledCharaDataEntry> _handledCharaData = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, HandledCharaDataEntry> HandledCharaData => _handledCharaData;
|
public IReadOnlyDictionary<string, HandledCharaDataEntry> HandledCharaData => _handledCharaData;
|
||||||
|
|
||||||
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> logger, MareMediator mediator,
|
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> logger, MareMediator mediator,
|
||||||
GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService,
|
GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService,
|
||||||
IpcManager ipcManager, NoSnapService noSnapService)
|
IpcManager ipcManager)
|
||||||
: base(logger, mediator)
|
: base(logger, mediator)
|
||||||
{
|
{
|
||||||
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
||||||
_dalamudUtilService = dalamudUtilService;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
mediator.Subscribe<GposeEndMessage>(this, msg =>
|
mediator.Subscribe<GposeEndMessage>(this, msg =>
|
||||||
{
|
{
|
||||||
foreach (var chara in _handledCharaData)
|
foreach (var chara in _handledCharaData)
|
||||||
@@ -94,7 +92,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
_handledCharaData.Remove(handled.Name);
|
_handledCharaData.Remove(handled.Name);
|
||||||
await _dalamudUtilService.RunOnFrameworkThread(async () =>
|
await _dalamudUtilService.RunOnFrameworkThread(async () =>
|
||||||
{
|
{
|
||||||
RemoveGposer(handled);
|
|
||||||
await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false);
|
await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false);
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
return true;
|
return true;
|
||||||
@@ -103,7 +100,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry)
|
internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry)
|
||||||
{
|
{
|
||||||
_handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry);
|
_handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry);
|
||||||
_ = _dalamudUtilService.RunOnFrameworkThread(() => AddGposer(handledCharaDataEntry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateHandledData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
public void UpdateHandledData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
||||||
@@ -134,23 +130,4 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
if (handler.Address == nint.Zero) return null;
|
if (handler.Address == nint.Zero) return null;
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGposerObjectIndex(string name)
|
|
||||||
{
|
|
||||||
return _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, _dalamudUtilService.IsInGpose)?.ObjectIndex ?? -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddGposer(HandledCharaDataEntry handled)
|
|
||||||
{
|
|
||||||
int objectIndex = GetGposerObjectIndex(handled.Name);
|
|
||||||
if (objectIndex > 0)
|
|
||||||
_noSnapService.AddGposer(objectIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveGposer(HandledCharaDataEntry handled)
|
|
||||||
{
|
|
||||||
int objectIndex = GetGposerObjectIndex(handled.Name);
|
|
||||||
if (objectIndex > 0)
|
|
||||||
_noSnapService.RemoveGposer(objectIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class ChatService : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
var chatMsg = message.ChatMsg;
|
var chatMsg = message.ChatMsg;
|
||||||
var prefix = new SeStringBuilder();
|
var prefix = new SeStringBuilder();
|
||||||
prefix.AddText("[BnnuyChat] ");
|
prefix.AddText("[UmbraChat] ");
|
||||||
_chatGui.Print(new XivChatEntry{
|
_chatGui.Print(new XivChatEntry{
|
||||||
MessageBytes = [..prefix.Build().Encode(), ..message.ChatMsg.PayloadContent],
|
MessageBytes = [..prefix.Build().Encode(), ..message.ChatMsg.PayloadContent],
|
||||||
Name = chatMsg.SenderName,
|
Name = chatMsg.SenderName,
|
||||||
@@ -207,7 +207,7 @@ public class ChatService : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_chatGui.PrintError($"[Umbra] Syncshell number #{shellNumber} not found");
|
_chatGui.PrintError($"[UmbraSync] Syncshell number #{shellNumber} not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendChatShell(int shellNumber, byte[] chatBytes)
|
public void SendChatShell(int shellNumber, byte[] chatBytes)
|
||||||
@@ -236,6 +236,6 @@ public class ChatService : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_chatGui.PrintError($"[Umbra] Syncshell number #{shellNumber} not found");
|
_chatGui.PrintError($"[UmbraSync] Syncshell number #{shellNumber} not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ namespace MareSynchronos.Services;
|
|||||||
public sealed class CommandManagerService : IDisposable
|
public sealed class CommandManagerService : IDisposable
|
||||||
{
|
{
|
||||||
private const string _commandName = "/sync";
|
private const string _commandName = "/sync";
|
||||||
private const string _commandName2 = "/snowcloak";
|
private const string _commandName2 = "/usync";
|
||||||
|
|
||||||
private const string _ssCommandPrefix = "/ss";
|
private const string _ssCommandPrefix = "/ss";
|
||||||
|
|
||||||
|
|||||||
@@ -1,226 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using MareSynchronos.Interop.Ipc;
|
|
||||||
using MareSynchronos.MareConfiguration.Models;
|
|
||||||
using MareSynchronos.Services.Mediator;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MareSynchronos.Services;
|
|
||||||
|
|
||||||
public sealed class NoSnapService : IHostedService, IMediatorSubscriber
|
|
||||||
{
|
|
||||||
private record NoSnapConfig
|
|
||||||
{
|
|
||||||
[JsonPropertyName("listOfPlugins")]
|
|
||||||
public string[]? ListOfPlugins { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ILogger<NoSnapService> _logger;
|
|
||||||
private readonly IDalamudPluginInterface _pluginInterface;
|
|
||||||
private readonly Dictionary<string, bool> _listOfPlugins = new(StringComparer.Ordinal)
|
|
||||||
{
|
|
||||||
["Snapper"] = false,
|
|
||||||
["Snappy"] = false,
|
|
||||||
["Meddle.Plugin"] = false,
|
|
||||||
};
|
|
||||||
private static readonly HashSet<int> _gposers = new();
|
|
||||||
private static readonly HashSet<string> _gposersNamed = new(StringComparer.Ordinal);
|
|
||||||
private readonly IHostApplicationLifetime _hostApplicationLifetime;
|
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
|
||||||
private readonly IpcManager _ipcManager;
|
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
|
|
||||||
public static bool AnyLoaded { get; private set; } = false;
|
|
||||||
public static string ActivePlugins { get; private set; } = string.Empty;
|
|
||||||
|
|
||||||
public MareMediator Mediator { get; init; }
|
|
||||||
|
|
||||||
public NoSnapService(ILogger<NoSnapService> logger, IDalamudPluginInterface pluginInterface, MareMediator mediator,
|
|
||||||
IHostApplicationLifetime hostApplicationLifetime, DalamudUtilService dalamudUtilService, IpcManager ipcManager,
|
|
||||||
RemoteConfigurationService remoteConfig)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_pluginInterface = pluginInterface;
|
|
||||||
Mediator = mediator;
|
|
||||||
_hostApplicationLifetime = hostApplicationLifetime;
|
|
||||||
_dalamudUtilService = dalamudUtilService;
|
|
||||||
_ipcManager = ipcManager;
|
|
||||||
_remoteConfig = remoteConfig;
|
|
||||||
|
|
||||||
Mediator.Subscribe<GposeEndMessage>(this, msg => ClearGposeList());
|
|
||||||
Mediator.Subscribe<CutsceneEndMessage>(this, msg => ClearGposeList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddGposer(int objectIndex)
|
|
||||||
{
|
|
||||||
if (AnyLoaded || _hostApplicationLifetime.ApplicationStopping.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Immediately reverting object index {id}", objectIndex);
|
|
||||||
RevertAndRedraw(objectIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogTrace("Registering gposer object index {id}", objectIndex);
|
|
||||||
lock (_gposers)
|
|
||||||
_gposers.Add(objectIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveGposer(int objectIndex)
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Un-registering gposer object index {id}", objectIndex);
|
|
||||||
lock (_gposers)
|
|
||||||
_gposers.Remove(objectIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddGposerNamed(string name)
|
|
||||||
{
|
|
||||||
if (AnyLoaded || _hostApplicationLifetime.ApplicationStopping.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Immediately reverting {name}", name);
|
|
||||||
RevertAndRedraw(name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogTrace("Registering gposer {name}", name);
|
|
||||||
lock (_gposers)
|
|
||||||
_gposersNamed.Add(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearGposeList()
|
|
||||||
{
|
|
||||||
if (_gposers.Count > 0 || _gposersNamed.Count > 0)
|
|
||||||
_logger.LogTrace("Clearing gposer list");
|
|
||||||
lock (_gposers)
|
|
||||||
_gposers.Clear();
|
|
||||||
lock (_gposersNamed)
|
|
||||||
_gposersNamed.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RevertAndRedraw(int objIndex, Guid applicationId = default)
|
|
||||||
{
|
|
||||||
if (applicationId == default)
|
|
||||||
applicationId = Guid.NewGuid();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_ipcManager.Glamourer.RevertNow(_logger, applicationId, objIndex);
|
|
||||||
_ipcManager.Penumbra.RedrawNow(_logger, applicationId, objIndex);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RevertAndRedraw(string name, Guid applicationId = default)
|
|
||||||
{
|
|
||||||
if (applicationId == default)
|
|
||||||
applicationId = Guid.NewGuid();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_ipcManager.Glamourer.RevertByNameNow(_logger, applicationId, name);
|
|
||||||
var addr = _dalamudUtilService.GetPlayerCharacterFromCachedTableByName(name);
|
|
||||||
if (addr != 0)
|
|
||||||
{
|
|
||||||
var obj = _dalamudUtilService.CreateGameObject(addr);
|
|
||||||
if (obj != null)
|
|
||||||
_ipcManager.Penumbra.RedrawNow(_logger, applicationId, obj.ObjectIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RevertGposers()
|
|
||||||
{
|
|
||||||
List<int>? gposersList = null;
|
|
||||||
List<string>? gposersList2 = null;
|
|
||||||
|
|
||||||
lock (_gposers)
|
|
||||||
{
|
|
||||||
if (_gposers.Count > 0)
|
|
||||||
{
|
|
||||||
gposersList = _gposers.ToList();
|
|
||||||
_gposers.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_gposersNamed)
|
|
||||||
{
|
|
||||||
if (_gposersNamed.Count > 0)
|
|
||||||
{
|
|
||||||
gposersList2 = _gposersNamed.ToList();
|
|
||||||
_gposersNamed.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gposersList == null && gposersList2 == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_logger.LogInformation("Reverting gposers");
|
|
||||||
|
|
||||||
_dalamudUtilService.RunOnFrameworkThread(() =>
|
|
||||||
{
|
|
||||||
Guid applicationId = Guid.NewGuid();
|
|
||||||
|
|
||||||
foreach (var gposer in gposersList ?? [])
|
|
||||||
RevertAndRedraw(gposer, applicationId);
|
|
||||||
|
|
||||||
foreach (var gposerName in gposersList2 ?? [])
|
|
||||||
RevertAndRedraw(gposerName, applicationId);
|
|
||||||
}).GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var config = await _remoteConfig.GetConfigAsync<NoSnapConfig>("noSnap").ConfigureAwait(false) ?? new();
|
|
||||||
|
|
||||||
if (config.ListOfPlugins != null)
|
|
||||||
{
|
|
||||||
_listOfPlugins.Clear();
|
|
||||||
foreach (var pluginName in config.ListOfPlugins)
|
|
||||||
_listOfPlugins.TryAdd(pluginName, value: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var pluginName in _listOfPlugins.Keys)
|
|
||||||
{
|
|
||||||
_listOfPlugins[pluginName] = PluginWatcherService.GetInitialPluginState(_pluginInterface, pluginName)?.IsLoaded ?? false;
|
|
||||||
Mediator.SubscribeKeyed<PluginChangeMessage>(this, pluginName, (msg) =>
|
|
||||||
{
|
|
||||||
_listOfPlugins[pluginName] = msg.IsLoaded;
|
|
||||||
_logger.LogDebug("{pluginName} isLoaded = {isLoaded}", pluginName, msg.IsLoaded);
|
|
||||||
Update();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
RevertGposers();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
bool anyLoadedNow = _listOfPlugins.Values.Any(p => p);
|
|
||||||
|
|
||||||
if (AnyLoaded != anyLoadedNow)
|
|
||||||
{
|
|
||||||
AnyLoaded = anyLoadedNow;
|
|
||||||
Mediator.Publish(new RecalculatePerformanceMessage(null));
|
|
||||||
|
|
||||||
if (AnyLoaded)
|
|
||||||
{
|
|
||||||
RevertGposers();
|
|
||||||
var pluginList = string.Join(", ", _listOfPlugins.Where(p => p.Value).Select(p => p.Key));
|
|
||||||
Mediator.Publish(new NotificationMessage("Incompatible plugin loaded", $"Synced player appearances will not apply until incompatible plugins are disabled: {pluginList}.",
|
|
||||||
NotificationType.Error));
|
|
||||||
ActivePlugins = pluginList;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ActivePlugins = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -41,19 +41,19 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ
|
|||||||
|
|
||||||
private void PrintErrorChat(string? message)
|
private void PrintErrorChat(string? message)
|
||||||
{
|
{
|
||||||
SeStringBuilder se = new SeStringBuilder().AddText("[Umbra] Error: " + message);
|
SeStringBuilder se = new SeStringBuilder().AddText("[UmbraSync] Error: " + message);
|
||||||
_chatGui.PrintError(se.BuiltString);
|
_chatGui.PrintError(se.BuiltString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintInfoChat(string? message)
|
private void PrintInfoChat(string? message)
|
||||||
{
|
{
|
||||||
SeStringBuilder se = new SeStringBuilder().AddText("[Umbra] Info: ").AddItalics(message ?? string.Empty);
|
SeStringBuilder se = new SeStringBuilder().AddText("[UmbraSync] Info: ").AddItalics(message ?? string.Empty);
|
||||||
_chatGui.Print(se.BuiltString);
|
_chatGui.Print(se.BuiltString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintWarnChat(string? message)
|
private void PrintWarnChat(string? message)
|
||||||
{
|
{
|
||||||
SeStringBuilder se = new SeStringBuilder().AddText("[Umbra] ").AddUiForeground("Warning: " + (message ?? string.Empty), 31).AddUiForegroundOff();
|
SeStringBuilder se = new SeStringBuilder().AddText("[UmbraSync] ").AddUiForeground("Warning: " + (message ?? string.Empty), 31).AddUiForegroundOff();
|
||||||
_chatGui.Print(se.BuiltString);
|
_chatGui.Print(se.BuiltString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace MareSynchronos.Services
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Stub minimal : renvoie toujours null (pas de conf distante).
|
|
||||||
/// </summary>
|
|
||||||
public class RemoteConfigurationService
|
|
||||||
{
|
|
||||||
private readonly ILogger<RemoteConfigurationService> _logger;
|
|
||||||
|
|
||||||
public RemoteConfigurationService(ILogger<RemoteConfigurationService> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T?> GetConfigAsync<T>(string key) where T : class
|
|
||||||
=> Task.FromResult<T?>(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -60,7 +60,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService,
|
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService,
|
||||||
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager,
|
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager,
|
||||||
PerformanceCollectorService performanceCollectorService)
|
PerformanceCollectorService performanceCollectorService)
|
||||||
: base(logger, mediator, "###UmbraSyncMainUI", performanceCollectorService)
|
: base(logger, mediator, "###UmbraSyncSyncMainUI", performanceCollectorService)
|
||||||
{
|
{
|
||||||
_uiSharedService = uiShared;
|
_uiSharedService = uiShared;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
@@ -80,11 +80,11 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
string dev = "Dev Build";
|
string dev = "Dev Build";
|
||||||
var ver = Assembly.GetExecutingAssembly().GetName().Version!;
|
var ver = Assembly.GetExecutingAssembly().GetName().Version!;
|
||||||
WindowName = $"Umbra Sync {dev} ({ver.Major}.{ver.Minor}.{ver.Build})###UmbraSyncMainUIDev";
|
WindowName = $"UmbraSync {dev} ({ver.Major}.{ver.Minor}.{ver.Build})###UmbraSyncSyncMainUIDev";
|
||||||
Toggle();
|
Toggle();
|
||||||
#else
|
#else
|
||||||
var ver = Assembly.GetExecutingAssembly().GetName().Version!;
|
var ver = Assembly.GetExecutingAssembly().GetName().Version!;
|
||||||
WindowName = "Umbra Sync " + ver.Major + "." + ver.Minor + "." + ver.Build + "###UmbraSyncMainUI";
|
WindowName = "UmbraSync " + ver.Major + "." + ver.Minor + "." + ver.Build + "###UmbraSyncSyncMainUI";
|
||||||
#endif
|
#endif
|
||||||
Mediator.Subscribe<SwitchToMainUiMessage>(this, (_) => IsOpen = true);
|
Mediator.Subscribe<SwitchToMainUiMessage>(this, (_) => IsOpen = true);
|
||||||
Mediator.Subscribe<SwitchToIntroUiMessage>(this, (_) => IsOpen = false);
|
Mediator.Subscribe<SwitchToIntroUiMessage>(this, (_) => IsOpen = false);
|
||||||
@@ -104,10 +104,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
protected override void DrawInternal()
|
protected override void DrawInternal()
|
||||||
{
|
{
|
||||||
if (_serverManager.CurrentApiUrl.Equals(ApiController.UmbraServiceUri, StringComparison.Ordinal))
|
UiSharedService.AccentColor = new Vector4(0.2f, 0.6f, 1f, 1f); // custom blue
|
||||||
UiSharedService.AccentColor = new(0.4275f, 0.6863f, 1f, 1f);
|
|
||||||
else
|
|
||||||
UiSharedService.AccentColor = new Vector4(0.6f, 0.4f, 0.8f, 1f);
|
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y);
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y);
|
||||||
WindowContentWidth = UiSharedService.GetWindowContentRegionWidth();
|
WindowContentWidth = UiSharedService.GetWindowContentRegionWidth();
|
||||||
if (!_apiController.IsCurrentVersion)
|
if (!_apiController.IsCurrentVersion)
|
||||||
@@ -121,8 +118,8 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextColored(ImGuiColors.DalamudRed, unsupported);
|
ImGui.TextColored(ImGuiColors.DalamudRed, unsupported);
|
||||||
}
|
}
|
||||||
UiSharedService.ColorTextWrapped($"Your Umbra installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " +
|
UiSharedService.ColorTextWrapped($"Your UmbraSync installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " +
|
||||||
$"It is highly recommended to keep Umbra up to date. Open /xlplugins and update the plugin.", ImGuiColors.DalamudRed);
|
$"It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.", ImGuiColors.DalamudRed);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (ImRaii.PushId("header")) DrawUIDHeader();
|
using (ImRaii.PushId("header")) DrawUIDHeader();
|
||||||
@@ -387,7 +384,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2);
|
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2);
|
||||||
if (!printShard) ImGui.AlignTextToFramePadding();
|
if (!printShard) ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextColored(new Vector4(0.6f, 0.4f, 0.8f, 1f), userCount);
|
ImGui.TextColored(ImGuiColors.ParsedBlue, userCount);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (!printShard) ImGui.AlignTextToFramePadding();
|
if (!printShard) ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted("Users Online");
|
ImGui.TextUnformatted("Users Online");
|
||||||
@@ -410,7 +407,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
|
||||||
}
|
}
|
||||||
var color = !_serverManager.CurrentServer!.FullPause ? new Vector4(0.6f, 0.4f, 0.8f, 1f) : ImGuiColors.DalamudRed;
|
var color = UiSharedService.GetBoolColor(!_serverManager.CurrentServer!.FullPause);
|
||||||
var connectedIcon = !_serverManager.CurrentServer.FullPause ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink;
|
var connectedIcon = !_serverManager.CurrentServer.FullPause ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink;
|
||||||
|
|
||||||
if (_apiController.ServerState is ServerState.Connected)
|
if (_apiController.ServerState is ServerState.Connected)
|
||||||
@@ -525,7 +522,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Mediator.Publish(new OpenSettingsUiMessage());
|
Mediator.Publish(new OpenSettingsUiMessage());
|
||||||
}
|
}
|
||||||
UiSharedService.AttachToolTip("Open the Umbra Settings");
|
UiSharedService.AttachToolTip("Open the UmbraSync Settings");
|
||||||
|
|
||||||
ImGui.SameLine(); //Important to draw the uidText consistently
|
ImGui.SameLine(); //Important to draw the uidText consistently
|
||||||
ImGui.SetCursorPos(originalPos);
|
ImGui.SetCursorPos(originalPos);
|
||||||
@@ -595,7 +592,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
ServerState.Connecting => ImGuiColors.DalamudYellow,
|
ServerState.Connecting => ImGuiColors.DalamudYellow,
|
||||||
ServerState.Reconnecting => ImGuiColors.DalamudRed,
|
ServerState.Reconnecting => ImGuiColors.DalamudRed,
|
||||||
ServerState.Connected => UiSharedService.AccentColor,
|
ServerState.Connected => new Vector4(0.2f, 0.6f, 1f, 1f), // custom blue
|
||||||
ServerState.Disconnected => ImGuiColors.DalamudYellow,
|
ServerState.Disconnected => ImGuiColors.DalamudYellow,
|
||||||
ServerState.Disconnecting => ImGuiColors.DalamudYellow,
|
ServerState.Disconnecting => ImGuiColors.DalamudYellow,
|
||||||
ServerState.Unauthorized => ImGuiColors.DalamudRed,
|
ServerState.Unauthorized => ImGuiColors.DalamudRed,
|
||||||
|
|||||||
@@ -163,13 +163,13 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
UiSharedService.Color(0, 0, 0, transparency), 1);
|
UiSharedService.Color(0, 0, 0, transparency), 1);
|
||||||
drawList.AddRectFilled(dlBarStart with { X = dlBarStart.X - dlBarBorder, Y = dlBarStart.Y - dlBarBorder },
|
drawList.AddRectFilled(dlBarStart with { X = dlBarStart.X - dlBarBorder, Y = dlBarStart.Y - dlBarBorder },
|
||||||
dlBarEnd with { X = dlBarEnd.X + dlBarBorder, Y = dlBarEnd.Y + dlBarBorder },
|
dlBarEnd with { X = dlBarEnd.X + dlBarBorder, Y = dlBarEnd.Y + dlBarBorder },
|
||||||
UiSharedService.Color(200, 170, 230, transparency), 1);
|
UiSharedService.Color(220, 220, 255, transparency), 1);
|
||||||
drawList.AddRectFilled(dlBarStart, dlBarEnd,
|
drawList.AddRectFilled(dlBarStart, dlBarEnd,
|
||||||
UiSharedService.Color(0, 0, 0, transparency), 1);
|
UiSharedService.Color(0, 0, 0, transparency), 1);
|
||||||
var dlProgressPercent = transferredBytes / (double)totalBytes;
|
var dlProgressPercent = transferredBytes / (double)totalBytes;
|
||||||
drawList.AddRectFilled(dlBarStart,
|
drawList.AddRectFilled(dlBarStart,
|
||||||
dlBarEnd with { X = dlBarStart.X + (float)(dlProgressPercent * dlBarWidth) },
|
dlBarEnd with { X = dlBarStart.X + (float)(dlProgressPercent * dlBarWidth) },
|
||||||
UiSharedService.Color(153, 102, 204, transparency), 1);
|
UiSharedService.Color(100, 100, 255, transparency), 1);
|
||||||
|
|
||||||
if (_configService.Current.TransferBarsShowText)
|
if (_configService.Current.TransferBarsShowText)
|
||||||
{
|
{
|
||||||
@@ -198,7 +198,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
|
|||||||
var drawList = ImGui.GetBackgroundDrawList();
|
var drawList = ImGui.GetBackgroundDrawList();
|
||||||
UiSharedService.DrawOutlinedFont(drawList, uploadText,
|
UiSharedService.DrawOutlinedFont(drawList, uploadText,
|
||||||
screenPos with { X = screenPos.X - textSize.X / 2f - 1, Y = screenPos.Y - textSize.Y / 2f - 1 },
|
screenPos with { X = screenPos.X - textSize.X / 2f - 1, Y = screenPos.Y - textSize.Y / 2f - 1 },
|
||||||
UiSharedService.Color(153, 102, 204, transparency),
|
UiSharedService.Color(255, 255, 0, transparency),
|
||||||
UiSharedService.Color(0, 0, 0, transparency), 2);
|
UiSharedService.Color(0, 0, 0, transparency), 2);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -106,9 +106,8 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
if (_uiShared.IsInGpose) return;
|
if (_uiShared.IsInGpose) return;
|
||||||
|
|
||||||
if ((!_configService.Current.AcceptedAgreement || _configService.Current.AcceptedTOSVersion != _configService.Current.ExpectedTOSVersion) && !_readFirstPage)
|
if (!_configService.Current.AcceptedAgreement && !_readFirstPage)
|
||||||
{
|
{
|
||||||
// TODO: The UI bugs hard if this page *isn't* shown before the new TOS. There's probably a way around it.
|
|
||||||
_uiShared.BigText("Welcome to Umbra");
|
_uiShared.BigText("Welcome to Umbra");
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
UiSharedService.TextWrapped("Umbra is a plugin that will replicate your full current character state including all Penumbra mods to other paired users. " +
|
UiSharedService.TextWrapped("Umbra is a plugin that will replicate your full current character state including all Penumbra mods to other paired users. " +
|
||||||
@@ -126,7 +125,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
_timeoutTask = Task.Run(async () =>
|
_timeoutTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
for (int i = 45; i > 0; i--)
|
for (int i = 10; i > 0; i--)
|
||||||
{
|
{
|
||||||
_timeoutLabel = $"'I agree' button will be available in {i}s";
|
_timeoutLabel = $"'I agree' button will be available in {i}s";
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
|
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
|
||||||
@@ -137,7 +136,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((!_configService.Current.AcceptedAgreement || _configService.Current.AcceptedTOSVersion != _configService.Current.ExpectedTOSVersion) && _readFirstPage)
|
else if (!_configService.Current.AcceptedAgreement && _readFirstPage)
|
||||||
{
|
{
|
||||||
using (_uiShared.UidFont.Push())
|
using (_uiShared.UidFont.Push())
|
||||||
{
|
{
|
||||||
@@ -152,7 +151,6 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed);
|
UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed);
|
||||||
ImGui.SetWindowFontScale(1.0f);
|
ImGui.SetWindowFontScale(1.0f);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
UiSharedService.TextWrapped("""
|
UiSharedService.TextWrapped("""
|
||||||
To use Umbra, you must be over the age of 18, or 21 in some jurisdictions.
|
To use Umbra, you must be over the age of 18, or 21 in some jurisdictions.
|
||||||
""");
|
""");
|
||||||
@@ -172,7 +170,10 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. After a period of not being used, the mod files will be automatically deleted.
|
Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. After a period of not being used, the mod files will be automatically deleted.
|
||||||
""");
|
""");
|
||||||
UiSharedService.TextWrapped("""
|
UiSharedService.TextWrapped("""
|
||||||
Umbra is operated from servers located in the European Union and Switzerland. You agree not to upload any content to the service that violates EU and CH law; and more specifically, German law for EU.
|
Accounts that are inactive for ninety (90) days will be deleted for privacy reasons.
|
||||||
|
""");
|
||||||
|
UiSharedService.TextWrapped("""
|
||||||
|
Umbra is operated from servers located in the European Union. You agree not to upload any content to the service that violates EU law; and more specifically, German law.
|
||||||
""");
|
""");
|
||||||
UiSharedService.TextWrapped("""
|
UiSharedService.TextWrapped("""
|
||||||
You may delete your account at any time from within the Settings panel of the plugin. Any mods unique to you will then be removed from the server within 14 days.
|
You may delete your account at any time from within the Settings panel of the plugin. Any mods unique to you will then be removed from the server within 14 days.
|
||||||
@@ -187,7 +188,6 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
if (ImGui.Button("I agree##toSetup"))
|
if (ImGui.Button("I agree##toSetup"))
|
||||||
{
|
{
|
||||||
_configService.Current.AcceptedAgreement = true;
|
_configService.Current.AcceptedAgreement = true;
|
||||||
_configService.Current.AcceptedTOSVersion = _configService.Current.ExpectedTOSVersion;
|
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +196,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
UiSharedService.TextWrapped(_timeoutLabel);
|
UiSharedService.TextWrapped(_timeoutLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((!_configService.Current.AcceptedAgreement || _configService.Current.AcceptedTOSVersion != _configService.Current.ExpectedTOSVersion)
|
else if (_configService.Current.AcceptedAgreement
|
||||||
&& (string.IsNullOrEmpty(_configService.Current.CacheFolder)
|
&& (string.IsNullOrEmpty(_configService.Current.CacheFolder)
|
||||||
|| !_configService.Current.InitialScanComplete
|
|| !_configService.Current.InitialScanComplete
|
||||||
|| !Directory.Exists(_configService.Current.CacheFolder)))
|
|| !Directory.Exists(_configService.Current.CacheFolder)))
|
||||||
|
|||||||
@@ -851,16 +851,6 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Umbra.");
|
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Umbra.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (NoSnapService.AnyLoaded)
|
|
||||||
{
|
|
||||||
IconText(FontAwesomeIcon.ExclamationTriangle, ImGuiColors.DalamudYellow);
|
|
||||||
ImGui.SameLine();
|
|
||||||
var cursorX = ImGui.GetCursorPosX();
|
|
||||||
ImGui.TextColored(ImGuiColors.DalamudYellow, "Synced player appearances will not apply until incompatible plugins are disabled:");
|
|
||||||
ImGui.SetCursorPosX(cursorX + 16.0f);
|
|
||||||
ImGui.TextColored(ImGuiColors.DalamudYellow, NoSnapService.ActivePlugins);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,18 +17,16 @@ public sealed class AccountRegistrationService : IDisposable
|
|||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<AccountRegistrationService> _logger;
|
private readonly ILogger<AccountRegistrationService> _logger;
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
|
|
||||||
private string GenerateSecretKey()
|
private 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, RemoteConfigurationService remoteConfig)
|
public AccountRegistrationService(ILogger<AccountRegistrationService> logger, ServerConfigurationManager serverManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_remoteConfig = remoteConfig;
|
|
||||||
_httpClient = new(
|
_httpClient = new(
|
||||||
new HttpClientHandler
|
new HttpClientHandler
|
||||||
{
|
{
|
||||||
@@ -47,22 +45,10 @@ public sealed class AccountRegistrationService : IDisposable
|
|||||||
|
|
||||||
public async Task<RegisterReplyDto> RegisterAccount(CancellationToken token)
|
public async Task<RegisterReplyDto> RegisterAccount(CancellationToken token)
|
||||||
{
|
{
|
||||||
var authApiUrl = _serverManager.CurrentApiUrl;
|
|
||||||
|
|
||||||
// Override the API URL used for auth from remote config, if one is available
|
|
||||||
if (authApiUrl.Equals(ApiController.UmbraServiceUri, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var config = await _remoteConfig.GetConfigAsync<HubConnectionConfig>("mainServer").ConfigureAwait(false) ?? new();
|
|
||||||
if (!string.IsNullOrEmpty(config.ApiUrl))
|
|
||||||
authApiUrl = config.ApiUrl;
|
|
||||||
else
|
|
||||||
authApiUrl = ApiController.UmbraServiceApiUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
var secretKey = GenerateSecretKey();
|
var secretKey = GenerateSecretKey();
|
||||||
var hashedSecretKey = secretKey.GetHash256();
|
var hashedSecretKey = secretKey.GetHash256();
|
||||||
|
|
||||||
Uri postUri = MareAuth.AuthRegisterV2FullPath(new Uri(authApiUrl
|
Uri postUri = MareAuth.AuthRegisterV2FullPath(new Uri(_serverManager.CurrentApiUrl
|
||||||
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
||||||
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ namespace MareSynchronos.WebAPI;
|
|||||||
#pragma warning disable MA0040
|
#pragma warning disable MA0040
|
||||||
public sealed partial class ApiController : DisposableMediatorSubscriberBase, IMareHubClient
|
public sealed partial class ApiController : DisposableMediatorSubscriberBase, IMareHubClient
|
||||||
{
|
{
|
||||||
public const string UmbraServer = "Umbra Main Server (BETA)";
|
public const string UmbraServer = "UmbraSync Main Server (BETA)";
|
||||||
public const string UmbraServiceUri = "wss://umbra-sync.net";
|
public const string UmbraServiceUri = "wss://umbra-sync.net/";
|
||||||
public const string UmbraServiceApiUri = "wss://umbra-sync.net/";
|
public const string UmbraServiceApiUri = "wss://umbra-sync.net/";
|
||||||
public const string UmbraServiceHubUri = "wss://umbra-sync.net/mare";
|
public const string UmbraServiceHubUri = "wss://umbra-sync.net/mare";
|
||||||
|
|
||||||
private readonly DalamudUtilService _dalamudUtil;
|
private readonly DalamudUtilService _dalamudUtil;
|
||||||
private readonly HubFactory _hubFactory;
|
private readonly HubFactory _hubFactory;
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ using Microsoft.AspNetCore.Http.Connections;
|
|||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace MareSynchronos.WebAPI.SignalR;
|
namespace MareSynchronos.WebAPI.SignalR;
|
||||||
|
|
||||||
@@ -16,7 +19,6 @@ public class HubFactory : MediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
private readonly ILoggerProvider _loggingProvider;
|
private readonly ILoggerProvider _loggingProvider;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
private readonly TokenProvider _tokenProvider;
|
private readonly TokenProvider _tokenProvider;
|
||||||
private HubConnection? _instance;
|
private HubConnection? _instance;
|
||||||
private string _cachedConfigFor = string.Empty;
|
private string _cachedConfigFor = string.Empty;
|
||||||
@@ -24,11 +26,10 @@ public class HubFactory : MediatorSubscriberBase
|
|||||||
private bool _isDisposed = false;
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
public HubFactory(ILogger<HubFactory> logger, MareMediator mediator,
|
public HubFactory(ILogger<HubFactory> logger, MareMediator mediator,
|
||||||
ServerConfigurationManager serverConfigurationManager, RemoteConfigurationService remoteConfig,
|
ServerConfigurationManager serverConfigurationManager,
|
||||||
TokenProvider tokenProvider, ILoggerProvider pluginLog) : base(logger, mediator)
|
TokenProvider tokenProvider, ILoggerProvider pluginLog) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_remoteConfig = remoteConfig;
|
|
||||||
_tokenProvider = tokenProvider;
|
_tokenProvider = tokenProvider;
|
||||||
_loggingProvider = pluginLog;
|
_loggingProvider = pluginLog;
|
||||||
}
|
}
|
||||||
@@ -65,28 +66,98 @@ public class HubFactory : MediatorSubscriberBase
|
|||||||
|
|
||||||
private async Task<HubConnectionConfig> ResolveHubConfig()
|
private async Task<HubConnectionConfig> ResolveHubConfig()
|
||||||
{
|
{
|
||||||
|
var stapledWellKnown = _tokenProvider.GetStapledWellKnown(_serverConfigurationManager.CurrentApiUrl);
|
||||||
|
|
||||||
|
var apiUrl = new Uri(_serverConfigurationManager.CurrentApiUrl);
|
||||||
|
|
||||||
|
HubConnectionConfig defaultConfig;
|
||||||
|
|
||||||
if (_cachedConfig != null && _serverConfigurationManager.CurrentApiUrl.Equals(_cachedConfigFor, StringComparison.Ordinal))
|
if (_cachedConfig != null && _serverConfigurationManager.CurrentApiUrl.Equals(_cachedConfigFor, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
return _cachedConfig;
|
defaultConfig = _cachedConfig;
|
||||||
}
|
}
|
||||||
var defaultConfig = new HubConnectionConfig
|
else
|
||||||
{
|
{
|
||||||
HubUrl = _serverConfigurationManager.CurrentApiUrl.TrimEnd('/') + IMareHub.Path,
|
defaultConfig = new HubConnectionConfig
|
||||||
Transports = []
|
{
|
||||||
};
|
HubUrl = _serverConfigurationManager.CurrentApiUrl.TrimEnd('/') + IMareHub.Path,
|
||||||
|
Transports = []
|
||||||
if (_serverConfigurationManager.CurrentApiUrl.Equals(ApiController.UmbraServiceUri, StringComparison.Ordinal))
|
};
|
||||||
{
|
}
|
||||||
var mainServerConfig = await _remoteConfig.GetConfigAsync<HubConnectionConfig>("mainServer").ConfigureAwait(false) ?? new();
|
|
||||||
if (string.IsNullOrEmpty(mainServerConfig.ApiUrl))
|
string jsonResponse;
|
||||||
mainServerConfig.ApiUrl = ApiController.UmbraServiceApiUri;
|
|
||||||
if (string.IsNullOrEmpty(mainServerConfig.HubUrl))
|
if (stapledWellKnown != null)
|
||||||
mainServerConfig.HubUrl = ApiController.UmbraServiceHubUri;
|
{
|
||||||
|
jsonResponse = stapledWellKnown;
|
||||||
mainServerConfig.Transports ??= defaultConfig.Transports ?? [];
|
Logger.LogTrace("Using stapled hub config for {url}", _serverConfigurationManager.CurrentApiUrl);
|
||||||
return mainServerConfig;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var httpScheme = apiUrl.Scheme.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"ws" => "http",
|
||||||
|
"wss" => "https",
|
||||||
|
_ => apiUrl.Scheme
|
||||||
|
};
|
||||||
|
|
||||||
|
var wellKnownUrl = $"{httpScheme}://{apiUrl.Host}/.well-known/Umbra/client";
|
||||||
|
Logger.LogTrace("Fetching hub config for {uri} via {wk}", _serverConfigurationManager.CurrentApiUrl, wellKnownUrl);
|
||||||
|
|
||||||
|
using var httpClient = new HttpClient(
|
||||||
|
new HttpClientHandler
|
||||||
|
{
|
||||||
|
AllowAutoRedirect = true,
|
||||||
|
MaxAutomaticRedirections = 5
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
var ver = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MareSynchronos", ver!.Major + "." + ver!.Minor + "." + ver!.Build));
|
||||||
|
|
||||||
|
var response = await httpClient.GetAsync(wellKnownUrl).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
return defaultConfig;
|
||||||
|
|
||||||
|
var contentType = response.Content.Headers.ContentType?.MediaType;
|
||||||
|
|
||||||
|
if (contentType == null || !contentType.Equals("application/json", StringComparison.Ordinal))
|
||||||
|
return defaultConfig;
|
||||||
|
|
||||||
|
jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(ex, "HTTP request failed for .well-known");
|
||||||
|
return defaultConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var config = JsonSerializer.Deserialize<HubConnectionConfig>(jsonResponse);
|
||||||
|
|
||||||
|
if (config == null)
|
||||||
|
return defaultConfig;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(config.ApiUrl))
|
||||||
|
config.ApiUrl = defaultConfig.ApiUrl;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(config.HubUrl))
|
||||||
|
config.HubUrl = defaultConfig.HubUrl;
|
||||||
|
|
||||||
|
config.Transports ??= defaultConfig.Transports ?? [];
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(ex, "Invalid JSON in .well-known response");
|
||||||
|
return defaultConfig;
|
||||||
}
|
}
|
||||||
return defaultConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HubConnection BuildHubConnection(HubConnectionConfig hubConfig, CancellationToken ct)
|
private HubConnection BuildHubConnection(HubConnectionConfig hubConfig, CancellationToken ct)
|
||||||
@@ -106,11 +177,13 @@ public class HubFactory : MediatorSubscriberBase
|
|||||||
var resolver = CompositeResolver.Create(StandardResolverAllowPrivate.Instance,
|
var resolver = CompositeResolver.Create(StandardResolverAllowPrivate.Instance,
|
||||||
BuiltinResolver.Instance,
|
BuiltinResolver.Instance,
|
||||||
AttributeFormatterResolver.Instance,
|
AttributeFormatterResolver.Instance,
|
||||||
|
// replace enum resolver
|
||||||
DynamicEnumAsStringResolver.Instance,
|
DynamicEnumAsStringResolver.Instance,
|
||||||
DynamicGenericResolver.Instance,
|
DynamicGenericResolver.Instance,
|
||||||
DynamicUnionResolver.Instance,
|
DynamicUnionResolver.Instance,
|
||||||
DynamicObjectResolver.Instance,
|
DynamicObjectResolver.Instance,
|
||||||
PrimitiveObjectResolver.Instance,
|
PrimitiveObjectResolver.Instance,
|
||||||
|
// final fallback(last priority)
|
||||||
StandardResolver.Instance);
|
StandardResolver.Instance);
|
||||||
|
|
||||||
opt.SerializerOptions =
|
opt.SerializerOptions =
|
||||||
|
|||||||
@@ -20,16 +20,14 @@ public sealed class TokenProvider : IDisposable, IMediatorSubscriber
|
|||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<TokenProvider> _logger;
|
private readonly ILogger<TokenProvider> _logger;
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
private readonly ConcurrentDictionary<JwtIdentifier, string> _tokenCache = new();
|
private readonly ConcurrentDictionary<JwtIdentifier, string> _tokenCache = new();
|
||||||
private readonly ConcurrentDictionary<string, string?> _wellKnownCache = new(StringComparer.Ordinal);
|
private readonly ConcurrentDictionary<string, string?> _wellKnownCache = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
public TokenProvider(ILogger<TokenProvider> logger, ServerConfigurationManager serverManager, RemoteConfigurationService remoteConfig,
|
public TokenProvider(ILogger<TokenProvider> logger, ServerConfigurationManager serverManager,
|
||||||
DalamudUtilService dalamudUtil, MareMediator mareMediator)
|
DalamudUtilService dalamudUtil, MareMediator mareMediator)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_remoteConfig = remoteConfig;
|
|
||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
_httpClient = new(
|
_httpClient = new(
|
||||||
new HttpClientHandler
|
new HttpClientHandler
|
||||||
@@ -70,23 +68,11 @@ public sealed class TokenProvider : IDisposable, IMediatorSubscriber
|
|||||||
Uri tokenUri;
|
Uri tokenUri;
|
||||||
HttpResponseMessage result;
|
HttpResponseMessage result;
|
||||||
|
|
||||||
var authApiUrl = _serverManager.CurrentApiUrl;
|
|
||||||
|
|
||||||
// Override the API URL used for auth from remote config, if one is available
|
|
||||||
if (authApiUrl.Equals(ApiController.UmbraServiceUri, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var config = await _remoteConfig.GetConfigAsync<HubConnectionConfig>("mainServer").ConfigureAwait(false) ?? new();
|
|
||||||
if (!string.IsNullOrEmpty(config.ApiUrl))
|
|
||||||
authApiUrl = config.ApiUrl;
|
|
||||||
else
|
|
||||||
authApiUrl = ApiController.UmbraServiceApiUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogDebug("GetNewToken: Requesting");
|
_logger.LogDebug("GetNewToken: Requesting");
|
||||||
|
|
||||||
tokenUri = MareAuth.AuthV2FullPath(new Uri(authApiUrl
|
tokenUri = MareAuth.AuthV2FullPath(new Uri(_serverManager.CurrentApiUrl
|
||||||
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
||||||
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
||||||
var secretKey = _serverManager.GetSecretKey(out _)!;
|
var secretKey = _serverManager.GetSecretKey(out _)!;
|
||||||
|
|||||||
BIN
MareSynchronos/images/logo.png
Normal file
BIN
MareSynchronos/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 928 KiB |
Reference in New Issue
Block a user