Browse Source

First pass on migrating to new plugin interface

4.0.0-beta
Anairkoen Schno 5 years ago
parent
commit
1b22d1d480
17 changed files with 138 additions and 74 deletions
  1. +3
    -1
      IPA.Loader/IPA.Loader.csproj
  2. +8
    -3
      IPA.Loader/Loader/Composite/CompositeBSPlugin.cs
  3. +5
    -5
      IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs
  4. +1
    -1
      IPA.Loader/Loader/Features/Feature.cs
  5. +7
    -0
      IPA.Loader/Loader/LibLoader.cs
  6. +2
    -0
      IPA.Loader/Loader/PluginComponent.cs
  7. +10
    -12
      IPA.Loader/Loader/PluginLoader.cs
  8. +11
    -11
      IPA.Loader/Loader/PluginManager.cs
  9. +4
    -38
      IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs
  10. +3
    -3
      IPA.Loader/PluginInterfaces/BeatSaber/IDisablablePlugin.cs
  11. +1
    -0
      IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs
  12. +16
    -0
      IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedPlugin.cs
  13. +61
    -0
      IPA.Loader/PluginInterfaces/BeatSaber/IPlugin.cs
  14. +6
    -0
      IPA.Loader/Utilities/Utils.cs
  15. BIN
      Refs/Assembly-CSharp.dll
  16. BIN
      Refs/Unity.TextMeshPro.dll
  17. BIN
      Refs/UnityEngine.CoreModule.Net4.dll

+ 3
- 1
IPA.Loader/IPA.Loader.csproj View File

@ -111,6 +111,8 @@
<Compile Include="PluginInterfaces\BeatSaber\IBeatSaberPlugin.cs" /> <Compile Include="PluginInterfaces\BeatSaber\IBeatSaberPlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IDisablablePlugin.cs" /> <Compile Include="PluginInterfaces\BeatSaber\IDisablablePlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IEnhancedBeatSaberPlugin.cs" /> <Compile Include="PluginInterfaces\BeatSaber\IEnhancedBeatSaberPlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IEnhancedPlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IPlugin.cs" />
<Compile Include="PluginInterfaces\IGenericEnhancedPlugin.cs" /> <Compile Include="PluginInterfaces\IGenericEnhancedPlugin.cs" />
<Compile Include="Config\IniFile.cs" /> <Compile Include="Config\IniFile.cs" />
<Compile Include="PluginInterfaces\IPA\IEnhancedPlugin.cs" /> <Compile Include="PluginInterfaces\IPA\IEnhancedPlugin.cs" />
@ -167,7 +169,7 @@
<EmbeddedResource Include="Loader\description.md" /> <EmbeddedResource Include="Loader\description.md" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="icon_black.png" />
<None Include="icon_black.png" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>

+ 8
- 3
IPA.Loader/Loader/Composite/CompositeBSPlugin.cs View File

