ref:d5c4a4d2c4818de06c262e80c9ed569d6deb3057

Fix two bugs found by GameTests

Bug 1: getUpdateTag() didn't include Cols/Rows/FontSize - Block entity data wouldn't sync to clients on chunk load - Override getUpdateTag() to call saveAdditional() - Added test: updateTagIncludesFields verifies the fix Bug 2: PTY read could block the game thread - alacritty_terminal's PTY fd may not be non-blocking when read() is called directly (bypassing mio) - Set O_NONBLOCK explicitly before each read on Unix - Prevents game tick freeze if shell produces no output Both bugs were discovered by writing comprehensive tests that exercised code paths the original tests didn't cover. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SHA: d5c4a4d2c4818de06c262e80c9ed569d6deb3057
Author: Cole Christensen <cole.christensen@macmillan.com>
Date: 2026-03-20 07:12
Parents: 9c5bdc1
3 files changed +43 -1
Type
rust/src/terminal.rs +16 −1
@@ -417,9 +417,24 @@
}
}
/// Read output from PTY and process through VTE parser
/// Read output from PTY and process through VTE parser.
/// Uses non-blocking read to prevent freezing the game loop.
fn read_pty_output(&mut self) {
let read_result = if let Some(ref mut pty) = self.pty {
// Set non-blocking before each read to guarantee we never block
// the game tick thread. This is defensive — alacritty_terminal
// should set non-blocking via mio, but we bypass mio with direct read().
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
let fd = pty.reader().as_raw_fd();
unsafe {
let flags = libc::fcntl(fd, libc::F_GETFL);
if flags >= 0 && (flags & libc::O_NONBLOCK) == 0 {
libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK);
}
}
}
match pty.reader().read(&mut self.read_buffer) {
Ok(n) => Some(n),
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => None,