diff --git a/Dalamud/Fools/FoolsManager.cs b/Dalamud/Fools/FoolsManager.cs
new file mode 100644
index 000000000..8d08e5c39
--- /dev/null
+++ b/Dalamud/Fools/FoolsManager.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Dalamud.Fools.Plugins;
+using Dalamud.Logging.Internal;
+
+namespace Dalamud.Fools;
+
+///
+/// Manager for all the IFoolsPlugin instances.
+///
+[ServiceManager.BlockingEarlyLoadedService]
+internal class FoolsManager : IDisposable, IServiceType
+{
+ public readonly List FoolsPlugins = new();
+ public readonly Dictionary ActivatedPlugins = new();
+
+ private static readonly ModuleLog Log = new("FOOLS");
+
+ [ServiceManager.ServiceConstructor]
+ private FoolsManager()
+ {
+ // reflect over all IFoolsPlugin implementations
+ this.FoolsPlugins = new List
+ {
+ new("Test Fool Plugin", "TestFoolPlugin", "this is a test", "NotNite", typeof(TestFoolPlugin)),
+ };
+ }
+
+ public void ActivatePlugin(string plugin)
+ {
+ if (this.ActivatedPlugins.ContainsKey(plugin))
+ {
+ Log.Warning("Trying to activate plugin {0} that is already activated", plugin);
+ return;
+ }
+
+ var pluginMetadata = this.FoolsPlugins.FirstOrDefault(x => x.InternalName == plugin);
+ if (pluginMetadata == null)
+ {
+ Log.Warning("Trying to activate plugin {0} that does not exist", plugin);
+ return;
+ }
+
+ var pluginInstance = (IFoolsPlugin)Activator.CreateInstance(pluginMetadata.Type);
+ this.ActivatedPlugins.Add(plugin, pluginInstance);
+ }
+
+ public bool IsPluginActivated(string plugin)
+ {
+ return this.ActivatedPlugins.ContainsKey(plugin);
+ }
+
+ public void DeactivatePlugin(string plugin)
+ {
+ if (!this.ActivatedPlugins.ContainsKey(plugin))
+ {
+ Log.Warning("Trying to deactivate plugin {0} that is not activated", plugin);
+ return;
+ }
+
+ var pluginInstance = this.ActivatedPlugins[plugin];
+ pluginInstance.Dispose();
+ this.ActivatedPlugins.Remove(plugin);
+ }
+
+ public void Dispose()
+ {
+ foreach (var plugin in this.ActivatedPlugins.Values)
+ {
+ plugin.Dispose();
+ }
+
+ this.ActivatedPlugins.Clear();
+ }
+}
diff --git a/Dalamud/Fools/FoolsPluginMetadata.cs b/Dalamud/Fools/FoolsPluginMetadata.cs
new file mode 100644
index 000000000..25c095a60
--- /dev/null
+++ b/Dalamud/Fools/FoolsPluginMetadata.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Dalamud.Fools;
+
+public class FoolsPluginMetadata
+{
+ public string Name { get; }
+
+ public string InternalName { get; }
+
+ public string Description { get; }
+
+ public string Author { get; }
+
+ public Type Type { get; }
+
+ public FoolsPluginMetadata(string name, string internalName, string description, string author, Type type)
+ {
+ this.Name = name;
+ this.InternalName = internalName;
+ this.Description = description;
+ this.Author = author;
+ this.Type = type;
+ }
+}
diff --git a/Dalamud/Fools/IFoolsPlugin.cs b/Dalamud/Fools/IFoolsPlugin.cs
new file mode 100644
index 000000000..f2957508e
--- /dev/null
+++ b/Dalamud/Fools/IFoolsPlugin.cs
@@ -0,0 +1,8 @@
+using Dalamud.Plugin;
+
+namespace Dalamud.Fools;
+
+public interface IFoolsPlugin : IDalamudPlugin
+{
+ public void DrawUI() { }
+}
diff --git a/Dalamud/Fools/Plugins/TestFoolPlugin.cs b/Dalamud/Fools/Plugins/TestFoolPlugin.cs
new file mode 100644
index 000000000..1cf2d1d94
--- /dev/null
+++ b/Dalamud/Fools/Plugins/TestFoolPlugin.cs
@@ -0,0 +1,16 @@
+namespace Dalamud.Fools.Plugins;
+
+public class TestFoolPlugin : IFoolsPlugin
+{
+ public string Name => "TestFoolPlugin";
+
+ public string Description => "TestFoolPlugin";
+
+ public string InternalName => "TestFoolPlugin";
+
+ public string Author => "NotNite";
+
+ public TestFoolPlugin() { }
+
+ public void Dispose() { }
+}
diff --git a/Dalamud/Interface/Internal/PluginCategoryManager.cs b/Dalamud/Interface/Internal/PluginCategoryManager.cs
index 06e306c50..1a8acfa3f 100644
--- a/Dalamud/Interface/Internal/PluginCategoryManager.cs
+++ b/Dalamud/Interface/Internal/PluginCategoryManager.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
-
using CheapLoc;
using Dalamud.Plugin.Internal;
using Dalamud.Plugin.Internal.Types;
@@ -23,11 +22,13 @@ internal class PluginCategoryManager
{
new(0, "special.all", () => Locs.Category_All),
new(1, "special.isTesting", () => Locs.Category_IsTesting, CategoryInfo.AppearCondition.DoPluginTest),
- new(2, "special.availableForTesting", () => Locs.Category_AvailableForTesting, CategoryInfo.AppearCondition.DoPluginTest),
+ new(2, "special.availableForTesting", () => Locs.Category_AvailableForTesting,
+ CategoryInfo.AppearCondition.DoPluginTest),
new(10, "special.devInstalled", () => Locs.Category_DevInstalled),
new(11, "special.devIconTester", () => Locs.Category_IconTester),
new(12, "special.dalamud", () => Locs.Category_Dalamud),
new(13, "special.plugins", () => Locs.Category_Plugins),
+ new(14, "special.alternateReality", () => "Alternate Reality"),
new(FirstTagBasedCategoryId + 0, "other", () => Locs.Category_Other),
new(FirstTagBasedCategoryId + 1, "jobs", () => Locs.Category_Jobs),
new(FirstTagBasedCategoryId + 2, "ui", () => Locs.Category_UI),
@@ -36,7 +37,6 @@ internal class PluginCategoryManager
new(FirstTagBasedCategoryId + 5, "sound", () => Locs.Category_Sound),
new(FirstTagBasedCategoryId + 6, "social", () => Locs.Category_Social),
new(FirstTagBasedCategoryId + 7, "utility", () => Locs.Category_Utility),
-
// order doesn't matter, all tag driven categories should have Id >= FirstTagBasedCategoryId
};
@@ -46,6 +46,7 @@ internal class PluginCategoryManager
new(GroupKind.Installed, () => Locs.Group_Installed, 0, 1),
new(GroupKind.Available, () => Locs.Group_Available, 0),
new(GroupKind.Changelog, () => Locs.Group_Changelog, 0, 12, 13),
+ new(GroupKind.AlternateReality, () => "Alternate Reality", 14),
// order important, used for drawing, keep in sync with defaults for currentGroupIdx
};
@@ -81,6 +82,11 @@ internal class PluginCategoryManager
/// UI group: changelog of plugins.
///
Changelog,
+
+ ///
+ /// April fools!
+ ///
+ AlternateReality
}
///
@@ -167,7 +173,8 @@ internal class PluginCategoryManager
foreach (var tag in pluginCategoryTags)
{
// only tags from whitelist can be accepted
- var matchIdx = Array.FindIndex(this.CategoryList, x => x.Tag.Equals(tag, StringComparison.InvariantCultureIgnoreCase));
+ var matchIdx = Array.FindIndex(this.CategoryList,
+ x => x.Tag.Equals(tag, StringComparison.InvariantCultureIgnoreCase));
if (matchIdx >= 0)
{
var categoryId = this.CategoryList[matchIdx].CategoryId;
@@ -235,7 +242,9 @@ internal class PluginCategoryManager
}
else
{
- var selectedCategoryInfo = Array.Find(this.categoryList, x => x.CategoryId == groupInfo.Categories[this.currentCategoryIdx]);
+ var selectedCategoryInfo = Array.Find(this.categoryList,
+ x => x.CategoryId ==
+ groupInfo.Categories[this.currentCategoryIdx]);
foreach (var plugin in plugins)
{
@@ -330,7 +339,8 @@ internal class PluginCategoryManager
/// Tag to match.
/// Function returning localized name of category.
/// Condition to be checked when deciding whether this category should be shown.
- public CategoryInfo(int categoryId, string tag, Func nameFunc, AppearCondition condition = AppearCondition.None)
+ public CategoryInfo(
+ int categoryId, string tag, Func nameFunc, AppearCondition condition = AppearCondition.None)
{
this.CategoryId = categoryId;
this.Tag = tag;
@@ -403,7 +413,8 @@ internal class PluginCategoryManager
public string Name => this.nameFunc();
}
- [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "locs")]
+ [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented",
+ Justification = "locs")]
internal static class Locs
{
#region UI groups
@@ -424,9 +435,11 @@ internal class PluginCategoryManager
public static string Category_IsTesting => Loc.Localize("InstallerCategoryIsTesting", "Currently Testing");
- public static string Category_AvailableForTesting => Loc.Localize("InstallerCategoryAvailableForTesting", "Testing Available");
+ public static string Category_AvailableForTesting =>
+ Loc.Localize("InstallerCategoryAvailableForTesting", "Testing Available");
- public static string Category_DevInstalled => Loc.Localize("InstallerInstalledDevPlugins", "Installed Dev Plugins");
+ public static string Category_DevInstalled =>
+ Loc.Localize("InstallerInstalledDevPlugins", "Installed Dev Plugins");
public static string Category_IconTester => "Image/Icon Tester";
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index c7847f58e..bbc8d1d7c 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -11,6 +11,7 @@ using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Configuration.Internal;
+using Dalamud.Fools;
using Dalamud.Game.Command;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
@@ -1236,6 +1237,11 @@ internal class PluginInstallerWindow : Window, IDisposable
}
break;
+
+ case PluginCategoryManager.GroupKind.AlternateReality:
+ this.DrawAlternateRealityPlugins();
+ break;
+
default:
this.DrawAvailablePluginList();
break;
@@ -1244,6 +1250,41 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.PopStyleVar();
}
+ private void DrawAlternateRealityPlugins()
+ {
+ var manager = Service.Get();
+
+ foreach (var plugin in manager.FoolsPlugins)
+ {
+ // dropdown
+ if (ImGui.CollapsingHeader($"{plugin.Name}##AprilFools_{plugin.Name}"))
+ {
+ ImGui.Indent();
+ ImGui.Text(plugin.Name);
+ ImGui.SameLine();
+
+ ImGui.TextColored(ImGuiColors.DalamudGrey3, $" by {plugin.Author}");
+
+ ImGui.TextWrapped(plugin.Description);
+
+ if (manager.IsPluginActivated(plugin.InternalName))
+ {
+ if (ImGui.Button("Disable"))
+ {
+ manager.DeactivatePlugin(plugin.InternalName);
+ }
+ }
+ else
+ {
+ if (ImGui.Button("Install"))
+ {
+ manager.ActivatePlugin(plugin.InternalName);
+ }
+ }
+ }
+ }
+ }
+
private void DrawImageTester()
{
var sectionSize = ImGuiHelpers.GlobalScale * 66;