// 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)
            {
                Tools.NotifyAllPlayers("<Server> Reloading plugin " + Name + ", you may experience lag...", Color.White, true);

                var signal = new ManualResetEvent(false);

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

                            Tools.WriteLine("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)
                            {
                                Tools.WriteLine("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))
                                    {
                                        //								Tools.WriteLine ("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;
                                    Tools.WriteLine("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)
                            {
                                Tools.WriteLine("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);
                                    }
                                }
                            }

                            Tools.WriteLine("Disabling old plugin instance...");
                            Disable();

                            Tools.WriteLine("Enabling new plugin instance...");
                            if (newPlugin.Enable())
                            {
                                result = true;
                            }
                        }
                    }
                    finally
                    {
                        Tools.NotifyAllPlayers("<Server> Done.", Color.White, true);

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

            return(result);
        }
Example #2
0
 internal protected abstract void Unhook(BasePlugin plugin);
Example #3
0
 internal abstract void Replace(BasePlugin oldPlugin, BasePlugin newPlugin, Delegate callback, HookOrder order);
Example #4
0
 internal protected abstract void HookBase(BasePlugin plugin, Delegate callback, HookOrder order = HookOrder.NORMAL);