Compare commits
1 Commits
eeab8354b6
...
main-legac
| Author | SHA1 | Date | |
|---|---|---|---|
|
46f2443824
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,6 +9,7 @@
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
.DS_Store
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.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)
|
||||
{
|
||||
//_logger.LogDebug("Checking {path}", entry.Value);
|
||||
|
||||
if (dict.TryGetValue(entry.Value, out var entity))
|
||||
{
|
||||
@@ -366,7 +365,6 @@ 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -27,9 +27,9 @@ public sealed class IpcCallerMoodles : IIpcCaller
|
||||
|
||||
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
|
||||
_moodlesOnChange = pi.GetIpcSubscriber<IPlayerCharacter, object>("Moodles.StatusManagerModified");
|
||||
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtr");
|
||||
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtr");
|
||||
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtr");
|
||||
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtrV2");
|
||||
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtrV2");
|
||||
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtrV2");
|
||||
|
||||
_moodlesOnChange.Subscribe(OnMoodlesChange);
|
||||
|
||||
@@ -47,7 +47,7 @@ public sealed class IpcCallerMoodles : IIpcCaller
|
||||
{
|
||||
try
|
||||
{
|
||||
APIAvailable = _moodlesApiVersion.InvokeFunc() == 1;
|
||||
APIAvailable = _moodlesApiVersion.InvokeFunc() == 3;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -30,12 +30,12 @@ public sealed class IpcCallerPetNames : IIpcCaller
|
||||
_dalamudUtil = dalamudUtil;
|
||||
_mareMediator = mareMediator;
|
||||
|
||||
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.Ready");
|
||||
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.Disposing");
|
||||
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.OnReady");
|
||||
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.OnDisposing");
|
||||
_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");
|
||||
_setPlayerData = pi.GetIpcSubscriber<string, object>("PetRenamer.SetPlayerData");
|
||||
_clearPlayerData = pi.GetIpcSubscriber<ushort, object>("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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||
<PropertyGroup>
|
||||
<AssemblyName>UmbraSync</AssemblyName>
|
||||
<Version>0.1.0.0</Version>
|
||||
<PackageProjectUrl>https://git.umbra-sync.net/SirConstance/UmbraClient</PackageProjectUrl>
|
||||
<RootNamespace>UmbraSync</RootNamespace>
|
||||
<Version>0.1.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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<PairHandler>(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory,
|
||||
_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 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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@ public sealed class Plugin : IDalamudPlugin
|
||||
public static Plugin Self;
|
||||
#pragma warning restore CA2211, CS8618, MA0069, S1104, S2223
|
||||
public Action<IFramework>? 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<IpcCallerMare>();
|
||||
collection.AddSingleton<IpcManager>();
|
||||
collection.AddSingleton<NotificationService>();
|
||||
collection.AddSingleton<NoSnapService>();
|
||||
|
||||
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<IConfigService<IMareConfiguration>>(s => s.GetRequiredService<RemoteConfigCacheService>());
|
||||
collection.AddSingleton<ConfigurationMigrator>();
|
||||
collection.AddSingleton<ConfigurationSaveService>();
|
||||
collection.AddSingleton<RemoteConfigurationService>();
|
||||
|
||||
collection.AddSingleton<HubFactory>();
|
||||
|
||||
@@ -209,7 +205,6 @@ public sealed class Plugin : IDalamudPlugin
|
||||
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
||||
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
|
||||
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
||||
collection.AddHostedService(p => p.GetRequiredService<NoSnapService>());
|
||||
})
|
||||
.Build();
|
||||
|
||||
|
||||
@@ -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<string, HandledCharaDataEntry> _handledCharaData = new(StringComparer.Ordinal);
|
||||
|
||||
public IReadOnlyDictionary<string, HandledCharaDataEntry> HandledCharaData => _handledCharaData;
|
||||
|
||||
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> 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<GposeEndMessage>(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<string, CharaDataMetaInfoExtendedDto?> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
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<SwitchToMainUiMessage>(this, (_) => IsOpen = true);
|
||||
Mediator.Subscribe<SwitchToIntroUiMessage>(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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -17,18 +17,16 @@ public sealed class AccountRegistrationService : IDisposable
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<AccountRegistrationService> _logger;
|
||||
private readonly ServerConfigurationManager _serverManager;
|
||||
private readonly RemoteConfigurationService _remoteConfig;
|
||||
|
||||
private string GenerateSecretKey()
|
||||
{
|
||||
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;
|
||||
_serverManager = serverManager;
|
||||
_remoteConfig = remoteConfig;
|
||||
_httpClient = new(
|
||||
new HttpClientHandler
|
||||
{
|
||||
@@ -47,22 +45,10 @@ public sealed class AccountRegistrationService : IDisposable
|
||||
|
||||
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 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)));
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ 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 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";
|
||||
|
||||
|
||||
@@ -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<HubFactory> 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<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))
|
||||
{
|
||||
return _cachedConfig;
|
||||
defaultConfig = _cachedConfig;
|
||||
}
|
||||
var defaultConfig = new HubConnectionConfig
|
||||
else
|
||||
{
|
||||
defaultConfig = new HubConnectionConfig
|
||||
{
|
||||
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))
|
||||
mainServerConfig.ApiUrl = ApiController.UmbraServiceApiUri;
|
||||
if (string.IsNullOrEmpty(mainServerConfig.HubUrl))
|
||||
mainServerConfig.HubUrl = ApiController.UmbraServiceHubUri;
|
||||
|
||||
mainServerConfig.Transports ??= defaultConfig.Transports ?? [];
|
||||
return mainServerConfig;
|
||||
}
|
||||
|
||||
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<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;
|
||||
}
|
||||
}
|
||||
|
||||
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 =
|
||||
|
||||
@@ -20,16 +20,14 @@ public sealed class TokenProvider : IDisposable, IMediatorSubscriber
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<TokenProvider> _logger;
|
||||
private readonly ServerConfigurationManager _serverManager;
|
||||
private readonly RemoteConfigurationService _remoteConfig;
|
||||
private readonly ConcurrentDictionary<JwtIdentifier, string> _tokenCache = new();
|
||||
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)
|
||||
{
|
||||
_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<HubConnectionConfig>("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 _)!;
|
||||
|
||||
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