Unity C#:与控制台计划不同步

发布于 2025-02-10 20:03:21 字数 2249 浏览 2 评论 0原文

我目前正在尝试用Unity 写国际象棋GUI。我有一个由UCI(控制台)通信的EXE文件的国际象棋引擎。该计划处于很早的阶段,我只想与国际象棋引擎(控制台应用程序)进行交流,作为概念证明。

目前,我使用 Process类与重定向的输出和输入。象棋发动机输出目前的所有内容都在Unity控制台中打印出来。不幸的是,我没有尝试的工作能像预期的那样。

国际象棋引擎(控制台程序)的工作方式:

  • 用户可以在控制台“ uci”或“ go dept 1”中编写命令,
  • 引擎将以“ uciok”或“ BestMove E2E4”这些响应也可以具有多行。

我想要的:

  1. 按UNITY播放
  2. 我的脚本立即将消息“ UCI”发送到国际象棋引擎,
  3. 输出(Muliple Lines)都会将输出(Muliple Lines)打印到Unity Console
  4. 每次我按“ C'C'步骤2和3, 。重复重复

当前发生的事情:

  1. 按Unity
  2. Console(国际象棋引擎)打开
  3. 我手动关闭控制台窗口的
  4. 消息“ UCI”将发送到国际象棋发动机
  5. 多线将输出到Unity Console
  6. IOException

