Browse Source

Re-added support for legacy IPA plugins for backwards compatability

refactor
Anairkoen Schno 6 years ago
parent
commit
26cd620fd9
16 changed files with 303 additions and 88 deletions
  1. +1
    -1
      BSIPA.sln
  2. +9
    -11
      IllusionInjector/BeatSaber/CompositeBSPlugin.cs
  3. +77
    -0
      IllusionInjector/IPA/CompositeIPAPlugin.cs
  4. +2
    -1
      IllusionInjector/IllusionInjector.csproj
  5. +27
    -10
      IllusionInjector/PluginComponent.cs
  6. +74
    -36
      IllusionInjector/PluginManager.cs
  7. +1
    -1
      IllusionInjector/obj/Debug/IllusionInjector.csproj.CoreCompileInputs.cache
  8. +2
    -2
      IllusionPlugin/BeatSaber/IBeatSaberPlugin.cs
  9. +10
    -0
      IllusionPlugin/BeatSaber/IEnhancedBeatSaberPlugin.cs
  10. +11
    -0
      IllusionPlugin/IPA/IEnhancedPlugin.cs
  11. +19
    -17
      IllusionPlugin/IPA/IGenericEnhancedPlugin.cs
  12. +58
    -0
      IllusionPlugin/IPA/IPlugin.cs
  13. +5
    -2
      IllusionPlugin/IllusionPlugin.csproj
  14. +3
    -3
      IllusionPlugin/Logger.cs
  15. +3
    -3
      IllusionPlugin/ModPrefs.cs
  16. +1
    -1
      IllusionPlugin/obj/Debug/IllusionPlugin.csproj.CoreCompileInputs.cache

IPA.sln → BSIPA.sln View File

@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Blend for Visual Studio 15
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2043
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA", "IPA\IPA.csproj", "{14092533-98BB-40A4-9AFC-27BB75672A70}"

IllusionInjector/CompositePlugin.cs → IllusionInjector/BeatSaber/CompositeBSPlugin.cs View File

