/// <summary> /// Returns the PluginMetadata of a provided BSIPA plugin /// </summary> public static PluginLoader.PluginMetadata GetPluginMetadata(IBeatSaberPlugin plugin) { foreach (PluginLoader.PluginInfo pluginInfo in PluginManager.AllPlugins) { if (pluginInfo != null && plugin == pluginInfo.GetPrivateProperty <IBeatSaberPlugin>("Plugin")) { return(pluginInfo.Metadata ?? null); } } return(null); }
/// <summary> /// Called after a plugin has been fully initialized, whether or not there is an `Init` method. This should never throw an exception. /// </summary> /// <param name="plugin">the plugin that was just initialized</param> /// <param name="pluginInstance">the instance of the plugin being initialized</param> public virtual void AfterInit(PluginLoader.PluginInfo plugin, IBeatSaberPlugin pluginInstance) => AfterInit(plugin);
/// <summary> /// Gets the ModPrefs object for the provided plugin. /// </summary> /// <param name="plugin">the plugin wanting the prefrences</param> /// <returns>the ModPrefs object</returns> public static IModPrefs GetModPrefs(this IBeatSaberPlugin plugin) { return(ModPrefs.ModPrefses.First(o => o.Key == plugin).Value); }
/// <summary> /// Constructs a ModPrefs object for the provide plugin. /// </summary> /// <param name="plugin">the plugin to get the preferences file for</param> public ModPrefs(IBeatSaberPlugin plugin) { Instance = new IniFile(Path.Combine(Environment.CurrentDirectory, "UserData", "ModPrefs", $"{plugin.Name}.ini")); ModPrefses.Add(plugin, this); }
private static Tuple <IEnumerable <BSPluginMeta>, IEnumerable <IPlugin> > LoadPluginsFromFile(string file, string exeName) { List <BSPluginMeta> bsPlugins = new List <BSPluginMeta>(); List <IPlugin> ipaPlugins = new List <IPlugin>(); if (!File.Exists(file) || !file.EndsWith(".dll", true, null)) { return(new Tuple <IEnumerable <BSPluginMeta>, 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) { Logger.log.Error($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}"); } } return(null); } try { Assembly assembly = Assembly.LoadFrom(file); foreach (Type t in assembly.GetTypes()) { IBeatSaberPlugin bsPlugin = OptionalGetPlugin <IBeatSaberPlugin>(t); if (bsPlugin != null) { try { var init = t.GetMethod("Init", BindingFlags.Instance | BindingFlags.Public); if (init != null) { var initArgs = new List <object>(); var initParams = init.GetParameters(); LoggerBase modLogger = null; IModPrefs modPrefs = null; foreach (var param in initParams) { var ptype = param.ParameterType; if (ptype.IsAssignableFrom(typeof(LoggerBase))) { if (modLogger == null) { modLogger = new StandardLogger(bsPlugin.Name); } initArgs.Add(modLogger); } else if (ptype.IsAssignableFrom(typeof(IModPrefs))) { if (modPrefs == null) { modPrefs = new ModPrefs(bsPlugin); } initArgs.Add(modPrefs); } else { initArgs.Add(ptype.GetDefault()); } } init.Invoke(bsPlugin, initArgs.ToArray()); } bsPlugins.Add(new BSPluginMeta { Plugin = bsPlugin, Filename = file.Replace("\\.cache", ""), // quick and dirty fix ModsaberInfo = bsPlugin.ModInfo }); } catch (AmbiguousMatchException) { Logger.log.Error($"Only one Init allowed per plugin"); } } else { IPlugin ipaPlugin = OptionalGetPlugin <IPlugin>(t); if (ipaPlugin != null) { ipaPlugins.Add(ipaPlugin); } } } } catch (Exception e) { Logger.log.Error($"Could not load {Path.GetFileName(file)}! {e}"); } return(new Tuple <IEnumerable <BSPluginMeta>, IEnumerable <IPlugin> >(bsPlugins, ipaPlugins)); }
private static bool LoadAssembly(Type[] types, string filename) { var asm = types.First().Assembly; Logger.log.SuperVerbose($"Checking for plugins in {asm.GetName().Name}"); List <Tuple <Type, BeatSaberPluginAttribute> > modTypes = new List <Tuple <Type, BeatSaberPluginAttribute> >(); foreach (var type in types) { Logger.log.SuperVerbose($"Checking {type.FullName}"); if (type.IsDefined(typeof(BeatSaberPluginAttribute), false)) { // marked a plugin, but is it actually? Logger.log.SuperVerbose($"Found attribute on {type.FullName}"); if (type.GetInterfaces().Contains(typeof(IBeatSaberPlugin))) { // also actually a plugin! great! Logger.log.SuperVerbose($"Found plugin {type.FullName}"); modTypes.Add(new Tuple <Type, BeatSaberPluginAttribute>(type, type.GetCustomAttribute <BeatSaberPluginAttribute>())); } } } if (modTypes.Count == 0) { //Logger.log.Warn($"Assembly {asm.GetName().Name} has the BeatSaberModule attribute, but defines no mods!"); return(false); } string commonPrefix = modTypes.Select(t => t.Item1.FullName).FindCommonPrefix(); int pluginsLoaded = 0; foreach (var type in modTypes) { string pluginFullName = $"{asm.GetName().Name}/{type.Item1.FullName.Replace(commonPrefix, "")}"; string finalName = modTypes.Count == 1 ? asm.GetName().Name : pluginFullName; finalName = type.Item2.Name ?? finalName; try { Logger.log.SuperVerbose($"Instantiating {finalName} ({type.Item1.FullName})"); IBeatSaberPlugin plugin = Activator.CreateInstance(type.Item1) as IBeatSaberPlugin; LoggerBase logger = Logger.CreateLogger(finalName); Logger.log.SuperVerbose($"Initializing {finalName}"); plugin.Init(logger); plugins.Add(new PluginObject { FileName = filename, Name = finalName, Plugin = plugin, Meta = type.Item2 }); pluginsLoaded++; } catch (Exception e) { Logger.log.Error($"Cannot initialize plugin {finalName}"); Logger.log.Debug(e); } } Logger.log.SuperVerbose($"Plugins loaded from {asm.GetName().Name}: {pluginsLoaded}"); if (pluginsLoaded == 0) { Logger.log.Error($"No plugins could be loaded from {asm.GetName().Name}."); return(false); } return(true); }