ScreenshotRunner

internal object ScreenshotRunner

Captures the game's framebuffer for the take_screenshot tool.

The render thread's whole contribution is one pixel-array copy; scaling and encoding run on the calling (HTTP) thread, so a screenshot costs the game a texture readback and nothing else. The hop over is vanilla's own Minecraft#execute rather than a lane — there is no tick affinity to respect here, just a thread requirement.

JPEG at a fixed size and quality, with nothing exposed to the caller: both are questions only whoever consumes the image can answer, and that is a model with no idea what resolution it can actually see. The cost of getting them wrong is ours, so the numbers are ours.

Loads only when the client path is actually taken, so it never touches client classes on a dedicated server. Minecraft.getInstance() is non-null from mod init on, but half-built until its constructor returns — the execute hop is what makes that safe, not Lanes.RENDER.isReady, which is a physical-side constant and would not catch a render-state read placed ahead of it.

Types

Link copied to clipboard
private class Raw(val pixels: IntArray, val width: Int, val height: Int)

Pixels as ScreenshotCompat handed them over: ARGB, top-down, row-major — BufferedImage.setRGB's own layout. Filled by the deprecated NativeImage#makePixelArray, used anyway because it is the only whole-image accessor 1.18.2 has; every replacement arrived later than the versions we target.

Properties

Link copied to clipboard
private const val MAX_PIXELS: Double
Link copied to clipboard
const val MIME: String
Link copied to clipboard
private const val QUALITY: Float = 0.85f

High enough that Minecraft's UI text survives the chroma subsampling.

Functions

Link copied to clipboard

Scaling on this thread, deliberately: the GPU-side downscale takeScreenshot grew at 1.21.6 would cost a version seam and does not exist on the older nodes.

Link copied to clipboard
Link copied to clipboard
fun grab(): ByteArray?

Take a screenshot and encode it. Blocks until the image lands.

Link copied to clipboard
private fun writeJpeg(image: BufferedImage): ByteArray

The long form, because ImageIO.write gives no way to set the quality.