@ -8,14 +8,15 @@ using UnityEngine.SceneManagement;
using Logger = IllusionPlugin.Logger;
namespace IllusionInjector {
public class CompositePlugin : IPlugin {
IEnumerable<IPlugin> plugins;
public class CompositeBSPlugin : IBeatSaberPlugin
{
IEnumerable<IBeatSaberPlugin> plugins;
private delegate void CompositeCall(IPlugin plugin);
private delegate void CompositeCall(IBeatSaberPlugin plugin);
private Logger debugLogger => PluginManager.debugLogger;
public CompositePlugin(IEnumerable<IPlugin> plugins) {
public CompositeBSPlugin(IEnumerable<IBeatSaberPlugin> plugins) {
this.plugins = plugins;
}
@ -59,8 +60,7 @@ namespace IllusionInjector {
}
}
}
private void Invoke(CompositeCall callback) {
foreach (var plugin in plugins) {
try {
@ -71,8 +71,7 @@ namespace IllusionInjector {
}
}
}
public void OnUpdate() {
Invoke(plugin => plugin.OnUpdate());
}
@ -81,7 +80,6 @@ namespace IllusionInjector {
Invoke(plugin => plugin.OnFixedUpdate());
}
public string Name {
get { throw new NotImplementedException(); }
}
@ -92,8 +90,8 @@ namespace IllusionInjector {
public void OnLateUpdate() {
Invoke(plugin => {
if (plugin is IEnhancedPlugin)
((IEnhancedPlugin) plugin).OnLateUpdate();
if (plugin is IEnhancedBeatSaberPlugin)
((IEnhancedBeatSaberPlugin) plugin).OnLateUpdate();
});
}
}

+ 77
- 0
IllusionInjector/IPA/CompositeIPAPlugin.cs View File

@ -0,0 +1,77 @@
using IllusionPlugin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using Logger = IllusionPlugin.Logger;
namespace IllusionInjector {
#pragma warning disable CS0618 // Type or member is obsolete
public class CompositeIPAPlugin : IPlugin
{
IEnumerable<IPlugin> plugins;
private delegate void CompositeCall(IPlugin plugin);
private Logger debugLogger => PluginManager.debugLogger;
public CompositeIPAPlugin(IEnumerable<IPlugin> plugins) {
this.plugins = plugins;
}
public void OnApplicationStart() {
Invoke(plugin => plugin.OnApplicationStart());
}
public void OnApplicationQuit() {
Invoke(plugin => plugin.OnApplicationQuit());
}
private void Invoke(CompositeCall callback) {
foreach (var plugin in plugins) {
try {
callback(plugin);
}
catch (Exception ex) {
debugLogger.Exception($"{plugin.Name}: {ex}");
}
}
}
public void OnUpdate() {
Invoke(plugin => plugin.OnUpdate());
}
public void OnFixedUpdate() {
Invoke(plugin => plugin.OnFixedUpdate());
}
public string Name {
get { throw new NotImplementedException(); }
}
public string Version {
get { throw new NotImplementedException(); }
}
public void OnLateUpdate() {
Invoke(plugin => {
if (plugin is IEnhancedBeatSaberPlugin)
((IEnhancedBeatSaberPlugin) plugin).OnLateUpdate();
});
}
public void OnLevelWasLoaded(int level)
{
Invoke(plugin => plugin.OnLevelWasLoaded(level));
}
public void OnLevelWasInitialized(int level)
{
Invoke(plugin => plugin.OnLevelWasInitialized(level));
}
}
#pragma warning restore CS0618 // Type or member is obsolete
}

+ 2
- 1
IllusionInjector/IllusionInjector.csproj View File

@ -47,9 +47,10 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Bootstrapper.cs" />
<Compile Include="CompositePlugin.cs" />
<Compile Include="BeatSaber\CompositeBSPlugin.cs" />
<Compile Include="ConsoleWindow.cs" />
<Compile Include="Injector.cs" />
<Compile Include="IPA\CompositeIPAPlugin.cs" />
<Compile Include="PluginManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PluginComponent.cs" />


+ 27
- 10
IllusionInjector/PluginComponent.cs View File

@ -8,7 +8,8 @@ namespace IllusionInjector
{
public class PluginComponent : MonoBehaviour
{
private CompositePlugin plugins;
private CompositeBSPlugin bsPlugins;
private CompositeIPAPlugin ipaPlugins;
private bool quitting = false;
public static PluginComponent Create()
@ -20,8 +21,10 @@ namespace IllusionInjector
{
DontDestroyOnLoad(gameObject);
plugins = new CompositePlugin(PluginManager.Plugins);
plugins.OnApplicationStart();
bsPlugins = new CompositeBSPlugin(PluginManager.BSPlugins);
ipaPlugins = new CompositeIPAPlugin(PluginManager.IPAPlugins);
bsPlugins.OnApplicationStart();
ipaPlugins.OnApplicationStart();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
SceneManager.sceneLoaded += OnSceneLoaded;
@ -30,17 +33,20 @@ namespace IllusionInjector
void Update()
{
plugins.OnUpdate();
bsPlugins.OnUpdate();
ipaPlugins.OnUpdate();
}
void LateUpdate()
{
plugins.OnLateUpdate();
bsPlugins.OnLateUpdate();
ipaPlugins.OnLateUpdate();
}
void FixedUpdate()
{
plugins.OnFixedUpdate();
bsPlugins.OnFixedUpdate();
ipaPlugins.OnFixedUpdate();
}
void OnDestroy()
@ -57,22 +63,33 @@ namespace IllusionInjector
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.sceneUnloaded += OnSceneUnloaded;
plugins.OnApplicationQuit();
bsPlugins.OnApplicationQuit();
ipaPlugins.OnApplicationQuit();
quitting = true;
}
void OnLevelWasLoaded(int level)
{
ipaPlugins.OnLevelWasLoaded(level);
}
public void OnLevelWasInitialized(int level)
{
ipaPlugins.OnLevelWasInitialized(level);
}
void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode)
{
plugins.OnSceneLoaded(scene, sceneMode);
bsPlugins.OnSceneLoaded(scene, sceneMode);
}
private void OnSceneUnloaded(Scene scene) {
plugins.OnSceneUnloaded(scene);
bsPlugins.OnSceneUnloaded(scene);
}
private void OnActiveSceneChanged(Scene prevScene, Scene nextScene) {
plugins.OnActiveSceneChanged(prevScene, nextScene);
bsPlugins.OnActiveSceneChanged(prevScene, nextScene);
}
}


+ 74
- 36
IllusionInjector/PluginManager.cs View File

@ -13,24 +13,38 @@ namespace IllusionInjector
{
public static class PluginManager
{
private static List<IPlugin> _Plugins = null;
#pragma warning disable CS0618 // Type or member is obsolete (IPlugin)
internal static readonly Logger debugLogger = new Logger("IllusionInjector");
/// <summary>
/// Gets the list of loaded plugins and loads them if necessary.
/// </summary>
public static IEnumerable<IPlugin> Plugins
public static IEnumerable<IBeatSaberPlugin> BSPlugins
{
get
{
if(_Plugins == null)
if(_bsPlugins == null)
{
LoadPlugins();
}
return _Plugins;
return _bsPlugins;
}
}
private static List<IBeatSaberPlugin> _bsPlugins = null;
public static IEnumerable<IPlugin> IPAPlugins
{
get
{
if (_ipaPlugins == null)
{
LoadPlugins();
}
return _ipaPlugins;
}
}
private static List<IPlugin> _ipaPlugins = null;
private static void LoadPlugins()
@ -41,17 +55,20 @@ namespace IllusionInjector
// so we need to resort to P/Invoke
string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);
debugLogger.Log(exeName);
_Plugins = new List<IPlugin>();
_bsPlugins = new List<IBeatSaberPlugin>();
_ipaPlugins = new List<IPlugin>();
if (!Directory.Exists(pluginDirectory)) return;
if (!Directory.Exists(Path.Combine(pluginDirectory, ".cache")))
string cacheDir = Path.Combine(pluginDirectory, ".cache");
if (!Directory.Exists(cacheDir))
{
Directory.CreateDirectory(Path.Combine(pluginDirectory, ".cache"));
Directory.CreateDirectory(cacheDir);
}
else
{
foreach (string plugin in Directory.GetFiles(Path.Combine(pluginDirectory, ".cache"), "*"))
foreach (string plugin in Directory.GetFiles(cacheDir, "*"))
{
File.Delete(plugin);
}
@ -61,37 +78,66 @@ namespace IllusionInjector
string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll");
foreach (string s in originalPlugins)
{
string pluginCopy = pluginDirectory + "\\.cache" + s.Substring(s.LastIndexOf('\\'));
string pluginCopy = Path.Combine(cacheDir, Path.GetFileName(s));
File.Copy(Path.Combine(pluginDirectory, s), pluginCopy);
}
//Load copied plugins
string copiedPluginsDirectory = pluginDirectory + "\\.cache";
string[] copiedPlugins = Directory.GetFiles(copiedPluginsDirectory, "*.dll");
string[] copiedPlugins = Directory.GetFiles(cacheDir, "*.dll");
foreach (string s in copiedPlugins)
{
_Plugins.AddRange(LoadPluginsFromFile(s, exeName));
var result = LoadPluginsFromFile(s, exeName);
_bsPlugins.AddRange(result.Item1);
_ipaPlugins.AddRange(result.Item2);
}
// DEBUG
debugLogger.Log($"Running on Unity {UnityEngine.Application.unityVersion}");
debugLogger.Log("-----------------------------");
debugLogger.Log($"Loading plugins from {pluginDirectory} and found {_Plugins.Count}");
debugLogger.Log($"Loading plugins from {pluginDirectory} and found {_bsPlugins.Count}");
debugLogger.Log("-----------------------------");
foreach (var plugin in _Plugins)
foreach (var plugin in _bsPlugins)
{
debugLogger.Log($"{plugin.Name}: {plugin.Version}");
}
debugLogger.Log("-----------------------------");
}
private static IEnumerable<IPlugin> LoadPluginsFromFile(string file, string exeName)
private static Tuple<IEnumerable<IBeatSaberPlugin>, IEnumerable<IPlugin>> LoadPluginsFromFile(string file, string exeName)
{
List<IPlugin> plugins = new List<IPlugin>();
List<IBeatSaberPlugin> bsPlugins = new List<IBeatSaberPlugin>();
List<IPlugin> ipaPlugins = new List<IPlugin>();
if (!File.Exists(file) || !file.EndsWith(".dll", true, null))
return plugins;
return new Tuple<IEnumerable<IBeatSaberPlugin>, IEnumerable<IPlugin>>(bsPlugins, ipaPlugins);
T OptionalGetPlugin<T>(Type t) where T : class
{
// use typeof() to allow for easier renaming (in an ideal world this compiles to a string, but ¯\_(ツ)_/¯)
if (t.GetInterface(typeof(T).Name) != null)
{
try
{
T pluginInstance = Activator.CreateInstance(t) as T;
string[] filter = null;
if (pluginInstance is IGenericEnhancedPlugin)
{
filter = ((IGenericEnhancedPlugin)pluginInstance).Filter;
}
if (filter == null || filter.Contains(exeName, StringComparer.OrdinalIgnoreCase))
return pluginInstance;
}
catch (Exception e)
{
debugLogger.Exception($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}");
}
}
return null;
}
try
{
@ -99,25 +145,17 @@ namespace IllusionInjector
foreach (Type t in assembly.GetTypes())
{
if (t.GetInterface("IPlugin") != null)
IBeatSaberPlugin bsPlugin = OptionalGetPlugin<IBeatSaberPlugin>(t);
if (bsPlugin != null)
{
try
{
IPlugin pluginInstance = Activator.CreateInstance(t) as IPlugin;
string[] filter = null;
if (pluginInstance is IEnhancedPlugin)
{
filter = ((IEnhancedPlugin)pluginInstance).Filter;
}
if(filter == null || filter.Contains(exeName, StringComparer.OrdinalIgnoreCase))
plugins.Add(pluginInstance);
}
catch (Exception e)
bsPlugins.Add(bsPlugin);
}
else
{
IPlugin ipaPlugin = OptionalGetPlugin<IPlugin>(t);
if (ipaPlugin != null)
{
debugLogger.Exception($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}");
ipaPlugins.Add(ipaPlugin);
}
}
}
@ -128,7 +166,7 @@ namespace IllusionInjector
debugLogger.Error($"Could not load {Path.GetFileName(file)}! {e}");
}
return plugins;
return new Tuple<IEnumerable<IBeatSaberPlugin>, IEnumerable<IPlugin>>(bsPlugins, ipaPlugins);
}
public class AppInfo
@ -146,6 +184,6 @@ namespace IllusionInjector
}
}
}
#pragma warning restore CS0618 // Type or member is obsolete (IPlugin)
}
}

