From 00cc07efa4539f24a135206fc7c5f4f1fa685fc5 Mon Sep 17 00:00:00 2001 From: t0w0bi Date: Wed, 10 Sep 2025 20:00:04 +0100 Subject: [PATCH] Remove nefarious services that use Reflection, and intefere with other plugins. Remove display of registration for main service. --- MareSynchronos/ClubPenguinSync.json | 6 +- MareSynchronos/MareSynchronos.csproj | 2 +- .../Factories/PairHandlerFactory.cs | 6 +- .../PlayerData/Handlers/PairHandler.cs | 10 +- MareSynchronos/PlayerData/Pairs/Pair.cs | 5 - MareSynchronos/Plugin.cs | 4 - .../CharaData/CharaDataCharacterHandler.cs | 25 +- MareSynchronos/Services/NoSnapService.cs | 226 ---------- MareSynchronos/Services/RepoChangeConfig.cs | 12 - MareSynchronos/Services/RepoChangeService.cs | 401 ------------------ MareSynchronos/UI/IntroUI.cs | 8 +- MareSynchronos/UI/UISharedService.cs | 10 - 12 files changed, 15 insertions(+), 700 deletions(-) delete mode 100644 MareSynchronos/Services/NoSnapService.cs delete mode 100644 MareSynchronos/Services/RepoChangeConfig.cs delete mode 100644 MareSynchronos/Services/RepoChangeService.cs diff --git a/MareSynchronos/ClubPenguinSync.json b/MareSynchronos/ClubPenguinSync.json index 85145e8..746bc31 100644 --- a/MareSynchronos/ClubPenguinSync.json +++ b/MareSynchronos/ClubPenguinSync.json @@ -1,14 +1,14 @@ { "Author": "tb", "Name": "Club Penguin Sync", - "Punchline": "Social modding for everyone!", + "Punchline": "Social modding for cool penguins!", "Description": "This plugin will synchronize your Penumbra mods and current Glamourer state with other paired clients automatically.", "InternalName": "ClubPenguinSync", "ApplicableVersion": "any", "Tags": [ "customization" ], - "IconUrl": "https://raw.githubusercontent.com/loporrit/MareClient/way4/MareSynchronos/images/icon.png", - "RepoUrl": "https://github.com/Rawrington/nope", + "IconUrl": "https://clubpenguin.drgn.rocks/icon.png", + "RepoUrl": "https://git.drgn.rocks/t0w0bi/ClubPenguinClient/", "CanUnloadAsync": true } diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index 63cc14d..417cc99 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -2,7 +2,7 @@ ClubPenguinSync - 1.7.0.7 + 1.7.0.8 https://github.com/Rawrington/ClubPenguinSync/ 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 3ab1f04..e4180f7 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); @@ -332,7 +329,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase var gposeName = actor.Name.TextValue; if (!name.Equals(gposeName, StringComparison.Ordinal)) continue; - _noSnapService.AddGposer(actor.ObjectIndex); } }); } @@ -385,10 +381,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 563c23a..f300317 100644 --- a/MareSynchronos/PlayerData/Pairs/Pair.cs +++ b/MareSynchronos/PlayerData/Pairs/Pair.cs @@ -215,11 +215,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 81323c6..7b29d63 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -165,7 +165,6 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); - collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); @@ -182,7 +181,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)); @@ -248,8 +246,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()); - 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/NoSnapService.cs b/MareSynchronos/Services/NoSnapService.cs deleted file mode 100644 index 95c7647..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) - { - ["QQSnapper"] = false, - ["QQSnappy"] = false, - ["QQMeddle.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/RepoChangeConfig.cs b/MareSynchronos/Services/RepoChangeConfig.cs deleted file mode 100644 index eaf0b2e..0000000 --- a/MareSynchronos/Services/RepoChangeConfig.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Text.Json.Serialization; - -namespace MareSynchronos.Services; - -public record RepoChangeConfig -{ - [JsonPropertyName("current_repo")] - public string? CurrentRepo { get; set; } - - [JsonPropertyName("valid_repos")] - public string[]? ValidRepos { get; set; } -} \ No newline at end of file diff --git a/MareSynchronos/Services/RepoChangeService.cs b/MareSynchronos/Services/RepoChangeService.cs deleted file mode 100644 index 3265e02..0000000 --- a/MareSynchronos/Services/RepoChangeService.cs +++ /dev/null @@ -1,401 +0,0 @@ -using Dalamud.Plugin; -using Dalamud.Plugin.Services; -using Dalamud.Utility; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System.Reflection; - -namespace MareSynchronos.Services; - -/* Reflection code based almost entirely on ECommons DalamudReflector - -MIT License - -Copyright (c) 2023 NightmareXIV - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -public sealed class RepoChangeService : IHostedService -{ - #region Reflection Helpers - private const BindingFlags AllFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; - private const BindingFlags StaticFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; - private const BindingFlags InstanceFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - - private static object GetFoP(object obj, string name) - { - Type? type = obj.GetType(); - while (type != null) - { - var fieldInfo = type.GetField(name, AllFlags); - if (fieldInfo != null) - { - return fieldInfo.GetValue(obj)!; - } - var propertyInfo = type.GetProperty(name, AllFlags); - if (propertyInfo != null) - { - return propertyInfo.GetValue(obj)!; - } - type = type.BaseType; - } - throw new Exception($"Reflection GetFoP failed (not found: {obj.GetType().Name}.{name})"); - } - - private static T GetFoP(object obj, string name) - { - return (T)GetFoP(obj, name); - } - - private static void SetFoP(object obj, string name, object value) - { - var type = obj.GetType(); - var field = type.GetField(name, AllFlags); - if (field != null) - { - field.SetValue(obj, value); - } - else - { - var prop = type.GetProperty(name, AllFlags)!; - if (prop == null) - throw new Exception($"Reflection SetFoP failed (not found: {type.Name}.{name})"); - prop.SetValue(obj, value); - } - } - - private static object? Call(object obj, string name, object[] @params, bool matchExactArgumentTypes = false) - { - MethodInfo? info; - var type = obj.GetType(); - if (!matchExactArgumentTypes) - { - info = type.GetMethod(name, AllFlags); - } - else - { - info = type.GetMethod(name, AllFlags, @params.Select(x => x.GetType()).ToArray()); - } - if (info == null) - throw new Exception($"Reflection Call failed (not found: {type.Name}.{name})"); - return info.Invoke(obj, @params); - } - - private static T Call(object obj, string name, object[] @params, bool matchExactArgumentTypes = false) - { - return (T)Call(obj, name, @params, matchExactArgumentTypes)!; - } - #endregion - - #region Dalamud Reflection - public object GetService(string serviceFullName) - { - return _pluginInterface.GetType().Assembly. - GetType("Dalamud.Service`1", true)!.MakeGenericType(_pluginInterface.GetType().Assembly.GetType(serviceFullName, true)!). - GetMethod("Get")!.Invoke(null, BindingFlags.Default, null, Array.Empty(), null)!; - } - - private object GetPluginManager() - { - return _pluginInterface.GetType().Assembly. - GetType("Dalamud.Service`1", true)!.MakeGenericType(_pluginInterface.GetType().Assembly.GetType("Dalamud.Plugin.Internal.PluginManager", true)!). - GetMethod("Get")!.Invoke(null, BindingFlags.Default, null, Array.Empty(), null)!; - } - - private void ReloadPluginMasters() - { - var mgr = GetService("Dalamud.Plugin.Internal.PluginManager"); - var pluginReload = mgr.GetType().GetMethod("SetPluginReposFromConfigAsync", BindingFlags.Instance | BindingFlags.Public)!; - pluginReload.Invoke(mgr, [true]); - } - - public void SaveDalamudConfig() - { - var conf = GetService("Dalamud.Configuration.Internal.DalamudConfiguration"); - var configSave = conf?.GetType().GetMethod("QueueSave", BindingFlags.Instance | BindingFlags.Public); - configSave?.Invoke(conf, null); - } - - private IEnumerable GetRepoByURL(string repoURL) - { - var conf = GetService("Dalamud.Configuration.Internal.DalamudConfiguration"); - var repolist = (System.Collections.IEnumerable)GetFoP(conf, "ThirdRepoList"); - foreach (var r in repolist) - { - if (((string)GetFoP(r, "Url")).Equals(repoURL, StringComparison.OrdinalIgnoreCase)) - yield return r; - } - } - - private bool HasRepo(string repoURL) - { - var conf = GetService("Dalamud.Configuration.Internal.DalamudConfiguration"); - var repolist = (System.Collections.IEnumerable)GetFoP(conf, "ThirdRepoList"); - foreach (var r in repolist) - { - if (((string)GetFoP(r, "Url")).Equals(repoURL, StringComparison.OrdinalIgnoreCase)) - return true; - } - return false; - } - - private void AddRepo(string repoURL, bool enabled) - { - var conf = GetService("Dalamud.Configuration.Internal.DalamudConfiguration"); - var repolist = (System.Collections.IEnumerable)GetFoP(conf, "ThirdRepoList"); - foreach (var r in repolist) - { - if (((string)GetFoP(r, "Url")).Equals(repoURL, StringComparison.OrdinalIgnoreCase)) - return; - } - var instance = Activator.CreateInstance(_pluginInterface.GetType().Assembly.GetType("Dalamud.Configuration.ThirdPartyRepoSettings")!)!; - SetFoP(instance, "Url", repoURL); - SetFoP(instance, "IsEnabled", enabled); - GetFoP(conf, "ThirdRepoList").Add(instance!); - } - - private void RemoveRepo(string repoURL) - { - var toRemove = new List(); - var conf = GetService("Dalamud.Configuration.Internal.DalamudConfiguration"); - var repolist = (System.Collections.IList)GetFoP(conf, "ThirdRepoList"); - foreach (var r in repolist) - { - if (((string)GetFoP(r, "Url")).Equals(repoURL, StringComparison.OrdinalIgnoreCase)) - toRemove.Add(r); - } - foreach (var r in toRemove) - repolist.Remove(r); - } - - public List<(object LocalPlugin, string InstalledFromUrl)> GetLocalPluginsByName(string internalName) - { - List<(object LocalPlugin, string RepoURL)> result = []; - - var pluginManager = GetPluginManager(); - var installedPlugins = (System.Collections.IList)pluginManager.GetType().GetProperty("InstalledPlugins")!.GetValue(pluginManager)!; - - foreach (var plugin in installedPlugins) - { - if (((string)plugin.GetType().GetProperty("InternalName")!.GetValue(plugin)!).Equals(internalName, StringComparison.Ordinal)) - { - var type = plugin.GetType(); - if (type.Name.Equals("LocalDevPlugin", StringComparison.Ordinal)) - continue; - var manifest = GetFoP(plugin, "manifest"); - string installedFromUrl = (string)GetFoP(manifest, "InstalledFromUrl"); - result.Add((plugin, installedFromUrl)); - } - } - - return result; - } - #endregion - - private readonly ILogger _logger; - private readonly RemoteConfigurationService _remoteConfig; - private readonly IDalamudPluginInterface _pluginInterface; - private readonly IFramework _framework; - - public RepoChangeService(ILogger logger, RemoteConfigurationService remoteConfig, IDalamudPluginInterface pluginInterface, IFramework framework) - { - _logger = logger; - _remoteConfig = remoteConfig; - _pluginInterface = pluginInterface; - _framework = framework; - } - - public async Task StartAsync(CancellationToken cancellationToken) - { - _logger.LogDebug("Starting RepoChange Service"); - var repoChangeConfig = await _remoteConfig.GetConfigAsync("repoChange").ConfigureAwait(false) ?? new(); - - var currentRepo = repoChangeConfig.CurrentRepo; - var validRepos = (repoChangeConfig.ValidRepos ?? []).ToList(); - - if (!currentRepo.IsNullOrEmpty() && !validRepos.Contains(currentRepo, StringComparer.Ordinal)) - validRepos.Add(currentRepo); - - if (validRepos.Count == 0) - { - _logger.LogInformation("No valid repos configured, skipping"); - return; - } - - await _framework.RunOnTick(() => - { - try - { - var internalName = Assembly.GetExecutingAssembly().GetName().Name!; - var localPlugins = GetLocalPluginsByName(internalName); - - var suffix = string.Empty; - - if (localPlugins.Count == 0) - { - _logger.LogInformation("Skipping: No intalled plugin found"); - return; - } - - var hasValidCustomRepoUrl = false; - - foreach (var vr in validRepos) - { - var vrCN = vr.Replace(".json", "_CN.json", StringComparison.Ordinal); - var vrKR = vr.Replace(".json", "_KR.json", StringComparison.Ordinal); - if (HasRepo(vr) || HasRepo(vrCN) || HasRepo(vrKR)) - { - hasValidCustomRepoUrl = true; - break; - } - } - - List oldRepos = []; - var pluginRepoUrl = localPlugins[0].InstalledFromUrl; - - if (pluginRepoUrl.Contains("_CN.json", StringComparison.Ordinal)) - suffix = "_CN"; - else if (pluginRepoUrl.Contains("_KR.json", StringComparison.Ordinal)) - suffix = "_KR"; - - bool hasOldPluginRepoUrl = false; - - foreach (var plugin in localPlugins) - { - foreach (var vr in validRepos) - { - var validRepo = vr.Replace(".json", $"{suffix}.json"); - if (!plugin.InstalledFromUrl.Equals(validRepo, StringComparison.Ordinal)) - { - oldRepos.Add(plugin.InstalledFromUrl); - hasOldPluginRepoUrl = true; - } - } - } - - if (hasValidCustomRepoUrl) - { - if (hasOldPluginRepoUrl) - _logger.LogInformation("Result: Repo URL is up to date, but plugin install source is incorrect"); - else - _logger.LogInformation("Result: Repo URL is up to date"); - } - else - { - _logger.LogInformation("Result: Repo URL needs to be replaced"); - } - - if (currentRepo.IsNullOrEmpty()) - { - _logger.LogWarning("No current repo URL configured"); - return; - } - - // Pre-test plugin repo url rewriting to ensure it succeeds before replacing the custom repo URL - if (hasOldPluginRepoUrl) - { - foreach (var plugin in localPlugins) - { - var manifest = GetFoP(plugin.LocalPlugin, "manifest"); - if (manifest == null) - throw new Exception("Plugin manifest is null"); - var manifestFile = GetFoP(plugin.LocalPlugin, "manifestFile"); - if (manifestFile == null) - throw new Exception("Plugin manifestFile is null"); - var repo = GetFoP(manifest, "InstalledFromUrl"); - if (((string)repo).IsNullOrEmpty()) - throw new Exception("Plugin repo url is null or empty"); - SetFoP(manifest, "InstalledFromUrl", repo); - } - } - - if (!hasValidCustomRepoUrl) - { - try - { - foreach (var oldRepo in oldRepos) - { - _logger.LogInformation("* Removing old repo: {r}", oldRepo); - RemoveRepo(oldRepo); - } - } - finally - { - _logger.LogInformation("* Adding current repo: {r}", currentRepo); - AddRepo(currentRepo, true); - } - } - - // This time do it for real, and crash the game if we fail, to avoid saving a broken state - if (hasOldPluginRepoUrl) - { - try - { - _logger.LogInformation("* Updating plugins"); - foreach (var plugin in localPlugins) - { - var manifest = GetFoP(plugin.LocalPlugin, "manifest"); - if (manifest == null) - throw new Exception("Plugin manifest is null"); - var manifestFile = GetFoP(plugin.LocalPlugin, "manifestFile"); - if (manifestFile == null) - throw new Exception("Plugin manifestFile is null"); - var repo = GetFoP(manifest, "InstalledFromUrl"); - if (((string)repo).IsNullOrEmpty()) - throw new Exception("Plugin repo url is null or empty"); - SetFoP(manifest, "InstalledFromUrl", currentRepo); - Call(manifest, "Save", [manifestFile, "RepoChange"]); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Exception while changing plugin install repo"); - foreach (var oldRepo in oldRepos) - { - _logger.LogInformation("* Restoring old repo: {r}", oldRepo); - AddRepo(oldRepo, true); - } - } - } - - if (!hasValidCustomRepoUrl || hasOldPluginRepoUrl) - { - _logger.LogInformation("* Saving dalamud config"); - SaveDalamudConfig(); - _logger.LogInformation("* Reloading plugin masters"); - ReloadPluginMasters(); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Exception in RepoChangeService"); - } - }, default, 10, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Started RepoChangeService"); - } - - public Task StopAsync(CancellationToken cancellationToken) - { - _ = cancellationToken; - _logger.LogDebug("Stopping RepoChange Service"); - return Task.CompletedTask; - } -} diff --git a/MareSynchronos/UI/IntroUI.cs b/MareSynchronos/UI/IntroUI.cs index 6a12719..f69e033 100644 --- a/MareSynchronos/UI/IntroUI.cs +++ b/MareSynchronos/UI/IntroUI.cs @@ -247,7 +247,7 @@ This service is provided as-is. ImGui.BeginDisabled(_registrationInProgress || _uiShared.ApiController.ServerState == ServerState.Connecting || _uiShared.ApiController.ServerState == ServerState.Reconnecting); _ = _uiShared.DrawServiceSelection(selectOnChange: true, intro: true); - if (true) // Enable registration button for all servers + if (_serverConfigurationManager.CurrentApiUrl == null || !_serverConfigurationManager.CurrentApiUrl.Equals(ApiController.ClubPenguinServiceUri, StringComparison.Ordinal)) // Enable registration button for all servers { ImGui.BeginDisabled(_registrationInProgress || _registrationSuccess || _secretKey.Length > 0); ImGui.Separator(); @@ -297,6 +297,12 @@ This service is provided as-is. ImGui.TextWrapped(_registrationMessage); } } + else + { + ImGui.Separator(); + UiSharedService.TextWrapped("You must join the discord to register a Club Penguin Sync account on the main server."); + UiSharedService.TextWrapped("Use the /signup command to register an account within the discord follow the instructiosn in the #how-to-setup channel."); + } ImGui.Separator(); diff --git a/MareSynchronos/UI/UISharedService.cs b/MareSynchronos/UI/UISharedService.cs index 769af27..7f1bed5 100644 --- a/MareSynchronos/UI/UISharedService.cs +++ b/MareSynchronos/UI/UISharedService.cs @@ -852,16 +852,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 Club Penguin Sync."); 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; }