diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj
index 1cf1965e..fe782f84 100644
--- a/IPA.Loader/IPA.Loader.csproj
+++ b/IPA.Loader/IPA.Loader.csproj
@@ -111,6 +111,8 @@
+
+
@@ -167,7 +169,7 @@
-
+
\ No newline at end of file
diff --git a/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs b/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs
index d4e9c755..9b0a1b9a 100644
--- a/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs
+++ b/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs
@@ -5,7 +5,11 @@ using Logger = IPA.Logging.Logger;
namespace IPA.Loader.Composite
{
- internal class CompositeBSPlugin : IBeatSaberPlugin
+ internal class CompositeBSPlugin :
+#pragma warning disable CS0618 // Type or member is obsolete
+ IBeatSaberPlugin,
+#pragma warning restore CS0618 // Type or member is obsolete
+ _IPlugin
{
private readonly IEnumerable plugins;
@@ -15,8 +19,9 @@ namespace IPA.Loader.Composite
this.plugins = plugins;
}
+ [Obsolete]
public void OnApplicationStart() {
- Invoke(plugin => plugin.Plugin.OnApplicationStart());
+ Invoke(plugin => (plugin.Plugin as IBeatSaberPlugin)?.OnApplicationStart());
}
public void OnApplicationQuit() {
@@ -61,7 +66,7 @@ namespace IPA.Loader.Composite
public void OnLateUpdate() {
Invoke(plugin => {
- if (plugin.Plugin is IEnhancedBeatSaberPlugin saberPlugin)
+ if (plugin.Plugin is IGenericEnhancedPlugin saberPlugin)
saberPlugin.OnLateUpdate();
});
}
diff --git a/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs b/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs
index 9825f6bc..6817eb8e 100644
--- a/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs
+++ b/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs
@@ -6,13 +6,13 @@ using Logger = IPA.Logging.Logger;
namespace IPA.Loader.Composite
{
#pragma warning disable CS0618 // Type or member is obsolete
- internal class CompositeIPAPlugin : IPlugin
+ internal class CompositeIPAPlugin : Old.IPlugin
{
- private readonly IEnumerable plugins;
+ private readonly IEnumerable plugins;
- private delegate void CompositeCall(IPlugin plugin);
+ private delegate void CompositeCall(Old.IPlugin plugin);
- public CompositeIPAPlugin(IEnumerable plugins) {
+ public CompositeIPAPlugin(IEnumerable plugins) {
this.plugins = plugins;
}
@@ -49,7 +49,7 @@ namespace IPA.Loader.Composite
public void OnLateUpdate() {
Invoke(plugin => {
- if (plugin is IEnhancedPlugin saberPlugin)
+ if (plugin is Old.IEnhancedPlugin saberPlugin)
saberPlugin.OnLateUpdate();
});
}
diff --git a/IPA.Loader/Loader/Features/Feature.cs b/IPA.Loader/Loader/Features/Feature.cs
index 5817bc74..b790f2c0 100644
--- a/IPA.Loader/Loader/Features/Feature.cs
+++ b/IPA.Loader/Loader/Features/Feature.cs
@@ -68,7 +68,7 @@ namespace IPA.Loader.Features
///
/// the plugin that was just initialized
/// the instance of the plugin being initialized
- public virtual void AfterInit(PluginLoader.PluginInfo plugin, IBeatSaberPlugin pluginInstance) => AfterInit(plugin);
+ public virtual void AfterInit(PluginLoader.PluginInfo plugin, IPlugin pluginInstance) => AfterInit(plugin);
///
/// Called after a plugin has been fully initialized, whether or not there is an `Init` method. This should never throw an exception.
diff --git a/IPA.Loader/Loader/LibLoader.cs b/IPA.Loader/Loader/LibLoader.cs
index d6e2601a..01b23a3d 100644
--- a/IPA.Loader/Loader/LibLoader.cs
+++ b/IPA.Loader/Loader/LibLoader.cs
@@ -7,16 +7,23 @@ using System.Reflection;
using System.Runtime.InteropServices;
using System.Linq;
using IPA.Logging;
+using IPA.Utilities;
using Mono.Cecil;
namespace IPA.Loader
{
internal class CecilLibLoader : BaseAssemblyResolver
{
+ private static string CurrentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
+ private static string CurrentAssemblyPath = Assembly.GetExecutingAssembly().Location;
+
public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
LibLoader.SetupAssemblyFilenames();
+ if (name.Name == CurrentAssemblyName)
+ return AssemblyDefinition.ReadAssembly(CurrentAssemblyPath, parameters);
+
if (LibLoader.FilenameLocations.TryGetValue($"{name.Name}.{name.Version}.dll", out var path))
{
if (File.Exists(path))
diff --git a/IPA.Loader/Loader/PluginComponent.cs b/IPA.Loader/Loader/PluginComponent.cs
index c0fcf8d0..88457e79 100644
--- a/IPA.Loader/Loader/PluginComponent.cs
+++ b/IPA.Loader/Loader/PluginComponent.cs
@@ -34,7 +34,9 @@ namespace IPA.Loader
gameObject.AddComponent();
#endif
+#pragma warning disable CS0612 // Type or member is obsolete
bsPlugins.OnApplicationStart();
+#pragma warning restore CS0612 // Type or member is obsolete
ipaPlugins.OnApplicationStart();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs
index 99deaaa5..e7b0eff6 100644
--- a/IPA.Loader/Loader/PluginLoader.cs
+++ b/IPA.Loader/Loader/PluginLoader.cs
@@ -124,7 +124,7 @@ namespace IPA.Loader
///
public class PluginInfo
{
- internal IBeatSaberPlugin Plugin { get; set; }
+ internal _IPlugin Plugin { get; set; }
///
/// Metadata for the plugin.
@@ -243,17 +243,14 @@ namespace IPA.Loader
{
if (type.Namespace != pluginNs) continue;
- foreach (var inter in type.Interfaces)
+ // TODO: change this to just IPlugin
+ if (type.HasInterface(typeof(_IPlugin).FullName))
{
- if (typeof(IBeatSaberPlugin).FullName == inter.InterfaceType.FullName)
- {
- metadata.PluginType = type;
- goto type_loop_done; // break out of both loops
- }
+ metadata.PluginType = type;
+ break;
}
}
- type_loop_done:
if (metadata.PluginType == null)
{
Logger.loader.Error($"No plugin found in the manifest namespace ({pluginNs}) in {Path.GetFileName(plugin)}");
@@ -645,7 +642,7 @@ namespace IPA.Loader
}
var type = meta.Assembly.GetType(meta.PluginType.FullName);
- var instance = (IBeatSaberPlugin)Activator.CreateInstance(type);
+ var instance = Activator.CreateInstance(type) as _IPlugin;
info.Metadata = meta;
info.Plugin = instance;
@@ -668,17 +665,18 @@ namespace IPA.Loader
foreach (var feature in meta.Features)
try
{
- feature.AfterInit(info, info.Plugin);
+ // TODO: remove need for cast
+ feature.AfterInit(info, info.Plugin as IPlugin);
}
catch (Exception e)
{
Logger.loader.Critical($"Feature errored in {nameof(Feature.AfterInit)}: {e}");
}
- if (instance is IDisablablePlugin disable)
+ if (instance is IPlugin newPlugin) // TODO: remove this check, all plugins should be IPlugin
try // TODO: move this out to after all plugins have been inited
{
- disable.OnEnable();
+ newPlugin.OnEnable();
}
catch (Exception e)
{
diff --git a/IPA.Loader/Loader/PluginManager.cs b/IPA.Loader/Loader/PluginManager.cs
index 6f081c98..a26c6385 100644
--- a/IPA.Loader/Loader/PluginManager.cs
+++ b/IPA.Loader/Loader/PluginManager.cs
@@ -32,7 +32,7 @@ namespace IPA.Loader
///
/// An of new Beat Saber plugins
///
- internal static IEnumerable BSPlugins => (_bsPlugins ?? throw new InvalidOperationException()).Select(p => p.Plugin);
+ internal static IEnumerable<_IPlugin> BSPlugins => (_bsPlugins ?? throw new InvalidOperationException()).Select(p => p.Plugin);
private static List _bsPlugins;
internal static IEnumerable BSMetas => _bsPlugins;
@@ -174,11 +174,11 @@ namespace IPA.Loader
var depsNeedRestart = plugin.Dependencies.Aggregate(false, (b, p) => EnablePlugin(p) || b);
var runtimeInfo = runtimeDisabled.FirstOrDefault(p => p.Metadata == plugin);
- if (runtimeInfo != null && runtimeInfo.Plugin is IDisablablePlugin disable)
+ if (runtimeInfo != null && runtimeInfo.Plugin is IPlugin newPlugin)
{
try
{
- disable.OnEnable();
+ newPlugin.OnEnable();
}
catch (Exception e)
{
@@ -290,8 +290,8 @@ namespace IPA.Loader
///
/// all legacy plugin instances
[Obsolete("I mean, IPlugin shouldn't be used, so why should this? Not renaming to extend support for old plugins.")]
- public static IEnumerable Plugins => _ipaPlugins;
- private static List _ipaPlugins;
+ public static IEnumerable Plugins => _ipaPlugins;
+ private static List _ipaPlugins;
internal static IConfigProvider SelfConfigProvider { get; set; }
@@ -303,7 +303,7 @@ namespace IPA.Loader
// so we need to resort to P/Invoke
string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);
_bsPlugins = new List();
- _ipaPlugins = new List();
+ _ipaPlugins = new List();
if (!Directory.Exists(pluginDirectory)) return;
@@ -398,12 +398,12 @@ namespace IPA.Loader
Logger.log.Info("-----------------------------");
}
- private static Tuple, IEnumerable> LoadPluginsFromFile(string file)
+ private static Tuple, IEnumerable> LoadPluginsFromFile(string file)
{
- List ipaPlugins = new List();
+ var ipaPlugins = new List();
if (!File.Exists(file) || !file.EndsWith(".dll", true, null))
- return new Tuple, IEnumerable>(null, ipaPlugins);
+ return new Tuple, IEnumerable>(null, ipaPlugins);
T OptionalGetPlugin(Type t) where T : class
{
@@ -431,7 +431,7 @@ namespace IPA.Loader
foreach (Type t in assembly.GetTypes())
{
- IPlugin ipaPlugin = OptionalGetPlugin(t);
+ var ipaPlugin = OptionalGetPlugin(t);
if (ipaPlugin != null)
{
ipaPlugins.Add(ipaPlugin);
@@ -450,7 +450,7 @@ namespace IPA.Loader
Logger.loader.Error(e);
}
- return new Tuple, IEnumerable>(null, ipaPlugins);
+ return new Tuple, IEnumerable>(null, ipaPlugins);
}
internal static class AppInfo
diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs b/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs
index 96936c94..2d16355e 100644
--- a/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs
+++ b/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs
@@ -1,4 +1,4 @@
-using UnityEngine.SceneManagement;
+using System;
// ReSharper disable CheckNamespace
namespace IPA
@@ -7,48 +7,14 @@ namespace IPA
/// Interface for Beat Saber plugins. Every class that implements this will be loaded if the DLL is placed at
/// data/Managed/Plugins.
///
- public interface IBeatSaberPlugin
+ [Obsolete("Use IPA.IPlugin instead")]
+ public interface IBeatSaberPlugin : _IPlugin
{
///
/// Gets invoked when the application is started.
///
- /// THIS EVENT WILL NOT BE GUARANTEED TO FIRE. USE Init OR INSTEAD.
+ /// THIS EVENT WILL NOT BE GUARANTEED TO FIRE. USE Init OR INSTEAD.
///
void OnApplicationStart();
-
- ///
- /// Gets invoked when the application is closed.
- ///
- void OnApplicationQuit();
-
- ///
- /// Gets invoked on every graphic update.
- ///
- void OnUpdate();
-
- ///
- /// Gets invoked on ever physics update.
- ///
- void OnFixedUpdate();
-
- ///
- /// Gets invoked whenever a scene is loaded.
- ///
- /// The scene currently loaded
- /// The type of loading
- void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode);
-
- ///
- /// Gets invoked whenever a scene is unloaded
- ///
- /// The unloaded scene
- void OnSceneUnloaded(Scene scene);
-
- ///
- /// Gets invoked whenever a scene is changed
- ///
- /// The Scene that was previously loaded
- /// The Scene being loaded
- void OnActiveSceneChanged(Scene prevScene, Scene nextScene);
}
}
diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/IDisablablePlugin.cs b/IPA.Loader/PluginInterfaces/BeatSaber/IDisablablePlugin.cs
index 14c918fe..fdabfd74 100644
--- a/IPA.Loader/PluginInterfaces/BeatSaber/IDisablablePlugin.cs
+++ b/IPA.Loader/PluginInterfaces/BeatSaber/IDisablablePlugin.cs
@@ -5,7 +5,7 @@
///
public interface IDisablablePlugin
{
- ///
+ /*///
/// Called when a plugin is enabled. This is where you should set up Harmony patches and the like.
///
///
@@ -14,14 +14,14 @@
///
/// Init will only ever be called once.
///
- void OnEnable();
+ void OnEnable();*/
///
/// Called when a plugin is disabled at runtime. This should disable things like Harmony patches and unsubscribe
/// from events. After this is called there should be no lingering effects of the mod.
///
///
- /// This will get called at shutdown, after , as well as when the
+ /// This will get called at shutdown, after , as well as when the
/// plugin is disabled at runtime.
///
void OnDisable();
diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs b/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs
index da67e31d..e83ce7f3 100644
--- a/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs
+++ b/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs
@@ -5,6 +5,7 @@ namespace IPA
///
/// An enhanced version of a standard BeatSaber plugin.
///
+ [System.Obsolete]
public interface IEnhancedBeatSaberPlugin : IBeatSaberPlugin, IGenericEnhancedPlugin
{
}
diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedPlugin.cs b/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedPlugin.cs
new file mode 100644
index 00000000..c0dcc842
--- /dev/null
+++ b/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedPlugin.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace IPA
+{
+ ///
+ ///
+ /// An enhanced version of a standard BeatSaber plugin.
+ ///
+ public interface IEnhancedPlugin : IPlugin, IGenericEnhancedPlugin
+ {
+ }
+}
diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/IPlugin.cs b/IPA.Loader/PluginInterfaces/BeatSaber/IPlugin.cs
new file mode 100644
index 00000000..60cbce66
--- /dev/null
+++ b/IPA.Loader/PluginInterfaces/BeatSaber/IPlugin.cs
@@ -0,0 +1,61 @@
+using UnityEngine.SceneManagement;
+
+namespace IPA
+{
+ ///
+ /// Interface for BSIPA plugins. Every class that implements this will be loaded if the DLL is placed at
+ /// <install dir>/Plugins.
+ ///
+ public interface IPlugin : _IPlugin
+ {
+ ///
+ /// Called when a plugin is enabled. This is where you should set up Harmony patches and the like.
+ ///
+ ///
+ /// This will be called after Init, and will be called when the plugin loads normally too.
+ /// When a plugin is disabled at startup, neither this nor Init will be called until it is enabled.
+ ///
+ /// Init will only ever be called once.
+ ///
+ void OnEnable();
+ }
+ ///
+ /// An interface for providing compatability with BSIPA 3.x.x. Do not use.
+ ///
+ public interface _IPlugin {
+ ///
+ /// Gets invoked when the application is closed.
+ ///
+ void OnApplicationQuit();
+
+ ///
+ /// Gets invoked on every graphic update.
+ ///
+ void OnUpdate();
+
+ ///
+ /// Gets invoked on ever physics update.
+ ///
+ void OnFixedUpdate();
+
+ ///
+ /// Gets invoked whenever a scene is loaded.
+ ///
+ /// The scene currently loaded
+ /// The type of loading
+ void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode);
+
+ ///
+ /// Gets invoked whenever a scene is unloaded
+ ///
+ /// The unloaded scene
+ void OnSceneUnloaded(Scene scene);
+
+ ///
+ /// Gets invoked whenever a scene is changed
+ ///
+ /// The Scene that was previously loaded
+ /// The Scene being loaded
+ void OnActiveSceneChanged(Scene prevScene, Scene nextScene);
+ }
+}
diff --git a/IPA.Loader/Utilities/Utils.cs b/IPA.Loader/Utilities/Utils.cs
index 87743ed8..b3205068 100644
--- a/IPA.Loader/Utilities/Utils.cs
+++ b/IPA.Loader/Utilities/Utils.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Text;
using System.Linq;
using System.Collections.Generic;
+using Mono.Cecil;
#if NET3
using File = Net3_Proxy.File;
#endif
@@ -187,6 +188,11 @@ namespace IPA.Utilities
cmpVal = l.Patch - r.Patch;
return cmpVal;
}
+ internal static bool HasInterface(this TypeDefinition type, string interfaceFullName)
+ {
+ return (type.Interfaces.Any(i => i.InterfaceType.FullName == interfaceFullName)
+ || type.Interfaces.Any(t => HasInterface(t.InterfaceType.Resolve(), interfaceFullName)));
+ }
#if NET4
internal static IEnumerable StrJP(this IEnumerable a) => a;
diff --git a/Refs/Assembly-CSharp.dll b/Refs/Assembly-CSharp.dll
index f3f83203..48b0eeb1 100644
Binary files a/Refs/Assembly-CSharp.dll and b/Refs/Assembly-CSharp.dll differ
diff --git a/Refs/Unity.TextMeshPro.dll b/Refs/Unity.TextMeshPro.dll
index 4e1ca61e..4a3242e5 100644
Binary files a/Refs/Unity.TextMeshPro.dll and b/Refs/Unity.TextMeshPro.dll differ
diff --git a/Refs/UnityEngine.CoreModule.Net4.dll b/Refs/UnityEngine.CoreModule.Net4.dll
index b6940600..158ef534 100644
Binary files a/Refs/UnityEngine.CoreModule.Net4.dll and b/Refs/UnityEngine.CoreModule.Net4.dll differ