Remove nefarious services that use Reflection, and intefere with other plugins.
Remove display of registration for main service.
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"Author": "tb",
|
"Author": "tb",
|
||||||
"Name": "Club Penguin Sync",
|
"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.",
|
"Description": "This plugin will synchronize your Penumbra mods and current Glamourer state with other paired clients automatically.",
|
||||||
"InternalName": "ClubPenguinSync",
|
"InternalName": "ClubPenguinSync",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"Tags": [
|
"Tags": [
|
||||||
"customization"
|
"customization"
|
||||||
],
|
],
|
||||||
"IconUrl": "https://raw.githubusercontent.com/loporrit/MareClient/way4/MareSynchronos/images/icon.png",
|
"IconUrl": "https://clubpenguin.drgn.rocks/icon.png",
|
||||||
"RepoUrl": "https://github.com/Rawrington/nope",
|
"RepoUrl": "https://git.drgn.rocks/t0w0bi/ClubPenguinClient/",
|
||||||
"CanUnloadAsync": true
|
"CanUnloadAsync": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<Project Sdk="Dalamud.NET.Sdk/13.1.0">
|
<Project Sdk="Dalamud.NET.Sdk/13.1.0">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>ClubPenguinSync</AssemblyName>
|
<AssemblyName>ClubPenguinSync</AssemblyName>
|
||||||
<Version>1.7.0.7</Version>
|
<Version>1.7.0.8</Version>
|
||||||
<PackageProjectUrl>https://github.com/Rawrington/ClubPenguinSync/</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Rawrington/ClubPenguinSync/</PackageProjectUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,13 @@ public class PairHandlerFactory
|
|||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
|
|
||||||
public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager,
|
public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager,
|
||||||
FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService,
|
FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService,
|
||||||
PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime,
|
PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime,
|
||||||
FileCacheManager fileCacheManager, MareMediator mareMediator, PlayerPerformanceService playerPerformanceService,
|
FileCacheManager fileCacheManager, MareMediator mareMediator, PlayerPerformanceService playerPerformanceService,
|
||||||
ServerConfigurationManager serverConfigManager, PairAnalyzerFactory pairAnalyzerFactory,
|
ServerConfigurationManager serverConfigManager, PairAnalyzerFactory pairAnalyzerFactory,
|
||||||
MareConfigService configService, VisibilityService visibilityService, NoSnapService noSnapService)
|
MareConfigService configService, VisibilityService visibilityService)
|
||||||
{
|
{
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
||||||
@@ -50,13 +49,12 @@ public class PairHandlerFactory
|
|||||||
_pairAnalyzerFactory = pairAnalyzerFactory;
|
_pairAnalyzerFactory = pairAnalyzerFactory;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PairHandler Create(Pair pair)
|
public PairHandler Create(Pair pair)
|
||||||
{
|
{
|
||||||
return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory,
|
return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory,
|
||||||
_ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime,
|
_ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime,
|
||||||
_fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService, _noSnapService);
|
_fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
private readonly ServerConfigurationManager _serverConfigManager;
|
private readonly ServerConfigurationManager _serverConfigManager;
|
||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
||||||
private Guid _applicationId;
|
private Guid _applicationId;
|
||||||
private Task? _applicationTask;
|
private Task? _applicationTask;
|
||||||
@@ -55,8 +54,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
FileCacheManager fileDbManager, MareMediator mediator,
|
FileCacheManager fileDbManager, MareMediator mediator,
|
||||||
PlayerPerformanceService playerPerformanceService,
|
PlayerPerformanceService playerPerformanceService,
|
||||||
ServerConfigurationManager serverConfigManager,
|
ServerConfigurationManager serverConfigManager,
|
||||||
MareConfigService configService, VisibilityService visibilityService,
|
MareConfigService configService, VisibilityService visibilityService) : base(logger, mediator)
|
||||||
NoSnapService noSnapService) : base(logger, mediator)
|
|
||||||
{
|
{
|
||||||
Pair = pair;
|
Pair = pair;
|
||||||
PairAnalyzer = pairAnalyzer;
|
PairAnalyzer = pairAnalyzer;
|
||||||
@@ -70,7 +68,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
_serverConfigManager = serverConfigManager;
|
_serverConfigManager = serverConfigManager;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
|
|
||||||
_visibilityService.StartTracking(Pair.Ident);
|
_visibilityService.StartTracking(Pair.Ident);
|
||||||
|
|
||||||
@@ -332,7 +329,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
var gposeName = actor.Name.TextValue;
|
var gposeName = actor.Name.TextValue;
|
||||||
if (!name.Equals(gposeName, StringComparison.Ordinal))
|
if (!name.Equals(gposeName, StringComparison.Ordinal))
|
||||||
continue;
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -215,11 +215,6 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID))
|
if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID))
|
||||||
HoldApplication("Blacklist", maxValue: 1);
|
HoldApplication("Blacklist", maxValue: 1);
|
||||||
|
|
||||||
if (NoSnapService.AnyLoaded)
|
|
||||||
HoldApplication("NoSnap", maxValue: 1);
|
|
||||||
else
|
|
||||||
UnholdApplication("NoSnap", skipApplication: true);
|
|
||||||
|
|
||||||
CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced);
|
CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<BlockedCharacterHandler>();
|
collection.AddSingleton<BlockedCharacterHandler>();
|
||||||
collection.AddSingleton<IpcProvider>();
|
collection.AddSingleton<IpcProvider>();
|
||||||
collection.AddSingleton<VisibilityService>();
|
collection.AddSingleton<VisibilityService>();
|
||||||
collection.AddSingleton<RepoChangeService>();
|
|
||||||
collection.AddSingleton<EventAggregator>();
|
collection.AddSingleton<EventAggregator>();
|
||||||
collection.AddSingleton<DalamudUtilService>();
|
collection.AddSingleton<DalamudUtilService>();
|
||||||
collection.AddSingleton<DtrEntry>();
|
collection.AddSingleton<DtrEntry>();
|
||||||
@@ -182,7 +181,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<IpcCallerMare>();
|
collection.AddSingleton<IpcCallerMare>();
|
||||||
collection.AddSingleton<IpcManager>();
|
collection.AddSingleton<IpcManager>();
|
||||||
collection.AddSingleton<NotificationService>();
|
collection.AddSingleton<NotificationService>();
|
||||||
collection.AddSingleton<NoSnapService>();
|
|
||||||
|
|
||||||
collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName));
|
collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName));
|
||||||
collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName));
|
collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName));
|
||||||
@@ -248,8 +246,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
|
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<RepoChangeService>());
|
|
||||||
collection.AddHostedService(p => p.GetRequiredService<NoSnapService>());
|
|
||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -13,20 +13,18 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
private readonly IpcManager _ipcManager;
|
private readonly IpcManager _ipcManager;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
private readonly Dictionary<string, HandledCharaDataEntry> _handledCharaData = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, HandledCharaDataEntry> _handledCharaData = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, HandledCharaDataEntry> HandledCharaData => _handledCharaData;
|
public IReadOnlyDictionary<string, HandledCharaDataEntry> HandledCharaData => _handledCharaData;
|
||||||
|
|
||||||
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> logger, MareMediator mediator,
|
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> logger, MareMediator mediator,
|
||||||
GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService,
|
GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService,
|
||||||
IpcManager ipcManager, NoSnapService noSnapService)
|
IpcManager ipcManager)
|
||||||
: base(logger, mediator)
|
: base(logger, mediator)
|
||||||
{
|
{
|
||||||
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
||||||
_dalamudUtilService = dalamudUtilService;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
mediator.Subscribe<GposeEndMessage>(this, msg =>
|
mediator.Subscribe<GposeEndMessage>(this, msg =>
|
||||||
{
|
{
|
||||||
foreach (var chara in _handledCharaData)
|
foreach (var chara in _handledCharaData)
|
||||||
@@ -94,7 +92,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
_handledCharaData.Remove(handled.Name);
|
_handledCharaData.Remove(handled.Name);
|
||||||
await _dalamudUtilService.RunOnFrameworkThread(async () =>
|
await _dalamudUtilService.RunOnFrameworkThread(async () =>
|
||||||
{
|
{
|
||||||
RemoveGposer(handled);
|
|
||||||
await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false);
|
await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false);
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
return true;
|
return true;
|
||||||
@@ -103,7 +100,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry)
|
internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry)
|
||||||
{
|
{
|
||||||
_handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry);
|
_handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry);
|
||||||
_ = _dalamudUtilService.RunOnFrameworkThread(() => AddGposer(handledCharaDataEntry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateHandledData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
public void UpdateHandledData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
||||||
@@ -134,23 +130,4 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
if (handler.Address == nint.Zero) return null;
|
if (handler.Address == nint.Zero) return null;
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGposerObjectIndex(string name)
|
|
||||||
{
|
|
||||||
return _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, _dalamudUtilService.IsInGpose)?.ObjectIndex ?? -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddGposer(HandledCharaDataEntry handled)
|
|
||||||
{
|
|
||||||
int objectIndex = GetGposerObjectIndex(handled.Name);
|
|
||||||
if (objectIndex > 0)
|
|
||||||
_noSnapService.AddGposer(objectIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveGposer(HandledCharaDataEntry handled)
|
|
||||||
{
|
|
||||||
int objectIndex = GetGposerObjectIndex(handled.Name);
|
|
||||||
if (objectIndex > 0)
|
|
||||||
_noSnapService.RemoveGposer(objectIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
{
|
|
||||||
["QQSnapper"] = false,
|
|
||||||
["QQSnappy"] = false,
|
|
||||||
["QQMeddle.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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; }
|
|
||||||
}
|
|
||||||
@@ -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<T>(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<T>(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<object>(), 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<object>(), 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<object> 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<System.Collections.IList>(conf, "ThirdRepoList").Add(instance!);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveRepo(string repoURL)
|
|
||||||
{
|
|
||||||
var toRemove = new List<object>();
|
|
||||||
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<RepoChangeService> _logger;
|
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
private readonly IDalamudPluginInterface _pluginInterface;
|
|
||||||
private readonly IFramework _framework;
|
|
||||||
|
|
||||||
public RepoChangeService(ILogger<RepoChangeService> 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<RepoChangeConfig>("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<string> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -247,7 +247,7 @@ This service is provided as-is.
|
|||||||
ImGui.BeginDisabled(_registrationInProgress || _uiShared.ApiController.ServerState == ServerState.Connecting || _uiShared.ApiController.ServerState == ServerState.Reconnecting);
|
ImGui.BeginDisabled(_registrationInProgress || _uiShared.ApiController.ServerState == ServerState.Connecting || _uiShared.ApiController.ServerState == ServerState.Reconnecting);
|
||||||
_ = _uiShared.DrawServiceSelection(selectOnChange: true, intro: true);
|
_ = _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.BeginDisabled(_registrationInProgress || _registrationSuccess || _secretKey.Length > 0);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
@@ -297,6 +297,12 @@ This service is provided as-is.
|
|||||||
ImGui.TextWrapped(_registrationMessage);
|
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();
|
ImGui.Separator();
|
||||||
|
|
||||||
|
|||||||
@@ -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.");
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
else if (NoSnapService.AnyLoaded)
|
|
||||||
{
|
|
||||||
IconText(FontAwesomeIcon.ExclamationTriangle, ImGuiColors.DalamudYellow);
|
|
||||||
ImGui.SameLine();
|
|
||||||
var cursorX = ImGui.GetCursorPosX();
|
|
||||||
ImGui.TextColored(ImGuiColors.DalamudYellow, "Synced player appearances will not apply until incompatible plugins are disabled:");
|
|
||||||
ImGui.SetCursorPosX(cursorX + 16.0f);
|
|
||||||
ImGui.TextColored(ImGuiColors.DalamudYellow, NoSnapService.ActivePlugins);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user