/// <summary> /// Call a specified hook on every plugin /// </summary> /// <param name="name">Hook name</param> /// <param name="args"></param> /// <returns></returns> public static object Call(string name, params object[] args) { try { object result = null; var results = PoolNew <List <HookResult> > .Get(); var conflicts = PoolNew <List <HookResult> > .Get(); for (var i = 0; i < Plugins.Count; i++) { var plugin = Plugins[i]; var currentResult = new HookResult(plugin, plugin.IsLoaded ? plugin.Call(name, args) : null); results.Add(currentResult); if (currentResult.Value != null) { result = currentResult.Value; } } for (var i = 0; i < Plugins.Count - 1; i++) { for (var j = i + 1; j < Plugins.Count; j++) { var result1 = results[i]; var result2 = results[j]; if (result1.Value == null || result2.Value == null || result1.Value.Equals(result2.Value)) { continue; } conflicts.Add(result1); conflicts.Add(result2); } } if (conflicts.Count <= 0) { return(result); } Log.Warning($"Calling hook '{name}' resulted in a conflict between the following plugins: {string.Join(", ", conflicts.Distinct())}"); return(null); } catch (Exception e) { Log.Exception(e); } return(null); }
/// <summary> /// Initialize a plugin /// </summary> /// <param name="path">Plugin path</param> /// <param name="isUnloadable">Whether the plugin is unloadable</param> internal void Initialize(string path, bool isUnloadable) { var type = GetType(); Path = path; Filename = System.IO.Path.GetFileName(path); Name = type.Name; Title = type.Name; Author = "Unknown"; Version = new Version(1, 0, 0); IsCorePlugin = string.IsNullOrEmpty(Path); IsUnloadable = isUnloadable; var info = type.GetCustomAttribute <InfoAttribute>(); if (info != null) { Title = info.Title; Author = info.Author; Version = info.Version; } var description = type.GetCustomAttribute <DescriptionAttribute>(); if (description != null) { Description = description.Description; } var typeList = PoolNew <List <Type> > .Get(); typeList.Add(type); while (type != typeof(Plugin)) { typeList.Add(type = type?.BaseType); } var typeCount = typeList.Count; for (var i = 0; i < typeCount; i++) { type = typeList[i]; var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var methodsCount = methods.Length; for (var j = 0; j < methodsCount; j++) { var method = methods[j]; if (method.GetCustomAttribute <HookMethodAttribute>(false) is HookMethodAttribute hookMethodAttribute) { AddHookMethod(hookMethodAttribute.Name, method); } if (method.GetCustomAttribute <CommandAttribute>(false) is CommandAttribute commandAttribute) { AddCommand(commandAttribute.Name, method); } } var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var fieldsCount = fields.Length; for (var j = 0; j < fieldsCount; j++) { var field = fields[j]; if (field.GetCustomAttribute <DependencyAttribute>(false) is DependencyAttribute dependencyAttribute) { AddDependency(dependencyAttribute.Name, field); } } } Interface.Plugins.Add(this); Interface.UpdateDependencies(); Interface.Load(Name); }
/// <summary> /// Build command argument instance from string entry /// </summary> /// <param name="entry">Input for building command argument</param> /// <returns>Built command argument</returns> public static CommandArgument Build(string entry) { var instance = PoolNew <CommandArgument> .Get(); return(instance.BuildCommand(entry)); }