@ -5,7 +5,11 @@ using Logger = IPA.Logging.Logger;
namespace IPA.Loader.Composite 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<PluginLoader.PluginInfo> plugins; private readonly IEnumerable<PluginLoader.PluginInfo> plugins;
@ -15,8 +19,9 @@ namespace IPA.Loader.Composite
this.plugins = plugins; this.plugins = plugins;
} }
[Obsolete]
public void OnApplicationStart() { public void OnApplicationStart() {
Invoke(plugin => plugin.Plugin.OnApplicationStart());
Invoke(plugin => (plugin.Plugin as IBeatSaberPlugin)?.OnApplicationStart());
} }
public void OnApplicationQuit() { public void OnApplicationQuit() {
@ -61,7 +66,7 @@ namespace IPA.Loader.Composite
public void OnLateUpdate() { public void OnLateUpdate() {
Invoke(plugin => { Invoke(plugin => {
if (plugin.Plugin is IEnhancedBeatSaberPlugin saberPlugin)
if (plugin.Plugin is IGenericEnhancedPlugin saberPlugin)
saberPlugin.OnLateUpdate(); saberPlugin.OnLateUpdate();
}); });
} }


+ 5
- 5
IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs View File

@ -6,13 +6,13 @@ using Logger = IPA.Logging.Logger;
namespace IPA.Loader.Composite namespace IPA.Loader.Composite
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
internal class CompositeIPAPlugin : IPlugin
internal class CompositeIPAPlugin : Old.IPlugin
{ {
private readonly IEnumerable<IPlugin> plugins;
private readonly IEnumerable<Old.IPlugin> plugins;
private delegate void CompositeCall(IPlugin plugin);
private delegate void CompositeCall(Old.IPlugin plugin);
public CompositeIPAPlugin(IEnumerable<IPlugin> plugins) {
public CompositeIPAPlugin(IEnumerable<Old.IPlugin> plugins) {
this.plugins = plugins; this.plugins = plugins;
} }
@ -49,7 +49,7 @@ namespace IPA.Loader.Composite
public void OnLateUpdate() { public void OnLateUpdate() {
Invoke(plugin => { Invoke(plugin => {
if (plugin is IEnhancedPlugin saberPlugin)
if (plugin is Old.IEnhancedPlugin saberPlugin)
saberPlugin.OnLateUpdate(); saberPlugin.OnLateUpdate();
}); });
} }


+ 1
- 1
IPA.Loader/Loader/Features/Feature.cs View File

@ -68,7 +68,7 @@ namespace IPA.Loader.Features
/// </summary> /// </summary>
/// <param name="plugin">the plugin that was just initialized</param> /// <param name="plugin">the plugin that was just initialized</param>
/// <param name="pluginInstance">the instance of the plugin being initialized</param> /// <param name="pluginInstance">the instance of the plugin being initialized</param>
public virtual void AfterInit(PluginLoader.PluginInfo plugin, IBeatSaberPlugin pluginInstance) => AfterInit(plugin);
public virtual void AfterInit(PluginLoader.PluginInfo plugin, IPlugin pluginInstance) => AfterInit(plugin);
/// <summary> /// <summary>
/// Called after a plugin has been fully initialized, whether or not there is an `Init` method. This should never throw an exception. /// Called after a plugin has been fully initialized, whether or not there is an `Init` method. This should never throw an exception.


+ 7
- 0
IPA.Loader/Loader/LibLoader.cs View File

@ -7,16 +7,23 @@ using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Linq; using System.Linq;
using IPA.Logging; using IPA.Logging;
using IPA.Utilities;
using Mono.Cecil; using Mono.Cecil;
namespace IPA.Loader namespace IPA.Loader
{ {
internal class CecilLibLoader : BaseAssemblyResolver 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) public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{ {
LibLoader.SetupAssemblyFilenames(); LibLoader.SetupAssemblyFilenames();
if (name.Name == CurrentAssemblyName)
return AssemblyDefinition.ReadAssembly(CurrentAssemblyPath, parameters);
if (LibLoader.FilenameLocations.TryGetValue($"{name.Name}.{name.Version}.dll", out var path)) if (LibLoader.FilenameLocations.TryGetValue($"{name.Name}.{name.Version}.dll", out var path))
{ {
if (File.Exists(path)) if (File.Exists(path))


+ 2
- 0
IPA.Loader/Loader/PluginComponent.cs View File

@ -34,7 +34,9 @@ namespace IPA.Loader
gameObject.AddComponent<Updating.BeatMods.Updater>(); gameObject.AddComponent<Updating.BeatMods.Updater>();
#endif #endif
#pragma warning disable CS0612 // Type or member is obsolete
bsPlugins.OnApplicationStart(); bsPlugins.OnApplicationStart();
#pragma warning restore CS0612 // Type or member is obsolete
ipaPlugins.OnApplicationStart(); ipaPlugins.OnApplicationStart();
SceneManager.activeSceneChanged += OnActiveSceneChanged; SceneManager.activeSceneChanged += OnActiveSceneChanged;


+ 10
- 12
IPA.Loader/Loader/PluginLoader.cs View File

@ -124,7 +124,7 @@ namespace IPA.Loader
/// </summary> /// </summary>
public class PluginInfo public class PluginInfo
{ {
internal IBeatSaberPlugin Plugin { get; set; }
internal _IPlugin Plugin { get; set; }
/// <summary> /// <summary>
/// Metadata for the plugin. /// Metadata for the plugin.
@ -243,17 +243,14 @@ namespace IPA.Loader
{ {
if (type.Namespace != pluginNs) continue; 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) if (metadata.PluginType == null)
{ {
Logger.loader.Error($"No plugin found in the manifest namespace ({pluginNs}) in {Path.GetFileName(plugin)}"); 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 type = meta.Assembly.GetType(meta.PluginType.FullName);
var instance = (IBeatSaberPlugin)Activator.CreateInstance(type);
var instance = Activator.CreateInstance(type) as _IPlugin;
info.Metadata = meta; info.Metadata = meta;
info.Plugin = instance; info.Plugin = instance;
@ -668,17 +665,18 @@ namespace IPA.Loader
foreach (var feature in meta.Features) foreach (var feature in meta.Features)
try try
{ {
feature.AfterInit(info, info.Plugin);
// TODO: remove need for cast
feature.AfterInit(info, info.Plugin as IPlugin);
} }
catch (Exception e) catch (Exception e)
{ {
Logger.loader.Critical($"Feature errored in {nameof(Feature.AfterInit)}: {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 try // TODO: move this out to after all plugins have been inited
{ {
disable.OnEnable();
newPlugin.OnEnable();
} }
catch (Exception e) catch (Exception e)
{ {


+ 11
- 11
IPA.Loader/Loader/PluginManager.cs View File

@ -32,7 +32,7 @@ namespace IPA.Loader
/// <summary> /// <summary>
/// An <see cref="IEnumerable"/> of new Beat Saber plugins /// An <see cref="IEnumerable"/> of new Beat Saber plugins
/// </summary> /// </summary>
internal static IEnumerable<IBeatSaberPlugin> 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<PluginInfo> _bsPlugins; private static List<PluginInfo> _bsPlugins;
internal static IEnumerable<PluginInfo> BSMetas => _bsPlugins; internal static IEnumerable<PluginInfo> BSMetas => _bsPlugins;
@ -174,11 +174,11 @@ namespace IPA.Loader
var depsNeedRestart = plugin.Dependencies.Aggregate(false, (b, p) => EnablePlugin(p) || b); var depsNeedRestart = plugin.Dependencies.Aggregate(false, (b, p) => EnablePlugin(p) || b);
var runtimeInfo = runtimeDisabled.FirstOrDefault(p => p.Metadata == plugin); 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 try
{ {
disable.OnEnable();
newPlugin.OnEnable();
} }
catch (Exception e) catch (Exception e)
{ {
@ -290,8 +290,8 @@ namespace IPA.Loader
/// </summary> /// </summary>
/// <value>all legacy plugin instances</value> /// <value>all legacy plugin instances</value>
[Obsolete("I mean, IPlugin shouldn't be used, so why should this? Not renaming to extend support for old plugins.")] [Obsolete("I mean, IPlugin shouldn't be used, so why should this? Not renaming to extend support for old plugins.")]
public static IEnumerable<IPlugin> Plugins => _ipaPlugins;
private static List<IPlugin> _ipaPlugins;
public static IEnumerable<Old.IPlugin> Plugins => _ipaPlugins;
private static List<Old.IPlugin> _ipaPlugins;
internal static IConfigProvider SelfConfigProvider { get; set; } internal static IConfigProvider SelfConfigProvider { get; set; }
@ -303,7 +303,7 @@ namespace IPA.Loader
// so we need to resort to P/Invoke // so we need to resort to P/Invoke
string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath); string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);
_bsPlugins = new List<PluginInfo>(); _bsPlugins = new List<PluginInfo>();
_ipaPlugins = new List<IPlugin>();
_ipaPlugins = new List<Old.IPlugin>();
if (!Directory.Exists(pluginDirectory)) return; if (!Directory.Exists(pluginDirectory)) return;
@ -398,12 +398,12 @@ namespace IPA.Loader
Logger.log.Info("-----------------------------"); Logger.log.Info("-----------------------------");
} }
private static Tuple<IEnumerable<PluginInfo>, IEnumerable<IPlugin>> LoadPluginsFromFile(string file)
private static Tuple<IEnumerable<PluginInfo>, IEnumerable<Old.IPlugin>> LoadPluginsFromFile(string file)
{ {
List<IPlugin> ipaPlugins = new List<IPlugin>();
var ipaPlugins = new List<Old.IPlugin>();
if (!File.Exists(file) || !file.EndsWith(".dll", true, null)) if (!File.Exists(file) || !file.EndsWith(".dll", true, null))
return new Tuple<IEnumerable<PluginInfo>, IEnumerable<IPlugin>>(null, ipaPlugins);
return new Tuple<IEnumerable<PluginInfo>, IEnumerable<Old.IPlugin>>(null, ipaPlugins);
T OptionalGetPlugin<T>(Type t) where T : class T OptionalGetPlugin<T>(Type t) where T : class
{ {
@ -431,7 +431,7 @@ namespace IPA.Loader
foreach (Type t in assembly.GetTypes()) foreach (Type t in assembly.GetTypes())
{ {
IPlugin ipaPlugin = OptionalGetPlugin<IPlugin>(t);
var ipaPlugin = OptionalGetPlugin<Old.IPlugin>(t);
if (ipaPlugin != null) if (ipaPlugin != null)
{ {
ipaPlugins.Add(ipaPlugin); ipaPlugins.Add(ipaPlugin);
@ -450,7 +450,7 @@ namespace IPA.Loader
Logger.loader.Error(e); Logger.loader.Error(e);
} }
return new Tuple<IEnumerable<PluginInfo>, IEnumerable<IPlugin>>(null, ipaPlugins);
return new Tuple<IEnumerable<PluginInfo>, IEnumerable<Old.IPlugin>>(null, ipaPlugins);
} }
internal static class AppInfo internal static class AppInfo


+ 4
- 38
IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs View File

@ -1,4 +1,4 @@
using UnityEngine.SceneManagement;
using System;
// ReSharper disable CheckNamespace // ReSharper disable CheckNamespace
namespace IPA 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 /// Interface for Beat Saber plugins. Every class that implements this will be loaded if the DLL is placed at
/// data/Managed/Plugins. /// data/Managed/Plugins.
/// </summary> /// </summary>
public interface IBeatSaberPlugin
[Obsolete("Use IPA.IPlugin instead")]
public interface IBeatSaberPlugin : _IPlugin
{ {
/// <summary> /// <summary>
/// Gets invoked when the application is started. /// Gets invoked when the application is started.
/// ///
/// THIS EVENT WILL NOT BE GUARANTEED TO FIRE. USE Init OR <see cref="IDisablablePlugin.OnEnable"/> INSTEAD.
/// THIS EVENT WILL NOT BE GUARANTEED TO FIRE. USE Init OR <see cref="IPlugin.OnEnable"/> INSTEAD.
/// </summary> /// </summary>
void OnApplicationStart(); void OnApplicationStart();
/// <summary>
/// Gets invoked when the application is closed.
/// </summary>
void OnApplicationQuit();
/// <summary>
/// Gets invoked on every graphic update.
/// </summary>
void OnUpdate();
/// <summary>
/// Gets invoked on ever physics update.
/// </summary>
void OnFixedUpdate();
/// <summary>
/// Gets invoked whenever a scene is loaded.
/// </summary>
/// <param name="scene">The scene currently loaded</param>
/// <param name="sceneMode">The type of loading</param>
void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode);
/// <summary>
/// Gets invoked whenever a scene is unloaded
/// </summary>
/// <param name="scene">The unloaded scene</param>
void OnSceneUnloaded(Scene scene);
/// <summary>
/// Gets invoked whenever a scene is changed
/// </summary>
/// <param name="prevScene">The Scene that was previously loaded</param>
/// <param name="nextScene">The Scene being loaded</param>
void OnActiveSceneChanged(Scene prevScene, Scene nextScene);
} }
} }

+ 3
- 3
IPA.Loader/PluginInterfaces/BeatSaber/IDisablablePlugin.cs View File

@ -5,7 +5,7 @@
/// </summary> /// </summary>
public interface IDisablablePlugin public interface IDisablablePlugin
{ {
/// <summary>
/*/// <summary>
/// Called when a plugin is enabled. This is where you should set up Harmony patches and the like. /// Called when a plugin is enabled. This is where you should set up Harmony patches and the like.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
@ -14,14 +14,14 @@
/// ///
/// Init will only ever be called once. /// Init will only ever be called once.
/// </remarks> /// </remarks>
void OnEnable();
void OnEnable();*/
/// <summary> /// <summary>
/// Called when a plugin is disabled at runtime. This should disable things like Harmony patches and unsubscribe /// 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. /// from events. After this is called there should be no lingering effects of the mod.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This will get called at shutdown, after <see cref="IBeatSaberPlugin.OnApplicationQuit"/>, as well as when the
/// This will get called at shutdown, after <see cref="_IPlugin.OnApplicationQuit"/>, as well as when the
/// plugin is disabled at runtime. /// plugin is disabled at runtime.
/// </remarks> /// </remarks>
void OnDisable(); void OnDisable();


+ 1
- 0
IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs View File

@ -5,6 +5,7 @@ namespace IPA
/// <summary> /// <summary>
/// An enhanced version of a standard BeatSaber plugin. /// An enhanced version of a standard BeatSaber plugin.
/// </summary> /// </summary>
[System.Obsolete]
public interface IEnhancedBeatSaberPlugin : IBeatSaberPlugin, IGenericEnhancedPlugin public interface IEnhancedBeatSaberPlugin : IBeatSaberPlugin, IGenericEnhancedPlugin
{ {
} }


+ 16
- 0
IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedPlugin.cs View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA
{
/// <inheritdoc cref="IPlugin" />
/// <summary>
/// An enhanced version of a standard BeatSaber plugin.
/// </summary>
public interface IEnhancedPlugin : IPlugin, IGenericEnhancedPlugin
{
}
}

+ 61
- 0
IPA.Loader/PluginInterfaces/BeatSaber/IPlugin.cs View File

@ -0,0 +1,61 @@
using UnityEngine.SceneManagement;
namespace IPA
{
/// <summary>
/// Interface for BSIPA plugins. Every class that implements this will be loaded if the DLL is placed at
/// &lt;install dir&gt;/Plugins.
/// </summary>
public interface IPlugin : _IPlugin
{
/// <summary>
/// Called when a plugin is enabled. This is where you should set up Harmony patches and the like.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
void OnEnable();
}
/// <summary>
/// An interface for providing compatability with BSIPA 3.x.x. Do not use.
/// </summary>
public interface _IPlugin {
/// <summary>
/// Gets invoked when the application is closed.
/// </summary>
void OnApplicationQuit();
/// <summary>
/// Gets invoked on every graphic update.
/// </summary>
void OnUpdate();
/// <summary>
/// Gets invoked on ever physics update.
/// </summary>
void OnFixedUpdate();
/// <summary>
/// Gets invoked whenever a scene is loaded.
/// </summary>
/// <param name="scene">The scene currently loaded</param>
/// <param name="sceneMode">The type of loading</param>
void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode);
/// <summary>
/// Gets invoked whenever a scene is unloaded
/// </summary>
/// <param name="scene">The unloaded scene</param>
void OnSceneUnloaded(Scene scene);
/// <summary>
/// Gets invoked whenever a scene is changed
/// </summary>
/// <param name="prevScene">The Scene that was previously loaded</param>
/// <param name="nextScene">The Scene being loaded</param>
void OnActiveSceneChanged(Scene prevScene, Scene nextScene);
}
}

+ 6
- 0
IPA.Loader/Utilities/Utils.cs View File

@ -3,6 +3,7 @@ using System.IO;
using System.Text; using System.Text;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using Mono.Cecil;
#if NET3 #if NET3
using File = Net3_Proxy.File; using File = Net3_Proxy.File;
#endif #endif
@ -187,6 +188,11 @@ namespace IPA.Utilities
cmpVal = l.Patch - r.Patch; cmpVal = l.Patch - r.Patch;
return cmpVal; 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 #if NET4
internal static IEnumerable<string> StrJP(this IEnumerable<string> a) => a; internal static IEnumerable<string> StrJP(this IEnumerable<string> a) => a;


BIN
Refs/Assembly-CSharp.dll View File


BIN
Refs/Unity.TextMeshPro.dll View File


BIN
Refs/UnityEngine.CoreModule.Net4.dll View File


Loading…
Cancel
Save