コード例 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SynServerTool" /> main class.
        /// </summary>
        /// <param name="isRestart">if set to <c>true</c> then the application was
        /// launched for the process of restarting previous monitoring.</param>
        /// <remarks>
        /// Some notes/thoughts: All of the core functions of the bot including console text
        /// processing, player/server event processing, modules, command processing, vote
        /// management, parsing, etc. are initialized in this constructor and set as properties in
        /// this main class. The bot only allows one instance of itself for the explicit reason that
        /// Quake Live can only have one running copy open at a time. For this reason, this
        /// initilizated <see cref="SynServerTool" /> object is frequently passed around the rest of
        /// the code almost entirely through constructor injection and the properties are directly
        /// accessed rather than constantly instantiating new classes. In this application, access
        /// to state among most parts is crucial, and unfortunately that leads to some unavoidable
        /// tight coupling. Once intilizated, the bot will then call the
        /// <see cref="CheckForAutoMonitoring" /> method which reads the configuration to see if the
        /// user has specified whether server monitoring should begin on application start. If Quake
        /// Live is running, we will check to see if the client is connected to a server. If
        /// connected, we will retrieve the server information and players using built in QL
        /// commands. After that, we will start a timer that waits for ~6.5s to perform any final
        /// initlization tasks to make sure all necessary information is present. This project
        /// initially started as a VERY simple proof of concept and expanded dramatically from
        /// there, so refactoring in various places is almost certainly in order. For example, a
        /// user interface was not initially planned (the tool was going to only be command-driven
        /// in-game), but was later added during development for ease of use.
        /// </remarks>
        public SynServerTool(bool isRestart)
        {
            // Core
            ServerInfo           = new ServerInfo();
            QlCommands           = new QlCommands(this);
            Parser               = new Parser();
            QlWindowUtils        = new QlWindowUtils();
            ConsoleTextProcessor = new ConsoleTextProcessor(this);
            ServerEventProcessor = new ServerEventProcessor(this);
            VoteManager          = new VoteManager();

            //Set the name of the bot
            AccountName = GetAccountNameFromConfig();
            // Hook up modules
            Mod = new ModuleManager(this);
            // Hook up command listener
            CommandProcessor = new CommandProcessor(this);

            // If being launched as restart then automatically try to start monitoring and skip the check.
            if (isRestart)
            {
                // ReSharper disable once UnusedVariable (synchronous)
                var a = AttemptAutoMonitorStart();
            }
            else
            {
                // Otherwise, check if we should begin monitoring a server immediately per user's settings.
                CheckForAutoMonitoring();
            }
        }
