BVE 車掌の動作を取得する

　BVEのATSプラグインがBVE本体から渡されるイベントは、車両になにか変化があったイベントのみであり、車掌の動作のイベントはない。
　しかし、プレイ中には見ることのできないBVEの標準出力には車掌の動作が出力されている。
　すなわち、プラグインがBVEの標準出力を乗っ取r(ry 取得すれば、車掌の動作による制御を実装することができる。

　Loadイベント後に取得できる標準出力内容は、現在のところ確認できているのは、「発車ベル: ON」「車掌: 停止位置よし」「車掌スイッチ: 開」「車掌スイッチ: 閉」「側灯滅」の5つ。
※非公式の機能のため、将来的に変更・廃止になる可能性がある。


# 1.BVEの標準出力を取得する

~~~C#
using System;
using System.ComponentModel;
using System.IO;
using System.Text;

namespace AtsPlugin.Core.Engine
{
    public class StdOut
    {
        // 標準出力に再出力するか？
        public bool Redirect { get; set; }
        // 標準出力
        TextWriter Console_StdOut { get; set; }
        // BVE標準出力の乗っ取り先
        StringWriter Bve_StdOut { get; set; }
        StringBuilder Bve_StdOut_StringBuilder { get; set; }
        // 実行間隔
        int Interval { get; set; } = 10;

        private BackgroundWorker bgWorker1 = new BackgroundWorker();

        //TimeEventArgs型のオブジェクトを返すようにする
        public delegate void StdOutRcvMessageEventHandler(object sender, StdOutRcvMessageEventArgs e);

        //イベントデリゲートの宣言
        public event StdOutRcvMessageEventHandler ReceiveMessage;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public StdOut()
        {
            Console_StdOut = Console.Out;
            Bve_StdOut = new StringWriter();
            Bve_StdOut_StringBuilder = Bve_StdOut.GetStringBuilder();
            Console.SetOut(Bve_StdOut);

            bgWorker1 = new BackgroundWorker();
            // キャンセル許可
            bgWorker1.WorkerSupportsCancellation = true;
            // ハンドラ
            bgWorker1.DoWork += new DoWorkEventHandler(bgWorker1_DoWork);
            bgWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker1_RunWorkerCompleted);

            bgWorker1.RunWorkerAsync();
        }

        public void Dispose()
        {
            if (bgWorker1.IsBusy)
            {
                bgWorker1.CancelAsync();
            }
            bgWorker1.Dispose();
        }

        private void bgWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            for(; ; )
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    if (Bve_StdOut_StringBuilder.Length > 0)
                    {
                        string s = Bve_StdOut_StringBuilder.ToString();
                        Bve_StdOut_StringBuilder.Remove(0, Bve_StdOut_StringBuilder.Length);

                        //返すデータの設定
                        StdOutRcvMessageEventArgs e2 = new StdOutRcvMessageEventArgs();
                        e2.Message = s.Replace("\n", "").Replace("\r", "");
                        //イベントの発生
                        OnReceiveMessage(e2);

                        if (Redirect == true) Console_StdOut.Write(s);
                    }
                    System.Threading.Thread.Sleep(Interval);
                }
            }
        }

        private void bgWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
              // キャンセルされた
            }
            else if (e.Error != null)
            {
              // エラーがあった
            }
            else
            {
              // 無事終了
            }
        }


        #region イベントクラス
        public class StdOutRcvMessageEventArgs : EventArgs
        {
            public string Message;
        }


        protected virtual void OnReceiveMessage(StdOutRcvMessageEventArgs e)
        {
            if (ReceiveMessage != null)
            {
                ReceiveMessage(this, e);
            }
        }
        #endregion

    }
}
~~~



# 2.実装する



~~~C#
namespace AtsPlugin.Core
{
  public class AtsMain
  {
    // 定義
    // BVE標準出力取得クラスのインスタンス
    private Engine.StdOut STD;

// (略)

    // Loadイベント内
    public void Load()
    {
      // (略)
      STD = new Engine.StdOut();
      // BVE標準出力に変化があったときに呼ばれるイベント
      STD.ReceiveMessage += new Engine.StdOut.StdOutRcvMessageEventHandler(this.CheckStdOut);
      // (略)
    }

    // お呼ばれされる関数
    private void CheckStdOut(object sender, Engine.StdOut.StdOutRcvMessageEventArgs e)
    {
      try
      {
        switch (e.Message)
        {
          case "発車ベル: ON":
            // 車掌が発車ベルを鳴らした際
            break;
          case "車掌: 停止位置よし":
            break;
          case "車掌スイッチ: 開":
            // 車掌が戸開け操作を開始した際
            break;
          case "車掌スイッチ: 閉":
            // 車掌が戸締め操作を開始した際
            break;
          case "側灯滅":
            break;
          default:
            break;
        }
      }
      catch
      {

      }
    }

// (略)
~~~
※名前空間は適宜調整してください。