mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-30 12:23:39 +01:00
Plugin manager cleanup (#815)
This commit is contained in:
parent
d676473928
commit
0b6417fd7c
9 changed files with 217 additions and 175 deletions
|
|
@ -104,7 +104,7 @@ namespace Dalamud.Plugin.Internal
|
|||
/// <summary>
|
||||
/// Gets a value indicating whether plugins are not still loading from boot.
|
||||
/// </summary>
|
||||
public bool PluginsReady { get; private set; } = false;
|
||||
public bool PluginsReady { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether all added repos are not in progress.
|
||||
|
|
@ -121,6 +121,82 @@ namespace Dalamud.Plugin.Internal
|
|||
/// </summary>
|
||||
public PluginConfigurations PluginConfigs { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Print to chat any plugin updates and whether they were successful.
|
||||
/// </summary>
|
||||
/// <param name="updateMetadata">The list of updated plugin metadata.</param>
|
||||
/// <param name="header">The header text to send to chat prior to any update info.</param>
|
||||
public static void PrintUpdatedPlugins(List<PluginUpdateStatus>? updateMetadata, string header)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
|
||||
if (updateMetadata is { Count: > 0 })
|
||||
{
|
||||
chatGui.Print(header);
|
||||
|
||||
foreach (var metadata in updateMetadata)
|
||||
{
|
||||
if (metadata.WasUpdated)
|
||||
{
|
||||
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
|
||||
}
|
||||
else
|
||||
{
|
||||
chatGui.PrintChat(new XivChatEntry
|
||||
{
|
||||
Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version),
|
||||
Type = XivChatType.Urgent,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For a given manifest, determine if the testing version should be used over the normal version.
|
||||
/// The higher of the two versions is calculated after checking other settings.
|
||||
/// </summary>
|
||||
/// <param name="manifest">Manifest to check.</param>
|
||||
/// <returns>A value indicating whether testing should be used.</returns>
|
||||
public static bool UseTesting(PluginManifest manifest)
|
||||
{
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
if (!configuration.DoPluginTest)
|
||||
return false;
|
||||
|
||||
if (manifest.IsTestingExclusive)
|
||||
return true;
|
||||
|
||||
var av = manifest.AssemblyVersion;
|
||||
var tv = manifest.TestingAssemblyVersion;
|
||||
var hasTv = tv != null;
|
||||
|
||||
if (hasTv)
|
||||
{
|
||||
return tv > av;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the given repo manifest should be visible to the user.
|
||||
/// </summary>
|
||||
/// <param name="manifest">Repo manifest.</param>
|
||||
/// <returns>If the manifest is visible.</returns>
|
||||
public static bool IsManifestVisible(RemotePluginManifest manifest)
|
||||
{
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
// Hidden by user
|
||||
if (configuration.HiddenPluginInternalName.Contains(manifest.InternalName))
|
||||
return false;
|
||||
|
||||
// Hidden by manifest
|
||||
return !manifest.IsHide;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
@ -144,7 +220,7 @@ namespace Dalamud.Plugin.Internal
|
|||
/// Set the list of repositories to use and downloads their contents.
|
||||
/// Should be called when the Settings window has been updated or at instantiation.
|
||||
/// </summary>
|
||||
/// <param name="notify">Whether the available plugins changed should be evented after.</param>
|
||||
/// <param name="notify">Whether the available plugins changed event should be sent after.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public async Task SetPluginReposFromConfigAsync(bool notify)
|
||||
{
|
||||
|
|
@ -198,7 +274,7 @@ namespace Dalamud.Plugin.Internal
|
|||
|
||||
var manifest = LocalPluginManifest.Load(manifestFile);
|
||||
|
||||
pluginDefs.Add(new(dllFile, manifest, false));
|
||||
pluginDefs.Add(new PluginDef(dllFile, manifest, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +301,7 @@ namespace Dalamud.Plugin.Internal
|
|||
// Manifests are not required for devPlugins. the Plugin type will handle any null manifests.
|
||||
var manifestFile = LocalPluginManifest.GetManifestFile(dllFile);
|
||||
var manifest = manifestFile.Exists ? LocalPluginManifest.Load(manifestFile) : null;
|
||||
devPluginDefs.Add(new(dllFile, manifest, true));
|
||||
devPluginDefs.Add(new PluginDef(dllFile, manifest, true));
|
||||
}
|
||||
|
||||
// Sort for load order - unloaded definitions have default priority of 0
|
||||
|
|
@ -235,9 +311,9 @@ namespace Dalamud.Plugin.Internal
|
|||
// Dev plugins should load first.
|
||||
pluginDefs.InsertRange(0, devPluginDefs);
|
||||
|
||||
void LoadPlugins(IEnumerable<PluginDef> pluginDefs)
|
||||
void LoadPlugins(IEnumerable<PluginDef> pluginDefsList)
|
||||
{
|
||||
foreach (var pluginDef in pluginDefs)
|
||||
foreach (var pluginDef in pluginDefsList)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -260,7 +336,7 @@ namespace Dalamud.Plugin.Internal
|
|||
|
||||
var asyncPlugins = pluginDefs.Where(def => def.Manifest == null || def.Manifest.LoadPriority <= 0);
|
||||
Task.Run(() => LoadPlugins(asyncPlugins))
|
||||
.ContinueWith(task =>
|
||||
.ContinueWith(_ =>
|
||||
{
|
||||
this.PluginsReady = true;
|
||||
this.NotifyInstalledPluginsChanged();
|
||||
|
|
@ -318,7 +394,7 @@ namespace Dalamud.Plugin.Internal
|
|||
this.AvailablePlugins = this.Repos
|
||||
.SelectMany(repo => repo.PluginMaster)
|
||||
.Where(this.IsManifestEligible)
|
||||
.Where(this.IsManifestVisible)
|
||||
.Where(IsManifestVisible)
|
||||
.ToImmutableList();
|
||||
|
||||
if (notify)
|
||||
|
|
@ -412,7 +488,7 @@ namespace Dalamud.Plugin.Internal
|
|||
var response = await Util.HttpClient.GetAsync(downloadUrl);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var outputDir = new DirectoryInfo(Path.Combine(this.pluginDirectory.FullName, repoManifest.InternalName, version.ToString()));
|
||||
var outputDir = new DirectoryInfo(Path.Combine(this.pluginDirectory.FullName, repoManifest.InternalName, version?.ToString() ?? string.Empty));
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -568,7 +644,6 @@ namespace Dalamud.Plugin.Internal
|
|||
{
|
||||
// Out of date plugins get added so they can be updated.
|
||||
Log.Information(ex, $"Plugin was outdated, adding anyways: {dllFile.Name}");
|
||||
// plugin.Disable(); // Don't disable, or it gets deleted next boot.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -625,14 +700,12 @@ namespace Dalamud.Plugin.Internal
|
|||
|
||||
return version;
|
||||
})
|
||||
.Where(version => version != null)
|
||||
.ToArray();
|
||||
|
||||
if (versionDirs.Length == 0)
|
||||
{
|
||||
Log.Information($"No versions: cleaning up {pluginDir.FullName}");
|
||||
pluginDir.Delete(true);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -675,7 +748,6 @@ namespace Dalamud.Plugin.Internal
|
|||
{
|
||||
Log.Information($"Inapplicable version: cleaning up {versionDir.FullName}");
|
||||
versionDir.Delete(true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -737,13 +809,12 @@ namespace Dalamud.Plugin.Internal
|
|||
{
|
||||
InternalName = plugin.Manifest.InternalName,
|
||||
Name = plugin.Manifest.Name,
|
||||
Version = metadata.UseTesting
|
||||
? metadata.UpdateManifest.TestingAssemblyVersion
|
||||
: metadata.UpdateManifest.AssemblyVersion,
|
||||
Version = (metadata.UseTesting
|
||||
? metadata.UpdateManifest.TestingAssemblyVersion
|
||||
: metadata.UpdateManifest.AssemblyVersion)!,
|
||||
WasUpdated = true,
|
||||
};
|
||||
|
||||
updateStatus.WasUpdated = true;
|
||||
|
||||
if (!dryRun)
|
||||
{
|
||||
// Unload if loaded
|
||||
|
|
@ -836,88 +907,6 @@ namespace Dalamud.Plugin.Internal
|
|||
plugin.Load(PluginLoadReason.Installer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print to chat any plugin updates and whether they were successful.
|
||||
/// </summary>
|
||||
/// <param name="updateMetadata">The list of updated plugin metadata.</param>
|
||||
/// <param name="header">The header text to send to chat prior to any update info.</param>
|
||||
public void PrintUpdatedPlugins(List<PluginUpdateStatus> updateMetadata, string header)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
|
||||
if (updateMetadata != null && updateMetadata.Count > 0)
|
||||
{
|
||||
chatGui.Print(header);
|
||||
|
||||
foreach (var metadata in updateMetadata)
|
||||
{
|
||||
if (metadata.WasUpdated)
|
||||
{
|
||||
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
|
||||
}
|
||||
else
|
||||
{
|
||||
chatGui.PrintChat(new XivChatEntry
|
||||
{
|
||||
Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version),
|
||||
Type = XivChatType.Urgent,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For a given manifest, determine if the testing version should be used over the normal version.
|
||||
/// The higher of the two versions is calculated after checking other settings.
|
||||
/// </summary>
|
||||
/// <param name="manifest">Manifest to check.</param>
|
||||
/// <returns>A value indicating whether testing should be used.</returns>
|
||||
public bool UseTesting(PluginManifest manifest)
|
||||
{
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
if (!configuration.DoPluginTest)
|
||||
return false;
|
||||
|
||||
if (manifest.IsTestingExclusive)
|
||||
return true;
|
||||
|
||||
var av = manifest.AssemblyVersion;
|
||||
var tv = manifest.TestingAssemblyVersion;
|
||||
var hasAv = av != null;
|
||||
var hasTv = tv != null;
|
||||
|
||||
if (hasAv && hasTv)
|
||||
{
|
||||
return tv > av;
|
||||
}
|
||||
else
|
||||
{
|
||||
return hasTv;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the given repo manifest should be visible to the user.
|
||||
/// </summary>
|
||||
/// <param name="manifest">Repo manifest.</param>
|
||||
/// <returns>If the manifest is visible.</returns>
|
||||
public bool IsManifestVisible(RemotePluginManifest manifest)
|
||||
{
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
// Hidden by user
|
||||
if (configuration.HiddenPluginInternalName.Contains(manifest.InternalName))
|
||||
return false;
|
||||
|
||||
// Hidden by manifest
|
||||
if (manifest.IsHide)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the given manifest is eligible for ANYTHING. These are hard
|
||||
/// checks that should not allow installation or loading.
|
||||
|
|
@ -942,10 +931,7 @@ namespace Dalamud.Plugin.Internal
|
|||
return false;
|
||||
|
||||
// Banned
|
||||
if (this.IsManifestBanned(manifest))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return !this.IsManifestBanned(manifest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -984,7 +970,7 @@ namespace Dalamud.Plugin.Internal
|
|||
.Where(remoteManifest => plugin.Manifest.InternalName == remoteManifest.InternalName)
|
||||
.Select(remoteManifest =>
|
||||
{
|
||||
var useTesting = this.UseTesting(remoteManifest);
|
||||
var useTesting = UseTesting(remoteManifest);
|
||||
var candidateVersion = useTesting
|
||||
? remoteManifest.TestingAssemblyVersion
|
||||
: remoteManifest.AssemblyVersion;
|
||||
|
|
@ -998,7 +984,7 @@ namespace Dalamud.Plugin.Internal
|
|||
if (updates.Count > 0)
|
||||
{
|
||||
var update = updates.Aggregate((t1, t2) => t1.candidateVersion > t2.candidateVersion ? t1 : t2);
|
||||
updatablePlugins.Add(new(plugin, update.remoteManifest, update.useTesting));
|
||||
updatablePlugins.Add(new AvailablePluginUpdate(plugin, update.remoteManifest, update.useTesting));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1033,41 +1019,6 @@ namespace Dalamud.Plugin.Internal
|
|||
}
|
||||
}
|
||||
|
||||
private struct BannedPlugin
|
||||
{
|
||||
[JsonProperty]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
public Version AssemblyVersion { get; private set; }
|
||||
|
||||
[JsonProperty]
|
||||
public string Reason { get; private set; }
|
||||
}
|
||||
|
||||
private struct PluginDef
|
||||
{
|
||||
public PluginDef(FileInfo dllFile, LocalPluginManifest? manifest, bool isDev)
|
||||
{
|
||||
this.DllFile = dllFile;
|
||||
this.Manifest = manifest;
|
||||
this.IsDev = isDev;
|
||||
}
|
||||
|
||||
public FileInfo DllFile { get; init; }
|
||||
|
||||
public LocalPluginManifest? Manifest { get; init; }
|
||||
|
||||
public bool IsDev { get; init; }
|
||||
|
||||
public static int Sorter(PluginDef def1, PluginDef def2)
|
||||
{
|
||||
var prio1 = def1.Manifest?.LoadPriority ?? 0;
|
||||
var prio2 = def2.Manifest?.LoadPriority ?? 0;
|
||||
return prio2.CompareTo(prio1);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Locs
|
||||
{
|
||||
public static string DalamudPluginUpdateSuccessful(string name, Version version) => Loc.Localize("DalamudPluginUpdateSuccessful", " 》 {0} updated to v{1}.").Format(name, version);
|
||||
|
|
@ -1162,7 +1113,7 @@ namespace Dalamud.Plugin.Internal
|
|||
if (methodBase == null)
|
||||
continue;
|
||||
|
||||
yield return methodBase.Module.Assembly.FullName;
|
||||
yield return methodBase.Module.Assembly.FullName!;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1171,37 +1122,14 @@ namespace Dalamud.Plugin.Internal
|
|||
var targetType = typeof(PluginManager).Assembly.GetType();
|
||||
|
||||
var locationTarget = targetType.GetProperty(nameof(Assembly.Location))!.GetGetMethod();
|
||||
var locationPatch = typeof(PluginManager).GetMethod(nameof(PluginManager.AssemblyLocationPatch), BindingFlags.NonPublic | BindingFlags.Static);
|
||||
var locationPatch = typeof(PluginManager).GetMethod(nameof(AssemblyLocationPatch), BindingFlags.NonPublic | BindingFlags.Static);
|
||||
this.assemblyLocationMonoHook = new MonoMod.RuntimeDetour.Hook(locationTarget, locationPatch);
|
||||
|
||||
#pragma warning disable SYSLIB0012 // Type or member is obsolete
|
||||
var codebaseTarget = targetType.GetProperty(nameof(Assembly.CodeBase)).GetGetMethod();
|
||||
var codebasePatch = typeof(PluginManager).GetMethod(nameof(PluginManager.AssemblyCodeBasePatch), BindingFlags.NonPublic | BindingFlags.Static);
|
||||
#pragma warning disable CS0618
|
||||
var codebaseTarget = targetType.GetProperty(nameof(Assembly.CodeBase))?.GetGetMethod();
|
||||
#pragma warning restore CS0618
|
||||
var codebasePatch = typeof(PluginManager).GetMethod(nameof(AssemblyCodeBasePatch), BindingFlags.NonPublic | BindingFlags.Static);
|
||||
this.assemblyCodeBaseMonoHook = new MonoMod.RuntimeDetour.Hook(codebaseTarget, codebasePatch);
|
||||
#pragma warning restore SYSLIB0012 // Type or member is obsolete
|
||||
}
|
||||
|
||||
internal record PluginPatchData
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginPatchData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dllFile">DLL file being loaded.</param>
|
||||
public PluginPatchData(FileInfo dllFile)
|
||||
{
|
||||
this.Location = dllFile.FullName;
|
||||
this.CodeBase = new Uri(dllFile.FullName).AbsoluteUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets simulated Assembly.Location output.
|
||||
/// </summary>
|
||||
public string Location { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets simulated Assembly.CodeBase output.
|
||||
/// </summary>
|
||||
public string CodeBase { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue