chore: only expose manifests as interfaces

This commit is contained in:
goat 2023-06-28 12:27:50 +02:00
parent a88151de7f
commit 98bdec1e34
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
16 changed files with 257 additions and 181 deletions

View file

@ -263,7 +263,7 @@ public sealed class EntryPoint
{
pluginInfo = $"Plugin that caused this:\n{plugin.Name}\n\nClick \"Yes\" and remove it.\n\n";
if (plugin.Manifest.IsThirdParty)
if (plugin.IsThirdParty)
supportText = string.Empty;
}
}

View file

@ -232,7 +232,7 @@ internal class PluginImageCache : IDisposable, IServiceType
/// <param name="isThirdParty">If the plugin was third party sourced.</param>
/// <param name="iconTexture">Cached image textures, or an empty array.</param>
/// <returns>True if an entry exists, may be null if currently downloading.</returns>
public bool TryGetIcon(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, out TextureWrap? iconTexture)
public bool TryGetIcon(LocalPlugin? plugin, IPluginManifest manifest, bool isThirdParty, out TextureWrap? iconTexture)
{
iconTexture = null;
@ -274,7 +274,7 @@ internal class PluginImageCache : IDisposable, IServiceType
/// <param name="isThirdParty">If the plugin was third party sourced.</param>
/// <param name="imageTextures">Cached image textures, or an empty array.</param>
/// <returns>True if the image array exists, may be empty if currently downloading.</returns>
public bool TryGetImages(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, out TextureWrap?[] imageTextures)
public bool TryGetImages(LocalPlugin? plugin, IPluginManifest manifest, bool isThirdParty, out TextureWrap?[] imageTextures)
{
if (!this.pluginImagesMap.TryAdd(manifest.InternalName, null))
{
@ -307,7 +307,7 @@ internal class PluginImageCache : IDisposable, IServiceType
byte[]? bytes,
string name,
string? loc,
PluginManifest manifest,
IPluginManifest manifest,
int maxWidth,
int maxHeight,
bool requireSquare)
@ -491,7 +491,7 @@ internal class PluginImageCache : IDisposable, IServiceType
Log.Debug("Plugin image loader has shutdown");
}
private async Task<TextureWrap?> DownloadPluginIconAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, ulong requestedFrame)
private async Task<TextureWrap?> DownloadPluginIconAsync(LocalPlugin? plugin, IPluginManifest manifest, bool isThirdParty, ulong requestedFrame)
{
if (plugin is { IsDev: true })
{
@ -558,7 +558,7 @@ internal class PluginImageCache : IDisposable, IServiceType
return icon;
}
private async Task DownloadPluginImagesAsync(TextureWrap?[] pluginImages, LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, ulong requestedFrame)
private async Task DownloadPluginImagesAsync(TextureWrap?[] pluginImages, LocalPlugin? plugin, IPluginManifest manifest, bool isThirdParty, ulong requestedFrame)
{
if (plugin is { IsDev: true })
{
@ -671,18 +671,15 @@ internal class PluginImageCache : IDisposable, IServiceType
}
}
private string? GetPluginIconUrl(PluginManifest manifest, bool isThirdParty, bool isTesting)
private string? GetPluginIconUrl(IPluginManifest manifest, bool isThirdParty, bool isTesting)
{
if (isThirdParty)
return manifest.IconUrl;
if (manifest.IsDip17Plugin)
return MainRepoDip17ImageUrl.Format(manifest.Dip17Channel!, manifest.InternalName, "icon.png");
return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png");
return MainRepoDip17ImageUrl.Format(manifest.Dip17Channel!, manifest.InternalName, "icon.png");
}
private List<string?>? GetPluginImageUrls(PluginManifest manifest, bool isThirdParty, bool isTesting)
private List<string?>? GetPluginImageUrls(IPluginManifest manifest, bool isThirdParty, bool isTesting)
{
if (isThirdParty)
{
@ -698,14 +695,7 @@ internal class PluginImageCache : IDisposable, IServiceType
var output = new List<string>();
for (var i = 1; i <= 5; i++)
{
if (manifest.IsDip17Plugin)
{
output.Add(MainRepoDip17ImageUrl.Format(manifest.Dip17Channel!, manifest.InternalName, $"image{i}.png"));
}
else
{
output.Add(MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, $"image{i}.png"));
}
output.Add(MainRepoDip17ImageUrl.Format(manifest.Dip17Channel!, manifest.InternalName, $"image{i}.png"));
}
return output;

View file

@ -48,15 +48,12 @@ internal class DalamudChangelogManager
foreach (var plugin in this.manager.InstalledPlugins)
{
if (!plugin.Manifest.IsThirdParty)
if (!plugin.IsThirdParty)
{
if (!plugin.Manifest.IsDip17Plugin)
continue;
var pluginChangelogs = await client.GetFromJsonAsync<PluginHistory>(string.Format(
PluginChangelogUrl,
plugin.Manifest.InternalName,
plugin.Manifest.Dip17Channel));
PluginChangelogUrl,
plugin.Manifest.InternalName,
plugin.Manifest.Dip17Channel));
changelogs = changelogs.Concat(pluginChangelogs.Versions
.Where(x => x.Dip17Track == plugin.Manifest.Dip17Channel)

View file

@ -33,7 +33,7 @@ internal class PluginChangelogEntry : IChangelogEntry
{
this.Plugin = plugin;
this.Version = plugin.Manifest.EffectiveVersion.ToString();
this.Version = plugin.EffectiveVersion.ToString();
this.Text = plugin.Manifest.Changelog ?? Loc.Localize("ChangelogNoText", "No changelog for this version.");
this.Author = plugin.Manifest.Author;
this.Date = DateTimeOffset.FromUnixTimeSeconds(this.Plugin.Manifest.LastUpdate).DateTime;

View file

@ -88,7 +88,7 @@ internal class PluginInstallerWindow : Window, IDisposable
private string feedbackModalBody = string.Empty;
private string feedbackModalContact = string.Empty;
private bool feedbackModalIncludeException = false;
private PluginManifest? feedbackPlugin = null;
private IPluginManifest? feedbackPlugin = null;
private bool feedbackIsTesting = false;
private int updatePluginCount = 0;
@ -1606,7 +1606,7 @@ internal class PluginInstallerWindow : Window, IDisposable
return ready;
}
private bool DrawPluginCollapsingHeader(string label, LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, bool trouble, bool updateAvailable, bool isNew, bool installableOutdated, bool isOrphan, Action drawContextMenuAction, int index)
private bool DrawPluginCollapsingHeader(string label, LocalPlugin? plugin, IPluginManifest manifest, bool isThirdParty, bool trouble, bool updateAvailable, bool isNew, bool installableOutdated, bool isOrphan, Action drawContextMenuAction, int index)
{
ImGui.Separator();
@ -1741,13 +1741,13 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.TextWrapped(Locs.PluginBody_Orphaned);
ImGui.PopStyleColor();
}
else if (plugin is { IsDecommissioned: true } && !plugin.Manifest.IsThirdParty)
else if (plugin is { IsDecommissioned: true, IsThirdParty: false })
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextWrapped(Locs.PluginBody_NoServiceOfficial);
ImGui.PopStyleColor();
}
else if (plugin is { IsDecommissioned: true } && plugin.Manifest.IsThirdParty)
else if (plugin is { IsDecommissioned: true, IsThirdParty: true })
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextWrapped(Locs.PluginBody_NoServiceThird);
@ -1808,7 +1808,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (log is PluginChangelogEntry pluginLog)
{
icon = this.imageCache.DefaultIcon;
var hasIcon = this.imageCache.TryGetIcon(pluginLog.Plugin, pluginLog.Plugin.Manifest, pluginLog.Plugin.Manifest.IsThirdParty, out var cachedIconTex);
var hasIcon = this.imageCache.TryGetIcon(pluginLog.Plugin, pluginLog.Plugin.Manifest, pluginLog.Plugin.IsThirdParty, out var cachedIconTex);
if (hasIcon && cachedIconTex != null)
{
icon = cachedIconTex;
@ -2031,15 +2031,18 @@ internal class PluginInstallerWindow : Window, IDisposable
}
// Testing
if (plugin.Manifest.Testing)
if (plugin.IsTesting)
{
label += Locs.PluginTitleMod_TestingVersion;
}
// TODO: check with the repos instead
/*
if (plugin.Manifest.IsAvailableForTesting && configuration.DoPluginTest && testingOptIn == null)
{
label += Locs.PluginTitleMod_TestingAvailable;
}
*/
// Freshly installed
if (showInstalled)
@ -2132,7 +2135,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}");
var hasChangelog = !plugin.Manifest.Changelog.IsNullOrEmpty();
if (this.DrawPluginCollapsingHeader(label, plugin, plugin.Manifest, plugin.Manifest.IsThirdParty, trouble, availablePluginUpdate != default, false, false, plugin.IsOrphaned, () => this.DrawInstalledPluginContextMenu(plugin, testingOptIn), index))
if (this.DrawPluginCollapsingHeader(label, plugin, plugin.Manifest, plugin.IsThirdParty, trouble, availablePluginUpdate != default, false, false, plugin.IsOrphaned, () => this.DrawInstalledPluginContextMenu(plugin, testingOptIn), index))
{
if (!this.WasPluginSeen(plugin.Manifest.InternalName))
configuration.SeenPluginInternalName.Add(plugin.Manifest.InternalName);
@ -2154,12 +2157,12 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText);
var isThirdParty = manifest.IsThirdParty;
var isThirdParty = plugin.IsThirdParty;
var canFeedback = !isThirdParty &&
!plugin.IsDev &&
!plugin.IsOrphaned &&
plugin.Manifest.DalamudApiLevel == PluginManager.DalamudApiLevel &&
plugin.Manifest.AcceptsFeedback &&
// plugin.Manifest.AcceptsFeedback && // TODO: check with the repos
availablePluginUpdate == default;
// Installed from
@ -2215,7 +2218,7 @@ internal class PluginInstallerWindow : Window, IDisposable
this.DrawUpdateSinglePluginButton(availablePluginUpdate);
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudGrey3, $" v{plugin.Manifest.EffectiveVersion}");
ImGui.TextColored(ImGuiColors.DalamudGrey3, $" v{plugin.EffectiveVersion}");
ImGuiHelpers.ScaledDummy(5);
@ -2226,7 +2229,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (hasChangelog)
{
if (ImGui.TreeNode(Locs.PluginBody_CurrentChangeLog(plugin.Manifest.EffectiveVersion)))
if (ImGui.TreeNode(Locs.PluginBody_CurrentChangeLog(plugin.EffectiveVersion)))
{
this.DrawInstalledPluginChangelog(plugin.Manifest);
ImGui.TreePop();
@ -2252,7 +2255,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.PopID();
}
private void DrawInstalledPluginChangelog(PluginManifest manifest)
private void DrawInstalledPluginChangelog(IPluginManifest manifest)
{
ImGuiHelpers.ScaledDummy(5);
@ -2265,7 +2268,7 @@ internal class PluginInstallerWindow : Window, IDisposable
{
ImGui.Text("Changelog:");
ImGuiHelpers.ScaledDummy(2);
ImGuiHelpers.SafeTextWrapped(manifest.Changelog);
ImGuiHelpers.SafeTextWrapped(manifest.Changelog!);
}
ImGui.EndChild();
@ -2363,7 +2366,7 @@ internal class PluginInstallerWindow : Window, IDisposable
var isLoadedAndUnloadable = plugin.State == PluginState.Loaded ||
plugin.State == PluginState.DependencyResolutionFailed;
//StyleModelV1.DalamudStandard.Push();
// StyleModelV1.DalamudStandard.Push();
var profileChooserPopupName = $"###pluginProfileChooser{plugin.Manifest.InternalName}";
if (ImGui.BeginPopup(profileChooserPopupName))
@ -2526,7 +2529,7 @@ internal class PluginInstallerWindow : Window, IDisposable
}
}
//StyleModelV1.DalamudStandard.Pop();
// StyleModelV1.DalamudStandard.Pop();
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(15, 0);
@ -2621,7 +2624,7 @@ internal class PluginInstallerWindow : Window, IDisposable
}
}
private void DrawSendFeedbackButton(PluginManifest manifest, bool isTesting)
private void DrawSendFeedbackButton(IPluginManifest manifest, bool isTesting)
{
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Comment))
@ -2796,7 +2799,7 @@ internal class PluginInstallerWindow : Window, IDisposable
}
}
private bool DrawPluginImages(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, int index)
private bool DrawPluginImages(LocalPlugin? plugin, IPluginManifest manifest, bool isThirdParty, int index)
{
var hasImages = this.imageCache.TryGetImages(plugin, manifest, isThirdParty, out var imageTextures);
if (!hasImages || imageTextures.All(x => x == null))
@ -2871,7 +2874,7 @@ internal class PluginInstallerWindow : Window, IDisposable
return true;
}
private bool IsManifestFiltered(PluginManifest manifest)
private bool IsManifestFiltered(IPluginManifest manifest)
{
var searchString = this.searchText.ToLowerInvariant();
var hasSearchString = !string.IsNullOrWhiteSpace(searchString);
@ -2889,7 +2892,7 @@ internal class PluginInstallerWindow : Window, IDisposable
(manifest.Tags != null && manifest.Tags.Any(tag => tag.ToLowerInvariant().Contains(searchString))));
}
private (bool IsInstalled, LocalPlugin Plugin) IsManifestInstalled(PluginManifest? manifest)
private (bool IsInstalled, LocalPlugin Plugin) IsManifestInstalled(IPluginManifest? manifest)
{
if (manifest == null) return (false, default);

View file

@ -77,9 +77,9 @@ internal class ProfileManagerWidget
private void DrawTutorial(string modalTitle)
{
var _ = true;
var open = true;
ImGui.SetNextWindowSize(new Vector2(450, 350), ImGuiCond.Appearing);
using (var popup = ImRaii.PopupModal(modalTitle, ref _))
using (var popup = ImRaii.PopupModal(modalTitle, ref open))
{
if (popup)
{
@ -399,7 +399,7 @@ internal class ProfileManagerWidget
if (pmPlugin != null)
{
pic.TryGetIcon(pmPlugin, pmPlugin.Manifest, pmPlugin.Manifest.IsThirdParty, out var icon);
pic.TryGetIcon(pmPlugin, pmPlugin.Manifest, pmPlugin.IsThirdParty, out var icon);
icon ??= pic.DefaultIcon;
ImGui.Image(icon.ImGuiHandle, new Vector2(pluginLineHeight));
@ -596,6 +596,5 @@ internal class ProfileManagerWidget
public static string TutorialCommandsEnd =>
Loc.Localize("ProfileManagerTutorialCommandsEnd", "If you run multiple of these commands, they will be executed in order.");
}
}

View file

@ -220,7 +220,7 @@ public sealed class DalamudPluginInterface : IDisposable
/// <summary>
/// Gets a list of installed plugins along with their current state.
/// </summary>
public IEnumerable<InstalledPluginState> InstalledPlugins => Service<PluginManager>.Get().InstalledPlugins.Select(p => new InstalledPluginState(p.Name, p.Manifest.InternalName, p.IsLoaded, p.Manifest.EffectiveVersion));
public IEnumerable<InstalledPluginState> InstalledPlugins => Service<PluginManager>.Get().InstalledPlugins.Select(p => new InstalledPluginState(p.Name, p.Manifest.InternalName, p.IsLoaded, p.EffectiveVersion));
/// <summary>
/// Opens the <see cref="PluginInstallerWindow"/> with the plugin name set as search target.

View file

@ -246,7 +246,7 @@ internal partial class PluginManager : IDisposable, IServiceType
/// </summary>
/// <param name="manifest">The manifest to test.</param>
/// <returns>Whether or not a testing version is available.</returns>
public static bool HasTestingVersion(PluginManifest manifest)
public static bool HasTestingVersion(IPluginManifest manifest)
{
var av = manifest.AssemblyVersion;
var tv = manifest.TestingAssemblyVersion;
@ -316,7 +316,7 @@ internal partial class PluginManager : IDisposable, IServiceType
/// </summary>
/// <param name="manifest">Manifest to check.</param>
/// <returns>A value indicating whether testing should be used.</returns>
public bool HasTestingOptIn(PluginManifest manifest)
public bool HasTestingOptIn(IPluginManifest manifest)
{
return this.configuration.PluginTestingOptIns!.Any(x => x.InternalName == manifest.InternalName);
}
@ -327,7 +327,7 @@ internal partial class PluginManager : IDisposable, IServiceType
/// </summary>
/// <param name="manifest">Manifest to check.</param>
/// <returns>A value indicating whether testing should be used.</returns>
public bool UseTesting(PluginManifest manifest)
public bool UseTesting(IPluginManifest manifest)
{
if (!this.configuration.DoPluginTest)
return false;

View file

@ -0,0 +1,19 @@
namespace Dalamud.Plugin.Internal.Types;
/// <summary>
/// Public interface for the local plugin manifest.
/// </summary>
public interface ILocalPluginManifest : IPluginManifest
{
/// <summary>
/// Gets the 3rd party repo URL that this plugin was installed from. Used to display where the plugin was
/// sourced from on the installed plugin view. This should not be included in the plugin master. This value is null
/// when installed from the main repo.
/// </summary>
public string InstalledFromUrl { get; }
/// <summary>
/// Gets a value indicating whether the plugin should be deleted during the next cleanup.
/// </summary>
public bool ScheduledForDeletion { get; }
}

View file

@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
namespace Dalamud.Plugin.Internal.Types;
/// <summary>
/// Public interface for the base plugin manifest.
/// </summary>
public interface IPluginManifest
{
/// <summary>
/// Gets the internal name of the plugin, which should match the assembly name of the plugin.
/// </summary>
public string InternalName { get; }
/// <summary>
/// Gets the public name of the plugin.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets a punchline of the plugins functions.
/// </summary>
public string? Punchline { get; }
/// <summary>
/// Gets the author/s of the plugin.
/// </summary>
public string Author { get; }
/// <summary>
/// Gets a value indicating whether the plugin can be unloaded asynchronously.
/// </summary>
public bool CanUnloadAsync { get; }
/// <summary>
/// Gets the assembly version of the plugin.
/// </summary>
public Version AssemblyVersion { get; }
/// <summary>
/// Gets the assembly version of the plugin's testing variant.
/// </summary>
public Version? TestingAssemblyVersion { get; }
/// <summary>
/// Gets the DIP17 channel name.
/// </summary>
public string? Dip17Channel { get; }
/// <summary>
/// Gets the last time this plugin was updated.
/// </summary>
public long LastUpdate { get; }
/// <summary>
/// Gets a changelog, null if none exists.
/// </summary>
public string? Changelog { get; }
/// <summary>
/// Gets a list of tags that apply to this plugin.
/// </summary>
public List<string>? Tags { get; }
/// <summary>
/// Gets the API level of this plugin. For the current API level, please see <see cref="PluginManager.DalamudApiLevel"/>
/// for the currently used API level.
/// </summary>
public int DalamudApiLevel { get; }
/// <summary>
/// Gets the number of downloads this plugin has.
/// </summary>
public long DownloadCount { get; }
/// <summary>
/// Gets a value indicating whether the plugin supports profiles.
/// </summary>
public bool SupportsProfiles { get; }
/// <summary>
/// Gets an URL to the website or source code of the plugin.
/// </summary>
public string? RepoUrl { get; }
/// <summary>
/// Gets a description of the plugins functions.
/// </summary>
public string? Description { get; }
/// <summary>
/// Gets a message that is shown to users when sending feedback.
/// </summary>
public string? FeedbackMessage { get; }
/// <summary>
/// Gets a value indicating whether the plugin is only available for testing.
/// </summary>
public bool IsTestingExclusive { get; }
/// <summary>
/// Gets a list of screenshot image URLs to show in the plugin installer.
/// </summary>
public List<string>? ImageUrls { get; }
/// <summary>
/// Gets an URL for the plugin's icon.
/// </summary>
public string? IconUrl { get; }
}

View file

@ -11,7 +11,6 @@ using Dalamud.Game.Gui.Dtr;
using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Internal;
using Dalamud.IoC.Internal;
using Dalamud.Logging;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Internal.Exceptions;
using Dalamud.Plugin.Internal.Loader;
@ -39,6 +38,8 @@ internal class LocalPlugin : IDisposable
private Type? pluginType;
private IDalamudPlugin? instance;
private LocalPluginManifest manifest;
/// <summary>
/// Initializes a new instance of the <see cref="LocalPlugin"/> class.
/// </summary>
@ -111,7 +112,7 @@ internal class LocalPlugin : IDisposable
// If the parameter manifest was null
if (manifest == null)
{
this.Manifest = new LocalPluginManifest()
this.manifest = new LocalPluginManifest()
{
Author = "developer",
Name = Path.GetFileNameWithoutExtension(this.DllFile.Name),
@ -125,11 +126,11 @@ internal class LocalPlugin : IDisposable
// Save the manifest to disk so there won't be any problems later.
// We'll update the name property after it can be retrieved from the instance.
this.Manifest.Save(this.manifestFile, "manifest was null");
this.manifest.Save(this.manifestFile, "manifest was null");
}
else
{
this.Manifest = manifest;
this.manifest = manifest;
}
var needsSaveDueToLegacyFiles = false;
@ -139,7 +140,7 @@ internal class LocalPlugin : IDisposable
if (this.disabledFile.Exists)
{
#pragma warning disable CS0618
this.Manifest.Disabled = true;
this.manifest.Disabled = true;
#pragma warning restore CS0618
this.disabledFile.Delete();
@ -150,15 +151,15 @@ internal class LocalPlugin : IDisposable
this.testingFile = LocalPluginManifest.GetTestingFile(this.DllFile);
if (this.testingFile.Exists)
{
this.Manifest.Testing = true;
this.manifest.Testing = true;
this.testingFile.Delete();
needsSaveDueToLegacyFiles = true;
}
var pluginManager = Service<PluginManager>.Get();
this.IsBanned = pluginManager.IsManifestBanned(this.Manifest) && !this.IsDev;
this.BanReason = pluginManager.GetBanReason(this.Manifest);
this.IsBanned = pluginManager.IsManifestBanned(this.manifest) && !this.IsDev;
this.BanReason = pluginManager.GetBanReason(this.manifest);
if (needsSaveDueToLegacyFiles)
this.SaveManifest("legacy");
@ -175,9 +176,9 @@ internal class LocalPlugin : IDisposable
public FileInfo DllFile { get; }
/// <summary>
/// Gets the plugin manifest, if one exists.
/// Gets the plugin manifest.
/// </summary>
public LocalPluginManifest Manifest { get; private set; }
public ILocalPluginManifest Manifest => this.manifest;
/// <summary>
/// Gets or sets the current state of the plugin.
@ -193,12 +194,12 @@ internal class LocalPlugin : IDisposable
/// <summary>
/// Gets the plugin name from the manifest.
/// </summary>
public string Name => this.Manifest.Name;
public string Name => this.manifest.Name;
/// <summary>
/// Gets the plugin internal name from the manifest.
/// </summary>
public string InternalName => this.Manifest.InternalName;
public string InternalName => this.manifest.InternalName;
/// <summary>
/// Gets an optional reason, if the plugin is banned.
@ -220,23 +221,23 @@ internal class LocalPlugin : IDisposable
/// INCLUDES the default profile.
/// </summary>
public bool IsWantedByAnyProfile =>
Service<ProfileManager>.Get().GetWantStateAsync(this.Manifest.InternalName, false, false).GetAwaiter().GetResult();
Service<ProfileManager>.Get().GetWantStateAsync(this.manifest.InternalName, false, false).GetAwaiter().GetResult();
/// <summary>
/// Gets a value indicating whether this plugin's API level is out of date.
/// </summary>
public bool IsOutdated => this.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel;
public bool IsOutdated => this.manifest.DalamudApiLevel < PluginManager.DalamudApiLevel;
/// <summary>
/// Gets a value indicating whether the plugin is for testing use only.
/// </summary>
public bool IsTesting => this.Manifest.IsTestingExclusive || this.Manifest.Testing;
public bool IsTesting => this.manifest.IsTestingExclusive || this.manifest.Testing;
/// <summary>
/// Gets a value indicating whether or not this plugin is orphaned(belongs to a repo) or not.
/// </summary>
public bool IsOrphaned => !this.IsDev &&
!this.Manifest.InstalledFromUrl.IsNullOrEmpty() && // TODO(api8): Remove this, all plugins will have a proper flag
!this.manifest.InstalledFromUrl.IsNullOrEmpty() && // TODO(api8): Remove this, all plugins will have a proper flag
this.GetSourceRepository() == null;
/// <summary>
@ -244,7 +245,7 @@ internal class LocalPlugin : IDisposable
/// </summary>
public bool IsDecommissioned => !this.IsDev &&
this.GetSourceRepository()?.State == PluginRepositoryState.Success &&
this.GetSourceRepository()?.PluginMaster?.FirstOrDefault(x => x.InternalName == this.Manifest.InternalName) == null;
this.GetSourceRepository()?.PluginMaster?.FirstOrDefault(x => x.InternalName == this.manifest.InternalName) == null;
/// <summary>
/// Gets a value indicating whether this plugin has been banned.
@ -256,12 +257,23 @@ internal class LocalPlugin : IDisposable
/// </summary>
public bool IsDev => this is LocalDevPlugin;
/// <summary>
/// Gets a value indicating whether this manifest is associated with a plugin that was installed from a third party
/// repo.
/// </summary>
public bool IsThirdParty => this.manifest.IsThirdParty;
/// <summary>
/// Gets a value indicating whether this plugin should be allowed to load.
/// </summary>
public bool ApplicableForLoad => !this.IsBanned && !this.IsDecommissioned && !this.IsOrphaned && !this.IsOutdated
&& !(!this.IsDev && this.State == PluginState.UnloadError) && this.CheckPolicy();
/// <summary>
/// Gets the effective version of this plugin.
/// </summary>
public Version EffectiveVersion => this.manifest.EffectiveVersion;
/// <summary>
/// Gets the service scope for this plugin.
/// </summary>
@ -277,7 +289,7 @@ internal class LocalPlugin : IDisposable
if (this.instance != null)
{
didPluginDispose = true;
if (this.Manifest.CanUnloadAsync || framework == null)
if (this.manifest.CanUnloadAsync || framework == null)
this.instance.Dispose();
else
framework.RunOnFrameworkThread(() => this.instance.Dispose()).Wait();
@ -316,7 +328,7 @@ internal class LocalPlugin : IDisposable
await Service<InterfaceManager>.GetAsync();
await Service<GameFontManager>.GetAsync();
if (this.Manifest.LoadRequiredState == 0)
if (this.manifest.LoadRequiredState == 0)
_ = await Service<InterfaceManager.InterfaceManagerWithScene>.GetAsync();
await this.pluginLoadStateLock.WaitAsync();
@ -329,9 +341,9 @@ internal class LocalPlugin : IDisposable
}
// If we reload a plugin we don't want to delete it. Makes sense, right?
if (this.Manifest.ScheduledForDeletion)
if (this.manifest.ScheduledForDeletion)
{
this.Manifest.ScheduledForDeletion = false;
this.manifest.ScheduledForDeletion = false;
this.SaveManifest("Scheduled for deletion, but loading");
}
@ -363,13 +375,13 @@ internal class LocalPlugin : IDisposable
throw new ArgumentOutOfRangeException(this.State.ToString());
}
if (pluginManager.IsManifestBanned(this.Manifest) && !this.IsDev)
if (pluginManager.IsManifestBanned(this.manifest) && !this.IsDev)
throw new BannedPluginException($"Unable to load {this.Name}, banned");
if (this.Manifest.ApplicableVersion < startInfo.GameVersion)
if (this.manifest.ApplicableVersion < startInfo.GameVersion)
throw new InvalidPluginOperationException($"Unable to load {this.Name}, no applicable version");
if (this.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel && !pluginManager.LoadAllApiLevels)
if (this.manifest.DalamudApiLevel < PluginManager.DalamudApiLevel && !pluginManager.LoadAllApiLevels)
throw new InvalidPluginOperationException($"Unable to load {this.Name}, incompatible API level");
// We might want to throw here?
@ -390,8 +402,8 @@ internal class LocalPlugin : IDisposable
{
Log.Error(
"==== IMPORTANT MESSAGE TO {0}, THE DEVELOPER OF {1} ====",
this.Manifest.Author!,
this.Manifest.InternalName);
this.manifest.Author!,
this.manifest.InternalName);
Log.Error(
"YOU ARE INCLUDING DALAMUD DEPENDENCIES IN YOUR BUILDS!!!");
Log.Error(
@ -459,7 +471,7 @@ internal class LocalPlugin : IDisposable
this.ServiceScope = ioc.GetScope();
this.ServiceScope.RegisterPrivateScopes(this); // Add this LocalPlugin as a private scope, so services can get it
if (this.Manifest.LoadSync && this.Manifest.LoadRequiredState is 0 or 1)
if (this.manifest.LoadSync && this.manifest.LoadRequiredState is 0 or 1)
{
this.instance = await framework.RunOnFrameworkThread(
() => this.ServiceScope.CreateAsync(this.pluginType!, this.DalamudInterface!)) as IDalamudPlugin;
@ -480,10 +492,10 @@ internal class LocalPlugin : IDisposable
}
// In-case the manifest name was a placeholder. Can occur when no manifest was included.
if (this.Manifest.Name.IsNullOrEmpty() && !this.IsDev)
if (this.manifest.Name.IsNullOrEmpty() && !this.IsDev)
{
this.Manifest.Name = this.instance.Name;
this.Manifest.Save(this.manifestFile, "manifest name null or empty");
this.manifest.Name = this.instance.Name;
this.manifest.Save(this.manifestFile, "manifest name null or empty");
}
this.State = PluginState.Loaded;
@ -515,7 +527,6 @@ internal class LocalPlugin : IDisposable
{
var configuration = Service<DalamudConfiguration>.Get();
var framework = Service<Framework>.GetNullable();
var ioc = await Service<ServiceContainer>.GetAsync();
await this.pluginLoadStateLock.WaitAsync();
try
@ -544,7 +555,7 @@ internal class LocalPlugin : IDisposable
this.State = PluginState.Unloading;
Log.Information($"Unloading {this.DllFile.Name}");
if (this.Manifest.CanUnloadAsync || framework == null)
if (this.manifest.CanUnloadAsync || framework == null)
this.instance?.Dispose();
else
await framework.RunOnFrameworkThread(() => this.instance?.Dispose());
@ -612,7 +623,7 @@ internal class LocalPlugin : IDisposable
if (startInfo.NoLoadPlugins)
return false;
if (startInfo.NoLoadThirdPartyPlugins && this.Manifest.IsThirdParty)
if (startInfo.NoLoadThirdPartyPlugins && this.manifest.IsThirdParty)
return false;
if (manager.SafeMode)
@ -627,7 +638,7 @@ internal class LocalPlugin : IDisposable
/// <param name="status">Schedule or cancel the deletion.</param>
public void ScheduleDeletion(bool status = true)
{
this.Manifest.ScheduledForDeletion = status;
this.manifest.ScheduledForDeletion = status;
this.SaveManifest("scheduling for deletion");
}
@ -636,12 +647,12 @@ internal class LocalPlugin : IDisposable
/// </summary>
public void ReloadManifest()
{
var manifest = LocalPluginManifest.GetManifestFile(this.DllFile);
if (manifest.Exists)
var manifestPath = LocalPluginManifest.GetManifestFile(this.DllFile);
if (manifestPath.Exists)
{
// var isDisabled = this.IsDisabled; // saving the internal state because it could have been deleted
this.Manifest = LocalPluginManifest.Load(manifest) ?? throw new Exception("Could not reload manifest.");
// this.Manifest.Disabled = isDisabled;
this.manifest = LocalPluginManifest.Load(manifestPath) ?? throw new Exception("Could not reload manifest.");
// this.manifest.Disabled = isDisabled;
this.SaveManifest("dev reload");
}
@ -659,10 +670,10 @@ internal class LocalPlugin : IDisposable
var repos = Service<PluginManager>.Get().Repos;
return repos.FirstOrDefault(x =>
{
if (!x.IsThirdParty && !this.Manifest.IsThirdParty)
if (!x.IsThirdParty && !this.manifest.IsThirdParty)
return true;
return x.PluginMasterUrl == this.Manifest.InstalledFromUrl;
return x.PluginMasterUrl == this.manifest.InstalledFromUrl;
});
}
@ -675,5 +686,5 @@ internal class LocalPlugin : IDisposable
config.SharedAssemblies.Add(typeof(Lumina.Excel.ExcelSheetImpl).Assembly.GetName());
}
private void SaveManifest(string reason) => this.Manifest.Save(this.manifestFile, reason);
private void SaveManifest(string reason) => this.manifest.Save(this.manifestFile, reason);
}

View file

@ -11,7 +11,7 @@ namespace Dalamud.Plugin.Internal.Types;
/// Information about a plugin, packaged in a json file with the DLL. This variant includes additional information such as
/// if the plugin is disabled and if it was installed from a testing URL. This is designed for use with manifests on disk.
/// </summary>
internal record LocalPluginManifest : PluginManifest
internal record LocalPluginManifest : PluginManifest, ILocalPluginManifest
{
/// <summary>
/// Flag indicating that a plugin was installed from the official repo.
@ -38,16 +38,10 @@ internal record LocalPluginManifest : PluginManifest
/// </summary>
public bool Testing { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the plugin should be deleted during the next cleanup.
/// </summary>
/// <inheritdoc/>
public bool ScheduledForDeletion { get; set; }
/// <summary>
/// Gets or sets the 3rd party repo URL that this plugin was installed from. Used to display where the plugin was
/// sourced from on the installed plugin view. This should not be included in the plugin master. This value is null
/// when installed from the main repo.
/// </summary>
/// <inheritdoc/>
public string InstalledFromUrl { get; set; } = string.Empty;
/// <summary>

View file

@ -9,41 +9,29 @@ namespace Dalamud.Plugin.Internal.Types;
/// <summary>
/// Information about a plugin, packaged in a json file with the DLL.
/// </summary>
internal record PluginManifest
internal record PluginManifest : IPluginManifest
{
/// <summary>
/// Gets the author/s of the plugin.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public string? Author { get; init; }
/// <summary>
/// Gets or sets the public name of the plugin.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public string Name { get; set; } = null!;
/// <summary>
/// Gets a punchline of the plugins functions.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public string? Punchline { get; init; }
/// <summary>
/// Gets a description of the plugins functions.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public string? Description { get; init; }
/// <summary>
/// Gets a changelog.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public string? Changelog { get; init; }
/// <summary>
/// Gets a list of tags defined on the plugin.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public List<string>? Tags { get; init; }
@ -60,33 +48,23 @@ internal record PluginManifest
[JsonProperty]
public bool IsHide { get; init; }
/// <summary>
/// Gets the internal name of the plugin, which should match the assembly name of the plugin.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public string InternalName { get; init; } = null!;
public string InternalName { get; set; } = null!;
/// <summary>
/// Gets the current assembly version of the plugin.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public Version AssemblyVersion { get; init; } = null!;
public Version AssemblyVersion { get; set; } = null!;
/// <summary>
/// Gets the current testing assembly version of the plugin.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public Version? TestingAssemblyVersion { get; init; }
/// <summary>
/// Gets a value indicating whether the plugin is only available for testing.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public bool IsTestingExclusive { get; init; }
/// <summary>
/// Gets an URL to the website or source code of the plugin.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public string? RepoUrl { get; init; }
@ -97,24 +75,17 @@ internal record PluginManifest
[JsonConverter(typeof(GameVersionConverter))]
public GameVersion? ApplicableVersion { get; init; } = GameVersion.Any;
/// <summary>
/// Gets the API level of this plugin. For the current API level, please see <see cref="PluginManager.DalamudApiLevel"/>
/// for the currently used API level.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public int DalamudApiLevel { get; init; } = PluginManager.DalamudApiLevel;
/// <summary>
/// Gets the number of downloads this plugin has.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public long DownloadCount { get; init; }
/// <summary>
/// Gets the last time this plugin was updated.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public long LastUpdate { get; init; }
public long LastUpdate { get; set; }
/// <summary>
/// Gets the download link used to install the plugin.
@ -156,26 +127,18 @@ internal record PluginManifest
[JsonProperty]
public int LoadPriority { get; init; }
/// <summary>
/// Gets a value indicating whether the plugin can be unloaded asynchronously.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public bool CanUnloadAsync { get; init; }
public bool CanUnloadAsync { get; set; }
/// <summary>
/// Gets a value indicating whether the plugin supports profiles.
/// </summary>
/// <inheritdoc/>
[JsonProperty]
public bool SupportsProfiles { get; init; } = true;
/// <summary>
/// Gets a list of screenshot image URLs to show in the plugin installer.
/// </summary>
/// <inheritdoc/>
public List<string>? ImageUrls { get; init; }
/// <summary>
/// Gets an URL for the plugin's icon.
/// </summary>
/// <inheritdoc/>
public string? IconUrl { get; init; }
/// <summary>
@ -183,21 +146,10 @@ internal record PluginManifest
/// </summary>
public bool AcceptsFeedback { get; init; } = true;
/// <summary>
/// Gets a message that is shown to users when sending feedback.
/// </summary>
/// <inheritdoc/>
public string? FeedbackMessage { get; init; }
/// <summary>
/// Gets a value indicating whether this plugin is DIP17.
/// To be removed.
/// </summary>
[JsonProperty("_isDip17Plugin")]
public bool IsDip17Plugin { get; init; } = false;
/// <summary>
/// Gets the DIP17 channel name.
/// </summary>
/// <inheritdoc/>
[JsonProperty("_Dip17Channel")]
public string? Dip17Channel { get; init; }
}

View file

@ -25,7 +25,7 @@ internal static class BugBait
/// <param name="reporter">The reporter name.</param>
/// <param name="includeException">Whether or not the most recent exception to occur should be included in the report.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task SendFeedback(PluginManifest plugin, bool isTesting, string content, string reporter, bool includeException)
public static async Task SendFeedback(IPluginManifest plugin, bool isTesting, string content, string reporter, bool includeException)
{
if (content.IsNullOrWhitespace())
return;

View file

@ -67,7 +67,7 @@ public static class Troubleshooting
{
var payload = new TroubleshootingPayload
{
LoadedPlugins = pluginManager?.InstalledPlugins?.Select(x => x.Manifest)?.OrderByDescending(x => x.InternalName).ToArray(),
LoadedPlugins = pluginManager?.InstalledPlugins?.Select(x => x.Manifest as LocalPluginManifest)?.OrderByDescending(x => x.InternalName).ToArray(),
PluginStates = pluginManager?.InstalledPlugins?.Where(x => !x.IsDev).ToDictionary(x => x.Manifest.InternalName, x => x.IsBanned ? "Banned" : x.State.ToString()),
EverStartedLoadingPlugins = pluginManager?.InstalledPlugins.Where(x => x.HasEverStartedLoad).Select(x => x.InternalName).ToList(),
DalamudVersion = Util.AssemblyVersion,

View file

@ -674,7 +674,7 @@ public static class Util
}
/// <summary>
/// Print formatted GameObject Information to ImGui
/// Print formatted GameObject Information to ImGui.
/// </summary>
/// <param name="actor">Game Object to Display.</param>
/// <param name="tag">Display Tag.</param>