当我按“ C”时,我会得到我也尝试过的

  • : startInfo.CreatEnowIndow = true; - >我必须与任务管理器保持团结,直到该过程完成
  • Engine Process.waitforexit(); - >不起作用,因为该过程不应该退出
  • Engine Process.beginOutputReadline(); - >我被Unity垃圾邮件和例外垃圾邮件,因为我正在混合同步操作,并且
  • 在Stackoverflow上已经建议了许多其他解决方案。到目前为止,什么都没有用:(

我对Unity和C#的新手很新,所以我希望这个问题不会让我看起来很愚蠢。我在下面发布了我的代码。

public string pathToExe = "PathToExe";
private Process engineProcess;

//gets automatically called once when I press start in Unity 
private void Start() {
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.CreateNoWindow = false;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardInput = true;
    startInfo.FileName = pathToExe;

    //Start process and write "uci" to chess engine
    try {
        engineProcess = Process.Start(startInfo);
        engineProcess.StandardInput.WriteLine("uci");
    }
    catch {
        UnityEngine.Debug.Log("Error when starting Engine");
    }
}

//gets called every tick when Unity is running
private void Update() {
    //write uci to chess engine when c is pressed
    if (Input.GetKeyDown(KeyCode.C)) {
        engineProcess.StandardInput.WriteLine("uci");
    }
    //read engine output if it exists
    while (!engineProcess.StandardOutput.EndOfStream) {
        string line = engineProcess.StandardOutput.ReadLine();
        UnityEngine.Debug.Log(line);
    }
}

I'm currently trying to write a chess GUI in Unity. I have a chess engine as an exe-file which communicates via UCI (console). The program is in a very early stage and I just want to communicate with the chess engine (console application) as a proof of concept.

At the moment I'm using the Process class with a redirected output and input. Everything that the chess engine outputs is currently being printed in the unity console. Unfortunately nothing I try works like expected.

How the Chess Engine (Console Program) works:

  • User can write a command in the console e.g. "uci" or "go dept 1"
  • The engine will respond with "uciok" or "bestmove e2e4"
    These responses can also have multiple lines.

What I want:

  1. Press play in Unity
  2. My script instantly sends the message "uci" to the chess engine
  3. The output (muliple lines) gets printed to the unity console
  4. Everytime I press 'c' step 2 and 3 get repeated

What currently happens:

  1. Press play in Unity
  2. Console (chess engine) opens
  3. I manually have to close the console window
  4. The message "uci" gets sent to the chess engine
  5. Multiple lines get outputted to the unity console
  6. When I press 'c' I'm getting an IOException

What I've also tried:

  • startInfo.CreateNoWindow = true; --> I have to close unity with the task manager as it waits until the process finishes
  • engineProcess.WaitForExit(); --> Does not work, as the process is not supposed to exit
  • engineProcess.BeginOutputReadLine(); --> I'm getting spammed by unity with exceptions because I'm mixing synchronus and asynchronous operations
  • Many other solutions already suggested on StackOverflow. Nothing worked so far :(

I'm pretty new to Unity and C#, so I hope that this question does not make me look stupid. I posted my code below.

public string pathToExe = "PathToExe";
private Process engineProcess;

//gets automatically called once when I press start in Unity 
private void Start() {
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.CreateNoWindow = false;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardInput = true;
    startInfo.FileName = pathToExe;

    //Start process and write "uci" to chess engine
    try {
        engineProcess = Process.Start(startInfo);
        engineProcess.StandardInput.WriteLine("uci");
    }
    catch {
        UnityEngine.Debug.Log("Error when starting Engine");
    }
}

//gets called every tick when Unity is running
private void Update() {
    //write uci to chess engine when c is pressed
    if (Input.GetKeyDown(KeyCode.C)) {
        engineProcess.StandardInput.WriteLine("uci");
    }
    //read engine output if it exists
    while (!engineProcess.StandardOutput.EndOfStream) {
        string line = engineProcess.StandardOutput.ReadLine();
        UnityEngine.Debug.Log(line);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

郁金香雨 2025-02-17 20:03:21

感谢@bugfinder指出,您可以将方法附加到某些事件。使用您的tipps和 process.beginOutputReadline 我能够解决问题。
我评论了与原始代码相比,我在哪里添加或删除了行。

public string pathToExe;
private Process engineProcess;

private void Start() {
    ProcessStartInfo startInfo = new ProcessStartInfo();

    startInfo.CreateNoWindow = false;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardInput = true;
    startInfo.FileName = pathToExe;

    try {
        engineProcess = Process.Start(startInfo);
        engineProcess.StandardInput.WriteLine("uci");
    }
    catch {
        UnityEngine.Debug.Log("Error when starting Engine");
    }

    //Added these two lines so the method "engineOutputHandler" 
    //gets automatically called every time an output is received
    engineProcess.OutputDataReceived += engineOutputHandler;
    engineProcess.BeginOutputReadLine();
}

private void Update() {
    if (Input.GetKeyDown(KeyCode.C)) {
        engineProcess.StandardInput.WriteLine("uci");
    }

    //removed the entire while loop

}

//Added this method, which prints out the data received
private void engineOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) {
    if (!string.IsNullOrEmpty(outLine.Data)) {
        UnityEngine.Debug.Log(outLine.Data);
    }
}

Thanks to @BugFinder to pointing out that there are events that you can attach a method to. Using your tipps and the documentation of Process.BeginOutputReadLine I was able to solve the problem.
I commented where I added or removed line in comparison with the original code.

public string pathToExe;
private Process engineProcess;

private void Start() {
    ProcessStartInfo startInfo = new ProcessStartInfo();

    startInfo.CreateNoWindow = false;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardInput = true;
    startInfo.FileName = pathToExe;

    try {
        engineProcess = Process.Start(startInfo);
        engineProcess.StandardInput.WriteLine("uci");
    }
    catch {
        UnityEngine.Debug.Log("Error when starting Engine");
    }

    //Added these two lines so the method "engineOutputHandler" 
    //gets automatically called every time an output is received
    engineProcess.OutputDataReceived += engineOutputHandler;
    engineProcess.BeginOutputReadLine();
}

private void Update() {
    if (Input.GetKeyDown(KeyCode.C)) {
        engineProcess.StandardInput.WriteLine("uci");
    }

    //removed the entire while loop

}

//Added this method, which prints out the data received
private void engineOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) {
    if (!string.IsNullOrEmpty(outLine.Data)) {
        UnityEngine.Debug.Log(outLine.Data);
    }
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文