コード例 #2
0
        /// <summary>
        /// Attempts to automatically start server monitoring on application launch, if the user has
        /// this option specified in the SST configuration file.
        /// </summary>
        public async Task AttemptAutoMonitorStart()
        {
            if (!QlWindowUtils.QuakeLiveConsoleWindowExists())
            {
                Log.Write(
                    "Attempt to auto-start server monitoring on program start failed: QL instance not found.",
                    _logClassType, _logPrefix);

                MessageBox.Show(
                    @"Could not auto-start server monitoring because a running instance of Quake Live was not found!",
                    @"Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            await BeginMonitoring();
        }
コード例 #3
0
        /// <summary>
        /// Reads the QL console window.
        /// </summary>
        private void ReadQlConsole()
        {
            var consoleWindow = QlWindowUtils.GetQuakeLiveConsoleWindow();
            var cText         = QlWindowUtils.GetQuakeLiveConsoleTextArea(consoleWindow,
                                                                          QlWindowUtils.GetQuakeLiveConsoleInputArea(consoleWindow));

            if (cText != IntPtr.Zero)
            {
                while (IsReadingConsole)
                {
                    var textLength = Win32Api.SendMessage(cText, Win32Api.WM_GETTEXTLENGTH, IntPtr.Zero,
                                                          IntPtr.Zero);
                    if ((textLength == 0) || (ConsoleTextProcessor.OldWholeConsoleLineLength == textLength))
                    {
                        continue;
                    }

                    // Entire console window text
                    var entireBuffer = new StringBuilder(textLength + 1);
                    Win32Api.SendMessage(cText, Win32Api.WM_GETTEXT, new IntPtr(textLength + 1), entireBuffer);
                    var received = entireBuffer.ToString();
                    ConsoleTextProcessor.ProcessEntireConsoleText(received, textLength);

                    var lengthDifference = Math.Abs(textLength - _oldLength);

                    if (received.Length > lengthDifference)
                    {
                        // Bounds checking
                        int start;
                        int length;

                        if (_oldLength > received.Length)
                        {
                            start  = 0;
                            length = received.Length;
                        }
                        else
                        {
                            start  = _oldLength;
                            length = lengthDifference;
                        }

                        // Standardize QL's annoying string formatting
                        var diffBuilder = new StringBuilder(received.Substring(start, length));
                        diffBuilder.Replace("\"\r\n\r\n", "\"\r\n");
                        diffBuilder.Replace("\r\n\"\r\n", "\r\n");
                        diffBuilder.Replace("\r\n\r\n", "\r\n");
                        ConsoleTextProcessor.ProcessShortConsoleLines(diffBuilder.ToString());
                    }

                    // Detect when buffer is about to be full, in order to auto-clear. Win Edit
                    // controls can have a max of 30,000 characters, see: "Limits of Edit Controls"
                    // - http://msdn.microsoft.com/en-us/library/ms997530.aspx More info: Q3 source
                    // (win_syscon.c), Conbuf_AppendText
                    int begin, end;
                    Win32Api.SendMessage(cText, Win32Api.EM_GETSEL, out begin, out end);
                    if ((begin >= 29300) && (end >= 29300))
                    {
                        Log.Write("Clearing nearly full conbuf.",
                                  _logClassType, _logPrefix);

                        // Auto-clear
                        QlCommands.ClearQlWinConsole();
                    }
                    _oldLength = textLength;
                }
            }
            else
            {
                Log.WriteCritical("Unable to get necessary console handle.", _logClassType, _logPrefix);
            }
        }
コード例 #4
0
        /// <summary>
        /// Executes the specified command asynchronously.
        /// </summary>
        /// <param name="c">The cmd args.</param>
        public async Task <bool> ExecAsync(Cmd c)
        {
            if (!c.Args[1].Equals("start") &&
                !c.Args[1].Equals("stop") && !c.Args[1].Equals("reset") &&
                !c.Args[1].Equals("status"))
            {
                DisplayArgLengthError(c);
                return(false);
            }
            var qlw = new QlWindowUtils();

            if (!qlw.QuakeLiveConsoleWindowExists())
            {
                _irc.SendIrcNotice(c.FromUser,
                                   "[ERROR] A running instance of Quake Live could not be found.");

                Log.Write(string.Format(
                              "{0} attempted to use {1} command but a running instance of Quake Live could not be found. Ignoring.",
                              c.FromUser, c.CmdName), _logClassType, _logPrefix);

                return(false);
            }
            if (c.Args[1].Equals("start"))
            {
                if (_sst.IsMonitoringServer)
                {
                    _irc.SendIrcNotice(c.FromUser,
                                       "[ERROR] Your QL server is already being monitored.");

                    Log.Write(string.Format(
                                  "{0} attempted to start server monitoring but server is already being monitored. Ignoring.",
                                  c.FromUser), _logClassType, _logPrefix);

                    return(false);
                }
                _irc.SendIrcMessage(_irc.IrcSettings.ircChannel,
                                    "\u0002[SUCCESS]\u0002 Attempting to start QL server monitoring.");
                await _sst.BeginMonitoring();

                // Give it time to complete initilization, then show status.
                await Task.Delay(11000);

                ShowMonitorStatus();
            }
            else if (c.Args[1].Equals("stop"))
            {
                if (!_sst.IsMonitoringServer)
                {
                    _irc.SendIrcNotice(c.FromUser,
                                       "[ERROR] No QL server is currently being monitored.");

                    Log.Write(string.Format(
                                  "{0} attempted to stop server monitoring but server is not currently being monitored. Ignoring.",
                                  c.FromUser), _logClassType, _logPrefix);

                    return(false);
                }

                _sst.StopMonitoring();
                _irc.SendIrcMessage(_irc.IrcSettings.ircChannel,
                                    "\u0002[SUCCESS]\u0002 Stopped monitoring your QL server.");
            }
            else if (c.Args[1].Equals("reset"))
            {
                if (_sst.IsMonitoringServer)
                {
                    Log.Write(string.Format(
                                  "{0} reset server monitoring for actively monitored server; now stopping server monitoring.",
                                  c.FromUser), _logClassType, _logPrefix);

                    _irc.SendIrcMessage(_irc.IrcSettings.ircChannel,
                                        "\u0002[SUCCESS]\u0002 Your QL server was being monitored; now stopping this monitoring.");

                    _sst.StopMonitoring();
                }
                else
                {
                    Log.Write(string.Format(
                                  "{0} reset server monitoring for non-actively monitored server; now starting server monitoring.",
                                  c.FromUser), _logClassType, _logPrefix);

                    _irc.SendIrcMessage(_irc.IrcSettings.ircChannel,
                                        "\u0002[SUCCESS]\u0002 Your QL server was not being monitored; now starting monitoring.");

                    await _sst.BeginMonitoring();
                }
            }
            else if (c.Args[1].Equals("status"))
            {
                ShowMonitorStatus();
            }

            return(true);
        }