diff --git a/.DS_Store b/.DS_Store index e050f7b..ff26028 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index a96d579..740eafe 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.user *.userosscache *.sln.docstates +.DS_Store # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs diff --git a/MareSynchronos/.DS_Store b/MareSynchronos/.DS_Store index c6bd2b5..d5b7076 100644 Binary files a/MareSynchronos/.DS_Store and b/MareSynchronos/.DS_Store differ diff --git a/MareSynchronos/FileCache/FileCacheManager.cs b/MareSynchronos/FileCache/FileCacheManager.cs index 0c3b1ab..a5a595c 100644 --- a/MareSynchronos/FileCache/FileCacheManager.cs +++ b/MareSynchronos/FileCache/FileCacheManager.cs @@ -236,7 +236,6 @@ public sealed class FileCacheManager : IHostedService foreach (var entry in cleanedPaths) { - //_logger.LogDebug("Checking {path}", entry.Value); 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))) { - //_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) { var resultingFileCache = ReplacePathPrefixes(fileCache); - //_logger.LogTrace("Validating {path}", fileCache.PrefixedFilePath); resultingFileCache = Validate(resultingFileCache); return resultingFileCache; } diff --git a/MareSynchronos/Interop/Ipc/IpcCallerBrio.cs b/MareSynchronos/Interop/Ipc/IpcCallerBrio.cs index b8a9c58..635787c 100644 --- a/MareSynchronos/Interop/Ipc/IpcCallerBrio.cs +++ b/MareSynchronos/Interop/Ipc/IpcCallerBrio.cs @@ -95,8 +95,6 @@ public sealed class IpcCallerBrio : IIpcCaller if (gameObject == null) return default; var data = await _dalamudUtilService.RunOnFrameworkThread(() => _brioGetModelTransform.InvokeFunc(gameObject)).ConfigureAwait(false); 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() { PositionX = data.Item1.Value.X, diff --git a/MareSynchronos/Interop/Ipc/IpcCallerMoodles.cs b/MareSynchronos/Interop/Ipc/IpcCallerMoodles.cs index 44b6ce5..be38465 100644 --- a/MareSynchronos/Interop/Ipc/IpcCallerMoodles.cs +++ b/MareSynchronos/Interop/Ipc/IpcCallerMoodles.cs @@ -27,9 +27,9 @@ public sealed class IpcCallerMoodles : IIpcCaller _moodlesApiVersion = pi.GetIpcSubscriber("Moodles.Version"); _moodlesOnChange = pi.GetIpcSubscriber("Moodles.StatusManagerModified"); - _moodlesGetStatus = pi.GetIpcSubscriber("Moodles.GetStatusManagerByPtr"); - _moodlesSetStatus = pi.GetIpcSubscriber("Moodles.SetStatusManagerByPtr"); - _moodlesRevertStatus = pi.GetIpcSubscriber("Moodles.ClearStatusManagerByPtr"); + _moodlesGetStatus = pi.GetIpcSubscriber("Moodles.GetStatusManagerByPtrV2"); + _moodlesSetStatus = pi.GetIpcSubscriber("Moodles.SetStatusManagerByPtrV2"); + _moodlesRevertStatus = pi.GetIpcSubscriber("Moodles.ClearStatusManagerByPtrV2"); _moodlesOnChange.Subscribe(OnMoodlesChange); @@ -47,7 +47,7 @@ public sealed class IpcCallerMoodles : IIpcCaller { try { - APIAvailable = _moodlesApiVersion.InvokeFunc() == 1; + APIAvailable = _moodlesApiVersion.InvokeFunc() == 3; } catch { diff --git a/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs b/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs index a662178..309556e 100644 --- a/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs +++ b/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs @@ -30,12 +30,12 @@ public sealed class IpcCallerPetNames : IIpcCaller _dalamudUtil = dalamudUtil; _mareMediator = mareMediator; - _petnamesReady = pi.GetIpcSubscriber("PetRenamer.Ready"); - _petnamesDisposing = pi.GetIpcSubscriber("PetRenamer.Disposing"); + _petnamesReady = pi.GetIpcSubscriber("PetRenamer.OnReady"); + _petnamesDisposing = pi.GetIpcSubscriber("PetRenamer.OnDisposing"); _apiVersion = pi.GetIpcSubscriber<(uint, uint)>("PetRenamer.ApiVersion"); - _enabled = pi.GetIpcSubscriber("PetRenamer.Enabled"); + _enabled = pi.GetIpcSubscriber("PetRenamer.IsEnabled"); - _playerDataChanged = pi.GetIpcSubscriber("PetRenamer.PlayerDataChanged"); + _playerDataChanged = pi.GetIpcSubscriber("PetRenamer.OnPlayerDataChanged"); _getPlayerData = pi.GetIpcSubscriber("PetRenamer.GetPlayerData"); _setPlayerData = pi.GetIpcSubscriber("PetRenamer.SetPlayerData"); _clearPlayerData = pi.GetIpcSubscriber("PetRenamer.ClearPlayerData"); @@ -56,7 +56,7 @@ public sealed class IpcCallerPetNames : IIpcCaller APIAvailable = _enabled?.InvokeFunc() ?? false; if (APIAvailable) { - APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 3, Item2: >= 1 }; + APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 4, Item2: >= 0 }; } } catch diff --git a/MareSynchronos/MareConfiguration/ConfigurationExtensions.cs b/MareSynchronos/MareConfiguration/ConfigurationExtensions.cs index f433484..a876578 100644 --- a/MareSynchronos/MareConfiguration/ConfigurationExtensions.cs +++ b/MareSynchronos/MareConfiguration/ConfigurationExtensions.cs @@ -8,6 +8,6 @@ public static class ConfigurationExtensions { return configuration.AcceptedAgreement && configuration.InitialScanComplete && !string.IsNullOrEmpty(configuration.CacheFolder) - && Directory.Exists(configuration.CacheFolder) && configuration.AcceptedTOSVersion == configuration.ExpectedTOSVersion; + && Directory.Exists(configuration.CacheFolder); } } \ No newline at end of file diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index b4eb042..c10cec5 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -1,10 +1,10 @@  - - UmbraSync - 0.1.0.0 - https://git.umbra-sync.net/SirConstance/UmbraClient - + + UmbraSync + UmbraSync + 0.1.1.0 + diff --git a/MareSynchronos/PlayerData/Factories/PairHandlerFactory.cs b/MareSynchronos/PlayerData/Factories/PairHandlerFactory.cs index 145889a..0fadae8 100644 --- a/MareSynchronos/PlayerData/Factories/PairHandlerFactory.cs +++ b/MareSynchronos/PlayerData/Factories/PairHandlerFactory.cs @@ -27,14 +27,13 @@ public class PairHandlerFactory private readonly PluginWarningNotificationService _pluginWarningNotificationManager; private readonly PairAnalyzerFactory _pairAnalyzerFactory; private readonly VisibilityService _visibilityService; - private readonly NoSnapService _noSnapService; public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager, FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService, PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime, FileCacheManager fileCacheManager, MareMediator mareMediator, PlayerPerformanceService playerPerformanceService, ServerConfigurationManager serverConfigManager, PairAnalyzerFactory pairAnalyzerFactory, - MareConfigService configService, VisibilityService visibilityService, NoSnapService noSnapService) + MareConfigService configService, VisibilityService visibilityService) { _loggerFactory = loggerFactory; _gameObjectHandlerFactory = gameObjectHandlerFactory; @@ -50,13 +49,12 @@ public class PairHandlerFactory _pairAnalyzerFactory = pairAnalyzerFactory; _configService = configService; _visibilityService = visibilityService; - _noSnapService = noSnapService; } public PairHandler Create(Pair pair) { return new PairHandler(_loggerFactory.CreateLogger(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory, _ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime, - _fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService, _noSnapService); + _fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService); } } \ No newline at end of file diff --git a/MareSynchronos/PlayerData/Handlers/PairHandler.cs b/MareSynchronos/PlayerData/Handlers/PairHandler.cs index d12a347..26e3aee 100644 --- a/MareSynchronos/PlayerData/Handlers/PairHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/PairHandler.cs @@ -32,7 +32,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase private readonly ServerConfigurationManager _serverConfigManager; private readonly PluginWarningNotificationService _pluginWarningNotificationManager; private readonly VisibilityService _visibilityService; - private readonly NoSnapService _noSnapService; private CancellationTokenSource? _applicationCancellationTokenSource = new(); private Guid _applicationId; private Task? _applicationTask; @@ -55,8 +54,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase FileCacheManager fileDbManager, MareMediator mediator, PlayerPerformanceService playerPerformanceService, ServerConfigurationManager serverConfigManager, - MareConfigService configService, VisibilityService visibilityService, - NoSnapService noSnapService) : base(logger, mediator) + MareConfigService configService, VisibilityService visibilityService) : base(logger, mediator) { Pair = pair; PairAnalyzer = pairAnalyzer; @@ -70,7 +68,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase _serverConfigManager = serverConfigManager; _configService = configService; _visibilityService = visibilityService; - _noSnapService = noSnapService; _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) { 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); _penumbraCollection = Guid.Empty; - RegisterGposeClones(); } 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) { diff --git a/MareSynchronos/PlayerData/Pairs/Pair.cs b/MareSynchronos/PlayerData/Pairs/Pair.cs index b867564..1ca50bc 100644 --- a/MareSynchronos/PlayerData/Pairs/Pair.cs +++ b/MareSynchronos/PlayerData/Pairs/Pair.cs @@ -171,11 +171,6 @@ public class Pair : DisposableMediatorSubscriberBase if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID)) HoldApplication("Blacklist", maxValue: 1); - if (NoSnapService.AnyLoaded) - HoldApplication("NoSnap", maxValue: 1); - else - UnholdApplication("NoSnap", skipApplication: true); - CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced); } diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs index 9312e4b..799c9fd 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -39,8 +39,6 @@ public sealed class Plugin : IDalamudPlugin public static Plugin Self; #pragma warning restore CA2211, CS8618, MA0069, S1104, S2223 public Action? RealOnFrameworkUpdate { get; set; } - - // Proxy function in the UmbraSync namespace to avoid confusion in /xlstats public void OnFrameworkUpdate(IFramework framework) { RealOnFrameworkUpdate?.Invoke(framework); @@ -142,7 +140,6 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); - collection.AddSingleton(); collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName)); @@ -168,7 +165,6 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton(); collection.AddSingleton(); - collection.AddSingleton(); collection.AddSingleton(); @@ -209,7 +205,6 @@ public sealed class Plugin : IDalamudPlugin collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); - collection.AddHostedService(p => p.GetRequiredService()); }) .Build(); diff --git a/MareSynchronos/Services/CharaData/CharaDataCharacterHandler.cs b/MareSynchronos/Services/CharaData/CharaDataCharacterHandler.cs index 21e390f..2b76ddf 100644 --- a/MareSynchronos/Services/CharaData/CharaDataCharacterHandler.cs +++ b/MareSynchronos/Services/CharaData/CharaDataCharacterHandler.cs @@ -13,20 +13,18 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; private readonly DalamudUtilService _dalamudUtilService; private readonly IpcManager _ipcManager; - private readonly NoSnapService _noSnapService; private readonly Dictionary _handledCharaData = new(StringComparer.Ordinal); public IReadOnlyDictionary HandledCharaData => _handledCharaData; public CharaDataCharacterHandler(ILogger logger, MareMediator mediator, GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService, - IpcManager ipcManager, NoSnapService noSnapService) + IpcManager ipcManager) : base(logger, mediator) { _gameObjectHandlerFactory = gameObjectHandlerFactory; _dalamudUtilService = dalamudUtilService; _ipcManager = ipcManager; - _noSnapService = noSnapService; mediator.Subscribe(this, msg => { foreach (var chara in _handledCharaData) @@ -94,7 +92,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase _handledCharaData.Remove(handled.Name); await _dalamudUtilService.RunOnFrameworkThread(async () => { - RemoveGposer(handled); await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false); }).ConfigureAwait(false); return true; @@ -103,7 +100,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry) { _handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry); - _ = _dalamudUtilService.RunOnFrameworkThread(() => AddGposer(handledCharaDataEntry)); } public void UpdateHandledData(Dictionary newData) @@ -134,23 +130,4 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase if (handler.Address == nint.Zero) return null; 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); - } } diff --git a/MareSynchronos/Services/ChatService.cs b/MareSynchronos/Services/ChatService.cs index 3b71fa1..1cf25f1 100644 --- a/MareSynchronos/Services/ChatService.cs +++ b/MareSynchronos/Services/ChatService.cs @@ -72,7 +72,7 @@ public class ChatService : DisposableMediatorSubscriberBase { var chatMsg = message.ChatMsg; var prefix = new SeStringBuilder(); - prefix.AddText("[BnnuyChat] "); + prefix.AddText("[UmbraChat] "); _chatGui.Print(new XivChatEntry{ MessageBytes = [..prefix.Build().Encode(), ..message.ChatMsg.PayloadContent], 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) @@ -236,6 +236,6 @@ public class ChatService : DisposableMediatorSubscriberBase } } - _chatGui.PrintError($"[Umbra] Syncshell number #{shellNumber} not found"); + _chatGui.PrintError($"[UmbraSync] Syncshell number #{shellNumber} not found"); } } \ No newline at end of file diff --git a/MareSynchronos/Services/CommandManagerService.cs b/MareSynchronos/Services/CommandManagerService.cs index 60fabe5..4a368c8 100644 --- a/MareSynchronos/Services/CommandManagerService.cs +++ b/MareSynchronos/Services/CommandManagerService.cs @@ -15,7 +15,7 @@ namespace MareSynchronos.Services; public sealed class CommandManagerService : IDisposable { private const string _commandName = "/sync"; - private const string _commandName2 = "/snowcloak"; + private const string _commandName2 = "/usync"; private const string _ssCommandPrefix = "/ss"; diff --git a/MareSynchronos/Services/NoSnapService.cs b/MareSynchronos/Services/NoSnapService.cs deleted file mode 100644 index 226fab3..0000000 --- a/MareSynchronos/Services/NoSnapService.cs +++ /dev/null @@ -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 _logger; - private readonly IDalamudPluginInterface _pluginInterface; - private readonly Dictionary _listOfPlugins = new(StringComparer.Ordinal) - { - ["Snapper"] = false, - ["Snappy"] = false, - ["Meddle.Plugin"] = false, - }; - private static readonly HashSet _gposers = new(); - private static readonly HashSet _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 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(this, msg => ClearGposeList()); - Mediator.Subscribe(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? gposersList = null; - List? 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("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(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; - } - } - } -} \ No newline at end of file diff --git a/MareSynchronos/Services/NotificationService.cs b/MareSynchronos/Services/NotificationService.cs index 604d33d..9a48c57 100644 --- a/MareSynchronos/Services/NotificationService.cs +++ b/MareSynchronos/Services/NotificationService.cs @@ -41,19 +41,19 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ 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); } 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); } 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); } diff --git a/MareSynchronos/Services/RemoteConfigurationService.cs b/MareSynchronos/Services/RemoteConfigurationService.cs deleted file mode 100644 index fcaf26d..0000000 --- a/MareSynchronos/Services/RemoteConfigurationService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; - -namespace MareSynchronos.Services -{ - /// - /// Stub minimal : renvoie toujours null (pas de conf distante). - /// - public class RemoteConfigurationService - { - private readonly ILogger _logger; - - public RemoteConfigurationService(ILogger logger) - { - _logger = logger; - } - - public Task GetConfigAsync(string key) where T : class - => Task.FromResult(null); - } -} diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index 3ebc1fa..69fa74f 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -60,7 +60,7 @@ public class CompactUi : WindowMediatorSubscriberBase public CompactUi(ILogger logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService, ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager, PerformanceCollectorService performanceCollectorService) - : base(logger, mediator, "###UmbraSyncMainUI", performanceCollectorService) + : base(logger, mediator, "###UmbraSyncSyncMainUI", performanceCollectorService) { _uiSharedService = uiShared; _configService = configService; @@ -80,11 +80,11 @@ public class CompactUi : WindowMediatorSubscriberBase #if DEBUG string dev = "Dev Build"; 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(); #else 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 Mediator.Subscribe(this, (_) => IsOpen = true); Mediator.Subscribe(this, (_) => IsOpen = false); @@ -104,10 +104,7 @@ public class CompactUi : WindowMediatorSubscriberBase protected override void DrawInternal() { - if (_serverManager.CurrentApiUrl.Equals(ApiController.UmbraServiceUri, StringComparison.Ordinal)) - UiSharedService.AccentColor = new(0.4275f, 0.6863f, 1f, 1f); - else - UiSharedService.AccentColor = new Vector4(0.6f, 0.4f, 0.8f, 1f); + UiSharedService.AccentColor = new Vector4(0.2f, 0.6f, 1f, 1f); // custom blue ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y); WindowContentWidth = UiSharedService.GetWindowContentRegionWidth(); if (!_apiController.IsCurrentVersion) @@ -121,8 +118,8 @@ public class CompactUi : WindowMediatorSubscriberBase ImGui.AlignTextToFramePadding(); ImGui.TextColored(ImGuiColors.DalamudRed, unsupported); } - UiSharedService.ColorTextWrapped($"Your Umbra 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); + 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 UmbraSync up to date. Open /xlplugins and update the plugin.", ImGuiColors.DalamudRed); } 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); if (!printShard) ImGui.AlignTextToFramePadding(); - ImGui.TextColored(new Vector4(0.6f, 0.4f, 0.8f, 1f), userCount); + ImGui.TextColored(ImGuiColors.ParsedBlue, userCount); ImGui.SameLine(); if (!printShard) ImGui.AlignTextToFramePadding(); 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); } - 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; if (_apiController.ServerState is ServerState.Connected) @@ -525,7 +522,7 @@ public class CompactUi : WindowMediatorSubscriberBase { 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.SetCursorPos(originalPos); @@ -595,7 +592,7 @@ public class CompactUi : WindowMediatorSubscriberBase { ServerState.Connecting => ImGuiColors.DalamudYellow, 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.Disconnecting => ImGuiColors.DalamudYellow, ServerState.Unauthorized => ImGuiColors.DalamudRed, diff --git a/MareSynchronos/UI/DownloadUi.cs b/MareSynchronos/UI/DownloadUi.cs index 165da34..fe60cf2 100644 --- a/MareSynchronos/UI/DownloadUi.cs +++ b/MareSynchronos/UI/DownloadUi.cs @@ -163,13 +163,13 @@ public class DownloadUi : WindowMediatorSubscriberBase UiSharedService.Color(0, 0, 0, transparency), 1); drawList.AddRectFilled(dlBarStart with { X = dlBarStart.X - dlBarBorder, Y = dlBarStart.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, UiSharedService.Color(0, 0, 0, transparency), 1); var dlProgressPercent = transferredBytes / (double)totalBytes; drawList.AddRectFilled(dlBarStart, 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) { @@ -198,7 +198,7 @@ public class DownloadUi : WindowMediatorSubscriberBase var drawList = ImGui.GetBackgroundDrawList(); UiSharedService.DrawOutlinedFont(drawList, uploadText, 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); } catch diff --git a/MareSynchronos/UI/IntroUI.cs b/MareSynchronos/UI/IntroUI.cs index 113ffde..0b64c1b 100644 --- a/MareSynchronos/UI/IntroUI.cs +++ b/MareSynchronos/UI/IntroUI.cs @@ -106,9 +106,8 @@ public partial class IntroUi : WindowMediatorSubscriberBase { 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"); ImGui.Separator(); 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 _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"; await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); @@ -137,7 +136,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase #endif } } - else if ((!_configService.Current.AcceptedAgreement || _configService.Current.AcceptedTOSVersion != _configService.Current.ExpectedTOSVersion) && _readFirstPage) + else if (!_configService.Current.AcceptedAgreement && _readFirstPage) { using (_uiShared.UidFont.Push()) { @@ -152,7 +151,6 @@ public partial class IntroUi : WindowMediatorSubscriberBase UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed); ImGui.SetWindowFontScale(1.0f); ImGui.Separator(); - UiSharedService.TextWrapped(""" 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. """); 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(""" 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")) { _configService.Current.AcceptedAgreement = true; - _configService.Current.AcceptedTOSVersion = _configService.Current.ExpectedTOSVersion; _configService.Save(); } } @@ -196,7 +196,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase UiSharedService.TextWrapped(_timeoutLabel); } } - else if ((!_configService.Current.AcceptedAgreement || _configService.Current.AcceptedTOSVersion != _configService.Current.ExpectedTOSVersion) + else if (_configService.Current.AcceptedAgreement && (string.IsNullOrEmpty(_configService.Current.CacheFolder) || !_configService.Current.InitialScanComplete || !Directory.Exists(_configService.Current.CacheFolder))) diff --git a/MareSynchronos/UI/UISharedService.cs b/MareSynchronos/UI/UISharedService.cs index 1af503d..649e3d9 100644 --- a/MareSynchronos/UI/UISharedService.cs +++ b/MareSynchronos/UI/UISharedService.cs @@ -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."); 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; } diff --git a/MareSynchronos/WebAPI/AccountRegistrationService.cs b/MareSynchronos/WebAPI/AccountRegistrationService.cs index 5ab414c..4b5d81b 100644 --- a/MareSynchronos/WebAPI/AccountRegistrationService.cs +++ b/MareSynchronos/WebAPI/AccountRegistrationService.cs @@ -17,18 +17,16 @@ public sealed class AccountRegistrationService : IDisposable private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly ServerConfigurationManager _serverManager; - private readonly RemoteConfigurationService _remoteConfig; private string GenerateSecretKey() { return Convert.ToHexString(SHA256.HashData(RandomNumberGenerator.GetBytes(64))); } - public AccountRegistrationService(ILogger logger, ServerConfigurationManager serverManager, RemoteConfigurationService remoteConfig) + public AccountRegistrationService(ILogger logger, ServerConfigurationManager serverManager) { _logger = logger; _serverManager = serverManager; - _remoteConfig = remoteConfig; _httpClient = new( new HttpClientHandler { @@ -47,22 +45,10 @@ public sealed class AccountRegistrationService : IDisposable public async Task 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("mainServer").ConfigureAwait(false) ?? new(); - if (!string.IsNullOrEmpty(config.ApiUrl)) - authApiUrl = config.ApiUrl; - else - authApiUrl = ApiController.UmbraServiceApiUri; - } - var secretKey = GenerateSecretKey(); 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("ws://", "http://", StringComparison.OrdinalIgnoreCase))); diff --git a/MareSynchronos/WebAPI/SignalR/ApiController.cs b/MareSynchronos/WebAPI/SignalR/ApiController.cs index f3a23dc..6c8dc88 100644 --- a/MareSynchronos/WebAPI/SignalR/ApiController.cs +++ b/MareSynchronos/WebAPI/SignalR/ApiController.cs @@ -21,10 +21,10 @@ namespace MareSynchronos.WebAPI; #pragma warning disable MA0040 public sealed partial class ApiController : DisposableMediatorSubscriberBase, IMareHubClient { - public const string UmbraServer = "Umbra Main Server (BETA)"; - public const string UmbraServiceUri = "wss://umbra-sync.net"; - public const string UmbraServiceApiUri = "wss://umbra-sync.net/"; - public const string UmbraServiceHubUri = "wss://umbra-sync.net/mare"; + public const string UmbraServer = "UmbraSync Main Server (BETA)"; + public const string UmbraServiceUri = "wss://umbra-sync.net/"; + public const string UmbraServiceApiUri = "wss://umbra-sync.net/"; + public const string UmbraServiceHubUri = "wss://umbra-sync.net/mare"; private readonly DalamudUtilService _dalamudUtil; private readonly HubFactory _hubFactory; diff --git a/MareSynchronos/WebAPI/SignalR/HubFactory.cs b/MareSynchronos/WebAPI/SignalR/HubFactory.cs index 6762f5a..887cca2 100644 --- a/MareSynchronos/WebAPI/SignalR/HubFactory.cs +++ b/MareSynchronos/WebAPI/SignalR/HubFactory.cs @@ -9,6 +9,9 @@ using Microsoft.AspNetCore.Http.Connections; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using System.Net.Http.Headers; +using System.Reflection; +using System.Text.Json; namespace MareSynchronos.WebAPI.SignalR; @@ -16,7 +19,6 @@ public class HubFactory : MediatorSubscriberBase { private readonly ILoggerProvider _loggingProvider; private readonly ServerConfigurationManager _serverConfigurationManager; - private readonly RemoteConfigurationService _remoteConfig; private readonly TokenProvider _tokenProvider; private HubConnection? _instance; private string _cachedConfigFor = string.Empty; @@ -24,11 +26,10 @@ public class HubFactory : MediatorSubscriberBase private bool _isDisposed = false; public HubFactory(ILogger logger, MareMediator mediator, - ServerConfigurationManager serverConfigurationManager, RemoteConfigurationService remoteConfig, + ServerConfigurationManager serverConfigurationManager, TokenProvider tokenProvider, ILoggerProvider pluginLog) : base(logger, mediator) { _serverConfigurationManager = serverConfigurationManager; - _remoteConfig = remoteConfig; _tokenProvider = tokenProvider; _loggingProvider = pluginLog; } @@ -65,28 +66,98 @@ public class HubFactory : MediatorSubscriberBase private async Task ResolveHubConfig() { + var stapledWellKnown = _tokenProvider.GetStapledWellKnown(_serverConfigurationManager.CurrentApiUrl); + + var apiUrl = new Uri(_serverConfigurationManager.CurrentApiUrl); + + HubConnectionConfig defaultConfig; + if (_cachedConfig != null && _serverConfigurationManager.CurrentApiUrl.Equals(_cachedConfigFor, StringComparison.Ordinal)) { - return _cachedConfig; + defaultConfig = _cachedConfig; } - var defaultConfig = new HubConnectionConfig + else { - HubUrl = _serverConfigurationManager.CurrentApiUrl.TrimEnd('/') + IMareHub.Path, - Transports = [] - }; - - if (_serverConfigurationManager.CurrentApiUrl.Equals(ApiController.UmbraServiceUri, StringComparison.Ordinal)) - { - var mainServerConfig = await _remoteConfig.GetConfigAsync("mainServer").ConfigureAwait(false) ?? new(); - if (string.IsNullOrEmpty(mainServerConfig.ApiUrl)) - mainServerConfig.ApiUrl = ApiController.UmbraServiceApiUri; - if (string.IsNullOrEmpty(mainServerConfig.HubUrl)) - mainServerConfig.HubUrl = ApiController.UmbraServiceHubUri; - - mainServerConfig.Transports ??= defaultConfig.Transports ?? []; - return mainServerConfig; + defaultConfig = new HubConnectionConfig + { + HubUrl = _serverConfigurationManager.CurrentApiUrl.TrimEnd('/') + IMareHub.Path, + Transports = [] + }; + } + + string jsonResponse; + + if (stapledWellKnown != null) + { + jsonResponse = stapledWellKnown; + Logger.LogTrace("Using stapled hub config for {url}", _serverConfigurationManager.CurrentApiUrl); + } + 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(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) @@ -106,11 +177,13 @@ public class HubFactory : MediatorSubscriberBase var resolver = CompositeResolver.Create(StandardResolverAllowPrivate.Instance, BuiltinResolver.Instance, AttributeFormatterResolver.Instance, + // replace enum resolver DynamicEnumAsStringResolver.Instance, DynamicGenericResolver.Instance, DynamicUnionResolver.Instance, DynamicObjectResolver.Instance, PrimitiveObjectResolver.Instance, + // final fallback(last priority) StandardResolver.Instance); opt.SerializerOptions = diff --git a/MareSynchronos/WebAPI/SignalR/TokenProvider.cs b/MareSynchronos/WebAPI/SignalR/TokenProvider.cs index 20703ec..4867239 100644 --- a/MareSynchronos/WebAPI/SignalR/TokenProvider.cs +++ b/MareSynchronos/WebAPI/SignalR/TokenProvider.cs @@ -20,16 +20,14 @@ public sealed class TokenProvider : IDisposable, IMediatorSubscriber private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly ServerConfigurationManager _serverManager; - private readonly RemoteConfigurationService _remoteConfig; private readonly ConcurrentDictionary _tokenCache = new(); private readonly ConcurrentDictionary _wellKnownCache = new(StringComparer.Ordinal); - public TokenProvider(ILogger logger, ServerConfigurationManager serverManager, RemoteConfigurationService remoteConfig, + public TokenProvider(ILogger logger, ServerConfigurationManager serverManager, DalamudUtilService dalamudUtil, MareMediator mareMediator) { _logger = logger; _serverManager = serverManager; - _remoteConfig = remoteConfig; _dalamudUtil = dalamudUtil; _httpClient = new( new HttpClientHandler @@ -70,23 +68,11 @@ public sealed class TokenProvider : IDisposable, IMediatorSubscriber Uri tokenUri; 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("mainServer").ConfigureAwait(false) ?? new(); - if (!string.IsNullOrEmpty(config.ApiUrl)) - authApiUrl = config.ApiUrl; - else - authApiUrl = ApiController.UmbraServiceApiUri; - } - try { _logger.LogDebug("GetNewToken: Requesting"); - tokenUri = MareAuth.AuthV2FullPath(new Uri(authApiUrl + tokenUri = MareAuth.AuthV2FullPath(new Uri(_serverManager.CurrentApiUrl .Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase) .Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase))); var secretKey = _serverManager.GetSecretKey(out _)!; diff --git a/MareSynchronos/images/logo.png b/MareSynchronos/images/logo.png new file mode 100644 index 0000000..93b5d3e Binary files /dev/null and b/MareSynchronos/images/logo.png differ