示例#1
0
        // newPlugin should not have been initialized at this point!
        internal bool ReplaceWith(BasePlugin newPlugin, bool saveState = true)
        {
            var    result     = false;
            var    noreturn   = false;
            var    paused     = new LinkedList <HookPoint> ();
            object savedState = null;

            lock (HookPoint.editLock)
            {
                Server.notifyAll("<Server> Reloading plugin " + Name + ", you may experience lag...", Misc.ChatColor.White, true);

                var signal = new ManualResetEvent(false);

                lock (HookPoint.editLock) try
                    {
                        using (this.Pause())
                        {
                            // initialize new instance with saved state
                            if (saveState)
                            {
                                savedState = Suspend();
                            }

                            ProgramLog.Debug.Log("Initializing new plugin instance...");
                            if (!newPlugin.Initialize(savedState))
                            {
                                if (saveState)
                                {
                                    Resume(savedState);
                                }
                                return(false);
                            }

                            // point of no return, if the new plugin fails now,
                            // blame the author
                            // because it's time to dispose the old plugin
                            noreturn = true;

                            // use command objects from the old plugin, because command invocations
                            // may be paused inside them, this way when they unpause
                            // they run the new plugin's methods
                            lock (commands)
                            {
                                ProgramLog.Debug.Log("Replacing commands...");

                                var prefixes = newPlugin.commands.Keys.ToArray();

                                var done = new HashSet <CommandInfo> ();

                                foreach (var prefix in prefixes)
                                {
                                    CommandInfo oldCmd;
                                    if (commands.TryGetValue(prefix, out oldCmd))
                                    {
                                        //								ProgramLog.Debug.Log ("Replacing command {0}.", prefix);
                                        var newCmd = newPlugin.commands[prefix];

                                        newPlugin.commands[prefix] = oldCmd;
                                        commands.Remove(prefix);

                                        if (done.Contains(oldCmd))
                                        {
                                            continue;
                                        }

                                        oldCmd.InitFrom(newCmd);
                                        done.Add(oldCmd);

                                        oldCmd.AfterEvent  += newPlugin.NotifyAfterCommand;
                                        oldCmd.BeforeEvent += newPlugin.NotifyBeforeCommand;

                                        // garbage
                                        newCmd.ClearCallbacks();
                                        newCmd.ClearEvents();
                                    }
                                }

                                foreach (var kv in commands)
                                {
                                    var cmd = kv.Value;
                                    ProgramLog.Debug.Log("Clearing command {0}.", kv.Key);
                                    cmd.ClearCallbacks();
                                }
                                commands.Clear();
                            }

                            // replace hook subscriptions from the old plugin with new ones
                            // in the exact same spots in the invocation chains
                            lock (newPlugin.desiredHooks)
                            {
                                ProgramLog.Debug.Log("Replacing hooks...");

                                foreach (var h in newPlugin.desiredHooks)
                                {
                                    if (hooks.Contains(h.hookPoint))
                                    {
                                        h.hookPoint.Replace(this, newPlugin, h.callback, h.order);
                                        hooks.Remove(h.hookPoint);
                                        newPlugin.hooks.Add(h.hookPoint);
                                    }
                                    else
                                    {
                                        // this adds the hook to newPlugin.hooks
                                        h.hookPoint.HookBase(newPlugin, h.callback, h.order);
                                    }
                                }
                            }

                            ProgramLog.Debug.Log("Disabling old plugin instance...");
                            Disable();

                            ProgramLog.Debug.Log("Enabling new plugin instance...");
                            if (newPlugin.Enable())
                            {
                                result = true;
                            }
                        }
                    }
                    finally
                    {
                        Server.notifyAll("<Server> Done.", Misc.ChatColor.White, true);

                        // clean up remaining hooks
                        if (noreturn)
                        {
                            ProgramLog.Debug.Log("Disposing of old plugin instance...");
                            Dispose();
                        }
                    }
            }

            return(result);
        }
        public static void PluginCommand(ISender sender, ArgumentList args)
        {
            /*
             * Commands:
             *      list    - shows all plugins
             *      info    - shows a plugin's author & description etc
             *      disable - disables a plugin
             *      enable  - enables a plugin
             *      reload
             *      unload
             *      status
             *      load
             */

            if (args.Count == 0)
            {
                throw new CommandError("Subcommand expected.");
            }

            string command = args[0];

            args.RemoveAt(0);             //Allow the commands to use any additional arguments without also getting the command

            lock (plugins)
                switch (command)
                {
                case "-l":
                case "ls":
                case "list":
                {
                    if (PluginCount == 0)
                    {
                        sender.Message(255, "No plugins loaded.");
                        return;
                    }

                    var msg = new StringBuilder();
                    msg.Append("Plugins: ");

                    int i = 0;
                    foreach (var plugin in EnumeratePlugins)
                    {
                        if (i > 0)
                        {
                            msg.Append(", ");
                        }
                        msg.Append(plugin.Name);
                        if (!plugin.IsEnabled)
                        {
                            msg.Append("[OFF]");
                        }
                        i++;
                    }
                    msg.Append(".");

                    sender.Message(255, ChatColor.DodgerBlue, msg.ToString());

                    break;
                }

                case "-s":
                case "stat":
                case "status":
                {
                    if (PluginCount == 0)
                    {
                        sender.Message(255, "No plugins loaded.");
                        return;
                    }

                    var msg = new StringBuilder();

                    foreach (var plugin in EnumeratePlugins)
                    {
                        msg.Clear();
                        msg.Append(plugin.IsDisposed ? "[DISPOSED] " : (plugin.IsEnabled ? "[ON]  " : "[OFF] "));
                        msg.Append(plugin.Name);
                        msg.Append(" ");
                        msg.Append(plugin.Version);
                        if (plugin.Status != null && plugin.Status.Length > 0)
                        {
                            msg.Append(" : ");
                            msg.Append(plugin.Status);
                        }
                        sender.Message(255, ChatColor.DodgerBlue, msg.ToString());
                    }

                    break;
                }

                case "-i":
                case "info":
                {
                    string name;
                    args.ParseOne(out name);

                    var fplugin = GetPlugin(name);
                    if (fplugin != null)
                    {
                        var path = Path.GetFileName(fplugin.Path);
                        sender.Message(255, ChatColor.DodgerBlue, fplugin.Name);
                        sender.Message(255, ChatColor.DodgerBlue, "Filename: " + path);
                        sender.Message(255, ChatColor.DodgerBlue, "Version:  " + fplugin.Version);
                        sender.Message(255, ChatColor.DodgerBlue, "Author:   " + fplugin.Author);
                        if (fplugin.Description != null && fplugin.Description.Length > 0)
                        {
                            sender.Message(255, ChatColor.DodgerBlue, fplugin.Description);
                        }
                        sender.Message(255, ChatColor.DodgerBlue, "Status:   " + (fplugin.IsEnabled ? "[ON] " : "[OFF] ") + fplugin.Status);
                    }
                    else
                    {
                        sender.sendMessage("The plugin \"" + args[1] + "\" was not found.");
                    }

                    break;
                }

                case "-d":
                case "disable":
                {
                    string name;
                    args.ParseOne(out name);

                    var fplugin = GetPlugin(name);
                    if (fplugin != null)
                    {
                        if (fplugin.Disable())
                        {
                            sender.Message(255, ChatColor.DodgerBlue, fplugin.Name + " was disabled.");
                        }
                        else
                        {
                            sender.Message(255, ChatColor.DodgerBlue, fplugin.Name + " was disabled, errors occured during the process.");
                        }
                    }
                    else
                    {
                        sender.Message(255, "The plugin \"" + name + "\" could not be found.");
                    }

                    break;
                }

                case "-e":
                case "enable":
                {
                    string name;
                    args.ParseOne(out name);

                    var fplugin = GetPlugin(name);
                    if (fplugin != null)
                    {
                        if (fplugin.Enable())
                        {
                            sender.Message(255, ChatColor.DodgerBlue, fplugin.Name + " was enabled.");
                        }
                        else
                        {
                            sender.Message(255, ChatColor.DodgerBlue, fplugin.Name + " was enabled, errors occured during the process.");
                        }
                    }
                    else
                    {
                        sender.Message(255, "The plugin \"" + name + "\" could not be found.");
                    }

                    break;
                }

                case "-u":
                case "-ua":
                case "unload":
                {
                    string name;

                    if (command == "-ua" || command == "-uca")
                    {
                        name = "all";
                    }
                    else
                    {
                        args.ParseOne(out name);
                    }

                    BasePlugin[] plugs;
                    if (name == "all" || name == "-a")
                    {
                        plugs = plugins.Values.ToArray();
                    }
                    else
                    {
                        var splugin = PluginManager.GetPlugin(name);

                        if (splugin == null)
                        {
                            sender.Message(255, "The plugin \"" + name + "\" could not be found.");
                            return;
                        }

                        plugs = new BasePlugin [] { splugin };
                    }

                    foreach (var fplugin in plugs)
                    {
                        if (UnloadPlugin(fplugin))
                        {
                            sender.Message(255, ChatColor.DodgerBlue, fplugin.Name + " was unloaded.");
                        }
                        else
                        {
                            sender.Message(255, ChatColor.DodgerBlue, fplugin.Name + " was unloaded, errors occured during the process.");
                        }
                    }

                    break;
                }

                case "-r":
                case "-rc":
                case "-ra":
                case "-rca":
                case "reload":
                {
                    bool save = true;
                    if (command == "-rc" || command == "-rca" || args.TryPop("-c") || args.TryPop("-clean"))
                    {
                        save = false;
                    }

                    string name;

                    if (command == "-ra" || command == "-rca")
                    {
                        name = "all";
                    }
                    else
                    {
                        args.ParseOne(out name);
                    }

                    BasePlugin[] plugs;
                    if (name == "all" || name == "-a")
                    {
                        plugs = plugins.Values.ToArray();
                    }
                    else
                    {
                        var splugin = PluginManager.GetPlugin(name);

                        if (splugin == null)
                        {
                            sender.Message(255, "The plugin \"" + name + "\" could not be found.");
                            return;
                        }

                        plugs = new BasePlugin [] { splugin };
                    }

                    foreach (var fplugin in plugs)
                    {
                        var nplugin = PluginManager.ReloadPlugin(fplugin, save);
                        if (nplugin == fplugin)
                        {
                            sender.Message(255, ChatColor.DodgerBlue, "Errors occured while reloading plugin " + fplugin.Name + ", old instance kept.");
                        }
                        else if (nplugin == null)
                        {
                            sender.Message(255, ChatColor.DodgerBlue, "Errors occured while reloading plugin " + fplugin.Name + ", it has been unloaded.");
                        }
                    }

                    break;
                }

                case "-L":
                case "-LR":
                case "load":
                {
                    bool replace = command == "-LR" || args.TryPop("-R") || args.TryPop("-replace");
                    bool save    = command != "-LRc" && !args.TryPop("-c") && !args.TryPop("-clean");

                    var    fname = string.Join(" ", args);
                    string path;

                    if (fname == "")
                    {
                        throw new CommandError("File name expected");
                    }

                    if (Path.IsPathRooted(fname))
                    {
                        path = Path.GetFullPath(fname);
                    }
                    else
                    {
                        path = Path.Combine(pluginPath, fname);
                    }

                    var fi = new FileInfo(path);

                    if (!fi.Exists)
                    {
                        sender.Message(255, "Specified file doesn't exist.");
                        return;
                    }

                    var newPlugin = LoadPluginFromPath(path);

                    if (newPlugin == null)
                    {
                        sender.Message(255, "Unable to load plugin.");
                        return;
                    }

                    var oldPlugin = GetPlugin(newPlugin.Name);
                    if (oldPlugin != null)
                    {
                        if (!replace)
                        {
                            sender.Message(255, "A plugin named {0} is already loaded, use -replace to replace it.", oldPlugin.Name);
                            return;
                        }

                        if (ReplacePlugin(oldPlugin, newPlugin, save))
                        {
                            sender.Message(255, ChatColor.DodgerBlue, "Plugin {0} has been replaced.", oldPlugin.Name);
                        }
                        else if (oldPlugin.IsDisposed)
                        {
                            sender.Message(255, ChatColor.DodgerBlue, "Replacement of plugin {0} failed, it has been unloaded.", oldPlugin.Name);
                        }
                        else
                        {
                            sender.Message(255, ChatColor.DodgerBlue, "Replacement of plugin {0} failed, old instance kept.", oldPlugin.Name);
                        }

                        return;
                    }

                    if (!newPlugin.InitializeAndHookUp())
                    {
                        sender.Message(255, ChatColor.DodgerBlue, "Failed to initialize new plugin instance.");
                    }

                    plugins.Add(newPlugin.Name.ToLower().Trim(), newPlugin);

                    if (!newPlugin.Enable())
                    {
                        sender.Message(255, ChatColor.DodgerBlue, "Failed to enable new plugin instance.");
                    }

                    break;
                }

                default:
                {
                    throw new CommandError("Subcommand not recognized.");
                }
                }
        }
 internal protected abstract void Unhook(BasePlugin plugin);
 internal abstract void Replace(BasePlugin oldPlugin, BasePlugin newPlugin, Delegate callback, HookOrder order);
 internal protected abstract void HookBase(BasePlugin plugin, Delegate callback, HookOrder order = HookOrder.NORMAL);