Пример #1
0
        /// <summary>
        /// Find and load all ModBases in the given assembly.
        /// </summary>
        /// <param name="meta">The mod metadata, preferably from the mod metadata.yaml file.</param>
        /// <param name="asm">The mod assembly, preferably relinked.</param>
        public static void LoadModAssembly(ModMetadata meta, Assembly asm)
        {
            if (meta != null)
            {
                ModContentManager.Crawl(new AssemblyModContent(asm));
            }

            Type[] types;
            try {
                types = asm.GetTypes();
            } catch (Exception e) {
                Logger.Log(LogLevel.Warn, "loader", $"Failed reading assembly: {e}");
                e.LogDetailed();
                return;
            }
            for (int i = 0; i < types.Length; i++)
            {
                Type type = types[i];
                if (!typeof(ModBase).IsAssignableFrom(type) || type.IsAbstract)
                {
                    continue;
                }

                ModBase mod = (ModBase)type.GetConstructor(ModManager._EmptyTypeArray).Invoke(ModManager._EmptyObjectArray);
                if (meta != null)
                {
                    mod.Metadata = meta;
                }
                mod.Register();
            }
        }
Пример #2
0
        /// <summary>
        /// Unregisters an already registered ModBase (mod) dynamically. Invokes Unload.
        /// </summary>
        /// <param name="module"></param>
        public static void Unregister(this ModBase module)
        {
            module.Unload();

            lock (_Mods) {
                int index = _Mods.IndexOf(module);
                _Mods.RemoveAt(index);
                _ModuleTypes.RemoveAt(index);
                _ModuleMethods.RemoveAt(index);
            }

            Logger.Log(LogLevel.Info, "core", $"Module {module.Metadata} unregistered.");
        }
Пример #3
0
        public static void Boot(string name, string version, ModBase coreModule)
        {
            if (_Booted)
            {
                return;
            }
            _Booted = true;

            Name          = name;
            VersionString = version;

            Logger.Log(LogLevel.Info, "core", $"Booting {name}");
            Logger.Log(LogLevel.Info, "core", $"Version: {VersionString}");

            if (string.IsNullOrEmpty(PathGame))
            {
                PathGame = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
            }
            if (string.IsNullOrEmpty(PathSettings))
            {
                PathSettings = Path.Combine(PathGame, "ModSettings");
            }
            Directory.CreateDirectory(PathSettings);

            // Automatically load all modules.
            if (coreModule != null)
            {
                coreModule.Metadata = coreModule.Metadata ?? new ModMetadata {
                    Name    = Name,
                    Version = Version
                };
                Register(coreModule);
            }
            ModLoader.LoadAuto();

            // Also let all mods parse the arguments.
            Queue <string> args = new Queue <string>(Args);

            while (args.Count > 0)
            {
                string arg = args.Dequeue();
                foreach (ModBase mod in Mods)
                {
                    if (mod.ParseArg(arg, args))
                    {
                        break;
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Register a new ModBase (mod) dynamically. Invokes LoadSettings and Load.
        /// </summary>
        /// <param name="module">Mod to register.</param>
        public static void Register(this ModBase module)
        {
            lock (_Mods) {
                _Mods.Add(module);
                _ModuleTypes.Add(module.GetType());
                _ModuleMethods.Add(new Dictionary <string, MethodInfo>());
                _ModuleMethodDelegates.Add(new Dictionary <string, FastReflectionDelegate>());
            }

            module.LoadSettings();
            module.Load();

            Logger.Log(LogLevel.Info, "core", $"Module {module.Metadata} registered.");

            // Attempt to load mods after their dependencies have been loaded.
            // Only load and lock the delayed list if we're not already loading delayed mods.
            if (Interlocked.CompareExchange(ref ModLoader.DelayedLock, 1, 0) == 0)
            {
                lock (ModLoader.Delayed) {
                    for (int i = ModLoader.Delayed.Count - 1; i > -1; i--)
                    {
                        ModLoader.DelayedEntry entry = ModLoader.Delayed[i];
                        if (!ModLoader.DependenciesLoaded(entry.Meta))
                        {
                            continue;
                        }

                        ModLoader.LoadMod(entry.Meta);
                        ModLoader.Delayed.RemoveAt(i);

                        entry.Callback?.Invoke();
                    }
                }
                Interlocked.Decrement(ref ModLoader.DelayedLock);
            }
        }
Пример #5
0
        /// <summary>
        /// Invoke a method in all loaded ModBases.
        /// </summary>
        /// <param name="methodName">The name of the method.</param>
        /// <param name="argsTypes">The types of the arguments passed to the methods.</param>
        /// <param name="args">Any arguments to be passed to the methods.</param>
        public static void InvokeTyped(string methodName, Type[] argsTypes, params object[] args)
        {
            if (args == null)
            {
                args = _EmptyObjectArray;
                if (argsTypes == null)
                {
                    argsTypes = _EmptyTypeArray;
                }
            }
            else if (argsTypes == null)
            {
                argsTypes = Type.GetTypeArray(args);
            }

            if (!Debugger.IsAttached)
            {
                // Fast codepath: DynamicMethodDelegate
                // Unfortunately prevents us from stepping into invoked methods.
                for (int i = 0; i < _Mods.Count; i++)
                {
                    ModBase module = _Mods[i];
                    IDictionary <string, FastReflectionDelegate> moduleMethods = _ModuleMethodDelegates[i];
                    FastReflectionDelegate method;

                    if (moduleMethods.TryGetValue(methodName, out method))
                    {
                        if (method == null)
                        {
                            continue;
                        }
                        method(module, args);
                        continue;
                    }

                    MethodInfo methodInfo = _ModuleTypes[i].GetMethod(methodName, argsTypes);
                    if (methodInfo != null)
                    {
                        method = methodInfo.GetFastDelegate();
                    }
                    moduleMethods[methodName] = method;
                    if (method == null)
                    {
                        continue;
                    }

                    method(module, args);
                }
            }
            else
            {
                // Slow codepath: MethodInfo.Invoke
                // Doesn't hinder us from stepping into the invoked methods.
                for (int i = 0; i < _Mods.Count; i++)
                {
                    ModBase module = _Mods[i];
                    IDictionary <string, MethodInfo> moduleMethods = _ModuleMethods[i];
                    MethodInfo methodInfo;

                    if (moduleMethods.TryGetValue(methodName, out methodInfo))
                    {
                        if (methodInfo == null)
                        {
                            continue;
                        }
                        methodInfo.Invoke(module, args);
                        continue;
                    }

                    methodInfo = _ModuleTypes[i].GetMethod(methodName, argsTypes);
                    moduleMethods[methodName] = methodInfo;
                    if (methodInfo == null)
                    {
                        continue;
                    }

                    methodInfo.Invoke(module, args);
                }
            }
        }