/// <summary>
 /// Initializes a new instance of the <see cref="MachineVariableMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="name">The player variable name.</param>
 /// <param name="value">The player variable value.</param>
 public MachineVariableMessageEventArgs(BcpMessage bcpMessage, string name, string value)
     : base(bcpMessage)
 {
     this.Name = name;
     this.Value = value;
 }
    /// <summary>
    /// Internal message handler for all "player_score" messages. Raises the <see cref="OnPlayerScore"/> event.
    /// </summary>
    /// <param name="message">The "player_score" BCP message.</param>
    protected void PlayerScoreMessageHandler(BcpMessage message)
    {
        if (OnPlayerScore != null)
        {
            try
            {
                int playerNum = int.Parse(message.Parameters["player_num"]);
                int value = int.Parse(message.Parameters["value"]);
                int previousValue = int.Parse(message.Parameters["prev_value"]);
                int change = int.Parse(message.Parameters["change"]);

                OnPlayerScore(this, new PlayerScoreMessageEventArgs(message, playerNum, value, previousValue, change));
            }
            catch (Exception e)
            {
                BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
            }
        }
    }
    /// <summary>
    /// Internal message handler for all "player_variable" messages. Raises the <see cref="OnPlayerVariable"/> event.
    /// </summary>
    /// <param name="message">The "player_variable" BCP message.</param>
    protected void PlayerVariableMessageHandler(BcpMessage message)
    {
        if (OnPlayerVariable != null)
        {
            try
            {
                int playerNum = int.Parse(message.Parameters["player_num"]);

                string name = message.Parameters["name"];
                if (String.IsNullOrEmpty(name))
                    throw new ArgumentException("Message parameter value expected", "name");

                string value = message.Parameters["value"];
                if (String.IsNullOrEmpty(value))
                    throw new ArgumentException("Message parameter value expected", "value");

                string previousValue = message.Parameters["prev_value"];
                if (String.IsNullOrEmpty(previousValue))
                    throw new ArgumentException("Message parameter value expected", "prev_value");

                string change = message.Parameters["change"];
                if (String.IsNullOrEmpty(change))
                    throw new ArgumentException("Message parameter value expected", "change");

                OnPlayerVariable(this, new PlayerVariableMessageEventArgs(message, playerNum, name, value, previousValue, change));

            }
            catch (Exception e)
            {
                BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
            }
        }
    }
    /// <summary>
    /// Internal message handler for all "goodbye" messages. Raises the <see cref="OnGoodbye"/> event.
    /// </summary>
    /// <param name="message">The "goodbye" BCP message.</param>
    protected void GoodbyeMessageHandler(BcpMessage message)
    {
        // Raise the OnGoodbye event by invoking the delegate. Pass in
        // the object that initated the event (this) as well as the BcpMessage.
        if (OnGoodbye != null)
        {
            try
            {
                OnGoodbye(this, new BcpMessageEventArgs(message));
            }
            catch (Exception e)
            {
                BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
            }
        }

        // Shutdown the media controller server (close socket listener)
        BcpServer.Instance.Close();

        // Shutdown the Unity application
        #if UNITY_EDITOR
        if (EditorApplication.isPlaying)
            EditorApplication.isPlaying = false;
        #endif
        Application.Quit ();
    }
 /// <summary>
 /// Initializes a new instance of the <see cref="BcpMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 public BcpMessageEventArgs(BcpMessage bcpMessage)
 {
     this.BcpMessage = bcpMessage;
 }
 /// <summary>
 /// Adds a BCP message to the queue for processing.
 /// </summary>
 /// <param name="message">The BCP message.</param>
 /// <remarks>
 /// This function may be accessed from several different threads and therefore must use thread-safe access methods.
 /// </remarks>
 public void AddMessageToQueue(BcpMessage message)
 {
     lock (_queueLock) {
         if (_messageQueue.Count < messageQueueSize) {
             _messageQueue.Enqueue(message);
         }
     }
 }
 /// <summary>
 /// Internal message handler for all "ball_end" messages. Raises the <see cref="OnBallEnd"/> event.
 /// </summary>
 /// <param name="message">The "ball_end" BCP message.</param>
 protected void BallEndMessageHandler(BcpMessage message)
 {
     if (OnBallEnd != null)
         OnBallEnd(this, new BcpMessageEventArgs(message));
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PlayerVariableMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="playerNum">The player number.</param>
 /// <param name="name">The player variable name.</param>
 /// <param name="value">The player variable value.</param>
 /// <param name="previousValue">The previous value of the player variable.</param>
 /// <param name="change">The change in value of the player variable.</param>
 public PlayerVariableMessageEventArgs(BcpMessage bcpMessage, int playerNum, string name, string value, string previousValue, string change)
     : base(bcpMessage)
 {
     this.PlayerNum = playerNum;
     this.Name = name;
     this.Value = value;
     this.PreviousValue = previousValue;
     this.Change = change;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="ResetMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="hard">if set to <c>true</c> [hard].</param>
 public ResetMessageEventArgs(BcpMessage bcpMessage, bool hard)
     : base(bcpMessage)
 {
     this.Hard = hard;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PlayerScoreMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="playerNum">The player number.</param>
 /// <param name="value">The specified player's score value.</param>
 /// <param name="previousValue">The specified player's previous score value.</param>
 /// <param name="change">The change in the specified player's score.</param>
 public PlayerScoreMessageEventArgs(BcpMessage bcpMessage, int playerNum, int value, int previousValue, int change)
     : base(bcpMessage)
 {
     this.PlayerNum = playerNum;
     this.Value = value;
     this.PreviousValue = previousValue;
     this.Change = change;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PlayerTurnStartMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="playerNum">The player number.</param>
 public PlayerTurnStartMessageEventArgs(BcpMessage bcpMessage, int playerNum)
     : base(bcpMessage)
 {
     this.PlayerNum = playerNum;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PlayerAddedMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="playerNum">The player number.</param>
 public PlayerAddedMessageEventArgs(BcpMessage bcpMessage, int playerNum)
     : base(bcpMessage)
 {
     this.PlayerNum = playerNum;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="ModeStopMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="name">The mode name.</param>
 public ModeStopMessageEventArgs(BcpMessage bcpMessage, string name)
     : base(bcpMessage)
 {
     this.Name = name;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="ModeStartMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="name">The mode name.</param>
 /// <param name="priority">The mode priority.</param>
 public ModeStartMessageEventArgs(BcpMessage bcpMessage, string name, int priority)
     : base(bcpMessage)
 {
     this.Name = name;
     this.Priority = priority;
 }
    /// <summary>
    /// Converts a BCP message to a socket packet to be sent to a pinball controller.
    /// </summary>
    /// <param name="message">The BCP message.</param>
    /// <param name="packet">The generated packet (by reference).</param>
    /// <returns>The length of the generated packet</returns>
    public static int BcpMessageToPacket(BcpMessage message, out byte[] packet)
    {
        StringBuilder parameters = new StringBuilder ();
        foreach (string name in message.Parameters)
        {
            if (parameters.Length > 0)
                parameters.Append("&");
            else
                parameters.Append("?");

            parameters.Append(WWW.EscapeURL(name));
            string value = message.Parameters[name];
            if (!String.IsNullOrEmpty(value))
                parameters.Append("=" + WWW.EscapeURL(value));

        }

        // Apply message termination character (line feed)
        parameters.Append("\n");

        packet = Encoding.UTF8.GetBytes(WWW.EscapeURL(message.Command) + parameters.ToString());
        return packet.Length;
    }
 /// <summary>
 /// Initializes a new instance of the <see cref="ResetMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 public ResetMessageEventArgs(BcpMessage bcpMessage)
     : base(bcpMessage)
 {
     this.Hard = false;
 }
    /// <summary>
    /// Converts a message string (in URL text format) to a BCP message.
    /// </summary>
    /// <param name="rawMessageBuffer">The raw message string/buffer.</param>
    /// <returns><see cref="BcpMessage"/></returns>
    public static BcpMessage StringToBcpMessage(string rawMessageBuffer)
    {
        BcpMessage bcpMessage = new BcpMessage ();

        // Remove line feed and carriage return characters
        rawMessageBuffer = rawMessageBuffer.Replace("\n", String.Empty);
        rawMessageBuffer = rawMessageBuffer.Replace("\r", String.Empty);

        bcpMessage.RawMessage = rawMessageBuffer;

        // Message text occurs before the question mark (?)
        if (rawMessageBuffer.Contains ("?")) {
            int messageDelimiterPos = rawMessageBuffer.IndexOf ('?');
            bcpMessage.Command = WWW.UnEscapeURL(rawMessageBuffer.Substring (0, messageDelimiterPos)).Trim();
            rawMessageBuffer = rawMessageBuffer.Substring (rawMessageBuffer.IndexOf ('?') + 1);

            foreach (string parameter in Regex.Split(rawMessageBuffer, "&"))
            {
                string[] parameterValuePair = Regex.Split(parameter, "=");
                if (parameterValuePair.Length == 2)
                {
                    bcpMessage.Parameters.Add(WWW.UnEscapeURL(parameterValuePair[0]).Trim(), WWW.UnEscapeURL(parameterValuePair[1]).Trim());
                }
                else
                {
                    // only one key with no value specified in query string
                    bcpMessage.Parameters.Add(WWW.UnEscapeURL(parameterValuePair[0].Trim()), string.Empty);
                }
            }

        }
        else
        {
            // No parameters in the message, the entire message contains just the message text
            bcpMessage.Command = WWW.UnEscapeURL(rawMessageBuffer).Trim();
        }

        return bcpMessage;
    }
 /// <summary>
 /// Initializes a new instance of the <see cref="ShotMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="name">The shot name.</param>
 /// <param name="profile">The shot profile value.</param>
 /// <param name="state">The shot state value.</param>
 public ShotMessageEventArgs(BcpMessage bcpMessage, string name, string profile, string state)
     : base(bcpMessage)
 {
     this.Name = name;
     this.Profile = profile;
     this.State = state;
 }
 /************************************************************************************
  * Internal BCP Message Handler functions (called when a specific message type is received)
  ************************************************************************************/
 /// <summary>
 /// Internal message handler callback function for all BCP messages received (called before individual message handlers). 
 /// Raises the <see cref="OnMessage"/> event.
 /// </summary>
 /// <param name="message">The BCP message.</param>
 protected void AllMessageHandler(BcpMessage message)
 {
     // Raise the OnMessage event by invoking the delegate.
     if (OnMessage != null)
     {
         try
         {
             OnMessage(this, new BcpMessageEventArgs(message));
         }
         catch (Exception e)
         {
             BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred in the AllMessageHandler while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
         }
     }
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SwitchMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="name">The switch name.</param>
 /// <param name="value">The switch value.</param>
 public SwitchMessageEventArgs(BcpMessage bcpMessage, string name, int value)
     : base(bcpMessage)
 {
     this.Name = name;
     this.Value = value;
 }
 /// <summary>
 /// Internal message handler for all "get" messages. Raises the <see cref="OnGet"/> event.
 /// </summary>
 /// <param name="message">The "get" BCP message.</param>
 protected void GetMessageHandler(BcpMessage message)
 {
     if (OnGet != null)
     {
         try
         {
             OnGet(this, new BcpMessageEventArgs(message));
         }
         catch (Exception e)
         {
             BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
         }
     }
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="TiltWarningMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="warnings">The number of tilt warnings.</param>
 /// <param name="warningsRemaining">The number of tilt warnings remaining before a tilt.</param>
 public TiltWarningMessageEventArgs(BcpMessage bcpMessage, int warnings, int warningsRemaining)
     : base(bcpMessage)
 {
     this.Warnings = warnings;
     this.WarningsRemaining = warningsRemaining;
 }
    /// <summary>
    /// Internal message handler for all "hello" messages. Raises the <see cref="OnHello"/> event.
    /// </summary>
    /// <param name="message">The "hello" BCP message.</param>
    protected void HelloMessageHandler(BcpMessage message)
    {
        try
        {
            string version = message.Parameters["version"] ?? String.Empty;
            if (String.IsNullOrEmpty(version))
                throw new Exception("'hello' message did not contain a valid value for the 'version' parameter");

            string controllerName = message.Parameters["controller_name"] ?? String.Empty;
            string controllerVersion = message.Parameters["controller_version"] ?? String.Empty;

            if (version == BCP_VERSION)
                BcpServer.Instance.Send(BcpMessage.HelloMessage(BCP_VERSION, BcpServer.CONTROLLER_NAME, BcpServer.CONTROLLER_VERSION));
            else
                throw new Exception("'hello' message received an unknown protocol version");

            // Raise the OnHello event by invoking the delegate. Pass in
            // the object that initated the event (this) as well as the BcpMessage.
            if (OnHello != null)
            {
                OnHello(this, new HelloMessageEventArgs(message, version, controllerName, controllerVersion));
            }

        }
        catch (Exception e)
        {
            BcpLogger.Trace("ERROR: " + e.Message);
            BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
        }
    }
 /// <summary>
 /// Initializes a new instance of the <see cref="TimerMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="name">The timer name.</param>
 /// <param name="action">The timer action.</param>
 /// <param name="ticks">The timer ticks.</param>
 public TimerMessageEventArgs(BcpMessage bcpMessage, string name, string action, int ticks)
     : base(bcpMessage)
 {
     this.Name = name;
     this.Action = action;
     this.Ticks = ticks;
 }
    /// <summary>
    /// Internal message handler for all "mode_stop" messages. Raises the <see cref="OnModeStop"/> event.
    /// </summary>
    /// <param name="message">The "mode_stop" BCP message.</param>
    protected void ModeStopMessageHandler(BcpMessage message)
    {
        if (OnModeStop != null)
        {
            try
            {
                string name = message.Parameters["name"];
                if (String.IsNullOrEmpty(name))
                    throw new ArgumentException("Message parameter value expected", "name");

                OnModeStop(this, new ModeStopMessageEventArgs(message, name));
            }
            catch (Exception e)
            {
                BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
            }
        }
    }
 /// <summary>
 /// Initializes a new instance of the <see cref="TriggerMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="name">The trigger name.</param>
 public TriggerMessageEventArgs(BcpMessage bcpMessage, string name)
     : base(bcpMessage)
 {
     this.Name = name;
 }
 /// <summary>
 /// Internal message handler for all "player_turn_start" messages. Raises the <see cref="OnPlayerTurnStart"/> event.
 /// </summary>
 /// <param name="message">The "player_turn_start" BCP message.</param>
 protected void PlayerTurnStartMessageHandler(BcpMessage message)
 {
     if (OnPlayerTurnStart != null)
     {
         try
         {
             int playerNum = int.Parse(message.Parameters["player_num"]);
             OnPlayerTurnStart(this, new PlayerTurnStartMessageEventArgs(message, playerNum));
         }
         catch (Exception e)
         {
             BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
         }
     }
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="BallStartMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="playerNum">The player number.</param>
 /// <param name="ball">The ball number.</param>
 public BallStartMessageEventArgs(BcpMessage bcpMessage, int playerNum, int ball)
     : base(bcpMessage)
 {
     this.PlayerNum = playerNum;
     this.Ball = ball;
 }
 /// <summary>
 /// Internal message handler for all "reset" messages. Raises the <see cref="OnReset"/> event.
 /// </summary>
 /// <param name="message">The "reset" BCP message.</param>
 protected void ResetMessageHandler(BcpMessage message)
 {
     // Check if any event handlers are established for the reset command
     if (OnReset == null)
     {
         // There are no event handlers, automatically send a Reset Complete command back to the pinball controller
         BcpServer.Instance.Send(BcpMessage.ResetCompleteMessage());
     }
     else
     {
         // Call the reset event handlers
         try
         {
             OnReset(this, new ResetMessageEventArgs(message, (message.Parameters["hard"] == null) ? false : bool.Parse(message.Parameters["hard"])));
         }
         catch (Exception e)
         {
             BcpServer.Instance.Send(BcpMessage.ErrorMessage("An error occurred while processing a '" + message.Command + "' message: " + e.Message, message.RawMessage));
         }
     }
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="HelloMessageEventArgs"/> class.
 /// </summary>
 /// <param name="bcpMessage">The BCP message.</param>
 /// <param name="version">The BCP message protocol version.</param>
 /// <param name="controllerName">The name of the controller.</param>
 /// <param name="controllerVersion">The version of the controller.</param>
 public HelloMessageEventArgs(BcpMessage bcpMessage, string version, string controllerName, string controllerVersion)
     : base(bcpMessage)
 {
     this.Version = version;
     this.ControllerName = controllerName;
     this.ControllerVersion = controllerVersion;
 }