+ 1
- 1
IllusionInjector/obj/Debug/IllusionInjector.csproj.CoreCompileInputs.cache View File

@ -1 +1 @@
e3db2f4e6085eb1ed3ec468191bb328ebb0f8b7f
26a9be3d697b3ac9c2a8af98062cb97cf748184e

IllusionPlugin/IPlugin.cs → IllusionPlugin/BeatSaber/IBeatSaberPlugin.cs View File

@ -6,10 +6,10 @@ using UnityEngine.SceneManagement;
namespace IllusionPlugin
{
/// <summary>
/// Interface for generic Illusion unity plugins. Every class that implements this will be loaded if the DLL is placed at
/// Interface for Beat Saber plugins. Every class that implements this will be loaded if the DLL is placed at
/// data/Managed/Plugins.
/// </summary>
public interface IPlugin
public interface IBeatSaberPlugin
{
/// <summary>

+ 10
- 0
IllusionPlugin/BeatSaber/IEnhancedBeatSaberPlugin.cs View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IllusionPlugin
{
public interface IEnhancedBeatSaberPlugin : IBeatSaberPlugin, IGenericEnhancedPlugin
{
}
}

+ 11
- 0
IllusionPlugin/IPA/IEnhancedPlugin.cs View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IllusionPlugin
{
[Obsolete("When building plugins for Beat Saber, use IEnhancedBeatSaberPlugin")]
public interface IEnhancedPlugin : IPlugin, IGenericEnhancedPlugin
{
}
}

IllusionPlugin/IEnhancedPlugin.cs → IllusionPlugin/IPA/IGenericEnhancedPlugin.cs View File

@ -1,17 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IllusionPlugin
{
public interface IEnhancedPlugin : IPlugin
{
/// <summary>
/// Gets a list of executables this plugin should be excuted on (without the file ending)
/// </summary>
/// <example>{ "PlayClub", "PlayClubStudio" }</example>
string[] Filter { get; }
void OnLateUpdate();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IllusionPlugin
{
public interface IGenericEnhancedPlugin
{
/// <summary>
/// Gets a list of executables this plugin should be excuted on (without the file ending)
/// </summary>
/// <example>{ "PlayClub", "PlayClubStudio" }</example>
string[] Filter { get; }
void OnLateUpdate();
}
}

+ 58
- 0
IllusionPlugin/IPA/IPlugin.cs View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IllusionPlugin
{
/// <summary>
/// Interface for generic Illusion unity plugins. Every class that implements this will be loaded if the DLL is placed at
/// data/Managed/Plugins.
/// </summary>
[Obsolete("When building plugins for Beat Saber, use IBeatSaberPlugin")]
public interface IPlugin
{
/// <summary>
/// Gets the name of the plugin.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the version of the plugin.
/// </summary>
string Version { get; }
/// <summary>
/// Gets invoked when the application is started.
/// </summary>
void OnApplicationStart();
/// <summary>
/// Gets invoked when the application is closed.
/// </summary>
void OnApplicationQuit();
/// <summary>
/// Gets invoked whenever a level is loaded.
/// </summary>
/// <param name="level"></param>
void OnLevelWasLoaded(int level);
/// <summary>
/// Gets invoked after the first update cycle after a level was loaded.
/// </summary>
/// <param name="level"></param>
void OnLevelWasInitialized(int level);
/// <summary>
/// Gets invoked on every graphic update.
/// </summary>
void OnUpdate();
/// <summary>
/// Gets invoked on ever physics update.
/// </summary>
void OnFixedUpdate();
}
}

+ 5
- 2
IllusionPlugin/IllusionPlugin.csproj View File

@ -43,9 +43,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="IEnhancedPlugin.cs" />
<Compile Include="BeatSaber\IEnhancedBeatSaberPlugin.cs" />
<Compile Include="IniFile.cs" />
<Compile Include="IPlugin.cs" />
<Compile Include="BeatSaber\IBeatSaberPlugin.cs" />
<Compile Include="IPA\IEnhancedPlugin.cs" />
<Compile Include="IPA\IGenericEnhancedPlugin.cs" />
<Compile Include="IPA\IPlugin.cs" />
<Compile Include="Logger.cs" />
<Compile Include="ModPrefs.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />


+ 3
- 3
IllusionPlugin/Logger.cs View File

@ -53,7 +53,7 @@ namespace IllusionPlugin {
_logFile.Create().Close();
}
public Logger(IPlugin plugin)
public Logger(IBeatSaberPlugin plugin)
{
SetupStatic();
_logFile = GetPath(plugin);
@ -135,7 +135,7 @@ namespace IllusionPlugin {
}
}
FileInfo GetPath(IPlugin plugin) => GetPath(plugin.Name);
FileInfo GetPath(IBeatSaberPlugin plugin) => GetPath(plugin.Name);
FileInfo GetPath(string modName) {
ModName = modName;
var logsDir = new DirectoryInfo($"./Logs/{modName}/{DateTime.Now:dd-MM-yy}");
@ -145,7 +145,7 @@ namespace IllusionPlugin {
}
public static class LoggerExtensions {
public static Logger GetLogger(this IPlugin plugin) {
public static Logger GetLogger(this IBeatSaberPlugin plugin) {
return new Logger(plugin);
}
}

+ 3
- 3
IllusionPlugin/ModPrefs.cs View File

@ -11,11 +11,11 @@ namespace IllusionPlugin
/// Allows to get and set preferences for your mod.
/// </summary>
public class ModPrefs {
internal static Dictionary<IPlugin, ModPrefs> ModPrefses { get; set; } = new Dictionary<IPlugin, ModPrefs>();
internal static Dictionary<IBeatSaberPlugin, ModPrefs> ModPrefses { get; set; } = new Dictionary<IBeatSaberPlugin, ModPrefs>();
private IniFile Instance;
public ModPrefs(IPlugin plugin) {
public ModPrefs(IBeatSaberPlugin plugin) {
Instance = new IniFile(Path.Combine(Environment.CurrentDirectory, $"UserData/ModPrefs/{plugin.Name}.ini"));
ModPrefses.Add(plugin, this);
}
@ -160,7 +160,7 @@ namespace IllusionPlugin
}
public static class ModPrefsExtensions {
public static ModPrefs GetModPrefs(this IPlugin plugin) {
public static ModPrefs GetModPrefs(this IBeatSaberPlugin plugin) {
return ModPrefs.ModPrefses.First(o => o.Key == plugin).Value;
}
}


+ 1
- 1
IllusionPlugin/obj/Debug/IllusionPlugin.csproj.CoreCompileInputs.cache View File

@ -1 +1 @@
3916871581af94648b18c3cc477ec3f5b61ffa03
eb108721e2940659deee6bd068631e6d4749736e

Loading…
Cancel
Save