Skip to content
LeviMC
Back to search

Be.D.D.

by LiteLDev

Drive a Minecraft Bedrock Edition client from test scripts without touching the real mouse, keyboard or foreground window

client · 0.3.1

README0.3.1

Be.D.D.

English | 简体中文

Release License

Be.D.D. (Bedrock Deep Dive) is named after the H.D.D. of Zenless Zone Zero: a Proxy guides agents through the Hollows from afar, your script guides Minecraft from the background.

Run end-to-end tests of your LeviLamina client mods in the background. Your script presses keys, types and clicks inside Minecraft Bedrock, while your own mouse, keyboard and windows stay yours, and several games can play at once.

Three Minecraft windows react to a test script while the terminal in front keeps the focus

Warning

This is a testing tool. While background mode is on, the game ignores your real mouse and keyboard. Do not leave it in a game you play (Ctrl+Shift+F12 in the game window turns background mode off).

Features

  • Keep using your PC. The game never takes the foreground, the cursor or your keystrokes, and your clicks never land in it.
  • Several games at once. Each game instance has its own pipe; a cheap clone of an instance takes a few seconds.
  • One window for all of them. The games of every test run on the PC show up live in one manager window instead of popping up on your desktop; closing it closes them all.
  • Plays like a player. Keys, chat, key bindings, menus, hover tooltips, clicks and the camera all work as with a real mouse and keyboard.
  • Deterministic. Every call returns once the game has handled the input, so no guessing sleeps.
  • Screenshots of covered windows. The game can sit behind your other windows.
  • Drop-in for existing harnesses. One file replaces the usual Click, Press-Key, Focus-Game helpers of LeviLauncher harnesses; scenarios stay as they are.

Your input goes to your apps; the script drives three background games over one pipe each

Install

Put it into the game instance your tests run, for example with lip:

lip install github.com/LiteLDev/BeDD#client

or unzip bedd-client-windows-x64.zip from the releases into the instance's mods\ folder. Most harnesses copy it in at the start of a run and remove it afterwards (see below).

Needs Minecraft Bedrock Edition 1.26.51 (GDK) with LeviLamina 26.51.x (client), in a game instance installed with LeviLauncher. Tests start that instance with Start-BeDDGame.ps1 rather than through the launcher (see below). Only the test PC's game needs it; servers and players do not.

How to use

The PowerShell module ships next to the mod:

Import-Module .\mods\BeDD\BeDD.psm1
Connect-BeDD                          # waits until the game is up
Send-BeDDKey E                             # open the inventory
Send-BeDDMouse click -RX 0.5 -RY 0.474     # click at a fraction of the window
Send-BeDDKey T; Send-BeDDText '/give @s apple 3'; Send-BeDDKey ENTER
Save-BeDDScreenshot C:\temp\shot.png       # works while the window is covered
CommandWhat it does
Connect-BeDD [-PipeName p]wait for the game and pick which game the next calls go to
Send-BeDDKey Epress a key; -Action down/up to hold, -Vk 0x10 for any virtual key
Send-BeDDText '...'type text (no key presses, so t does not open chat); -DelayMs per character
Send-BeDDMouse click -RX 0.5 -RY 0.5move, down, up, click, wheel at -X -Y pixels or -RX -RY fractions; -Button right
Send-BeDDRaw move -Dx 200turn the camera in the world; click -Button right to use an item
Clear-BeDDInputrelease every key and button still held
Save-BeDDScreenshot path.png / Get-BeDDBitmapthe game's picture, even when covered
Set-BeDDWindow 1600 900resize the game window without bringing it forward
Set-BeDDBackground $falsehand the game back to your real mouse and keyboard
Get-BeDDStateis the game up, how much input arrived, did it ever get the foreground

Key names: letters, digits, ESC, ENTER, BACK, TAB, SPACE, SHIFT, CTRL, ALT, arrows (LEFT...), HOME, END, PGUP, PGDN, INSERT, DELETE, F1..F24, SLASH, GRAVE, MINUS, EQUALS.

Several games at once

pwsh -NoProfile -File clone-instance.ps1 -Slot 2                  # versions\1.26.51.01-hi2, ~90 MB, seconds
& .\Start-BeDDGame.ps1 -Instance 1.26.51.01-hi2                # starts it without bringing it forward
Connect-BeDD -PipeName BeDD-1.26.51.01-hi2   # the pipeName in that instance's config

A clone has its own mods\, logs, worlds and options. A few rules keep parallel runs from tripping over each other:

  • Give every instance its own lock file, and find your game by its instance folder, never just by the name Minecraft.Windows (or you close someone else's game).
  • Start games as Minecraft.Windows.exe (Start-BeDDGame.ps1 does): under another file name the game uses your normal Minecraft profile instead of the instance's.
  • Make test worlds single-player with Set-WorldSinglePlayer <worldDir> (from the harness shim): games on one PC share an online sign-in, and multiplayer worlds opened at the same time fail with "An error has occurred" (code "Blaze").
  • A run that joins a server online sets $script:ExclusiveSignaling = $true before Start-Game and gets the PC to itself while the other games close.

The manager window

The first Start-BeDDGame.ps1 of your logon session opens the manager window, and every later run (from any terminal, harness or agent) reuses it. Each headless game then shows up there as a live picture instead of as a window of its own: no taskbar buttons, nothing in Alt+Tab, no windows popping up and vanishing while several runs start and close games. It never takes the focus.

  • Each game is labelled with the project (and worktree) of the script that started it, its instance and pid, and whether input is arriving. -Label on Start-BeDDGame.ps1 names it.
  • Closing the manager window closes every game in it (it asks first). The games also go if the manager is killed, so nothing is left running in the background.
  • Double-click a game to show only that one. Right-click it to take it over with your own mouse and keyboard (and hand it back to the script), open its latest.log or instance folder, or close it.
  • From a script: BeDDManager.ps1 -List lists the games, -Game <pid> -Action show|hide|close does what the right-click menu does, -Shutdown closes the manager and every game without asking.

It needs PowerShell 7 (pwsh). Start-BeDDGame.ps1 -NoManager (or BEDD_MANAGER=0) starts a game without starting the manager, and Install-BeDDMod -NoManager (config "manager": false) keeps a game out of a running one, for example to record the real screen.

Plug it into a harness

harness-shim.ps1 replaces the usual helpers of LeviLauncher harnesses (Focus-Game, Assert-GameForeground, Set-GameWindowSize, Move-Mouse, Click, Scroll, Press-Key, Type-Text, Get-ClientBitmap, same parameters) and wraps Start-Game/Stop-Game:

. "$PSScriptRoot/lib.ps1"
if (-not $Foreground) {
    . "$beddDir\harness-shim.ps1"
    Register-BeDDNative ([MyE2E.Native])   # optional, see below
}
# after deploying your mod and moving the other mods aside:
if ($script:Headless) { Install-BeDDMod -ModsDir $script:ModsDir -PipeName 'BeDD-<instance>' }
# ... and in finally, once the game is closed:
if ($script:Headless) { Uninstall-BeDDMod -ModsDir $script:ModsDir }

Start games with Start-BeDDGame.ps1 rather than the launcher, and keep BeDD out of any "move other mods aside" step: it is installed fresh each run and removed afterwards (a leftover copy would make a normally started game ignore your mouse and keyboard).

If your scenarios call the harness's own input class directly ([MyE2E.Native]::Key(0x10, $false) and friends), give it these fields and a one-line guard at the top of each method; Register-BeDDNative fills them:

public static Action<ushort, bool> KeyRedirect;          // (vk, up)
public static Action<int, bool>    MouseButtonRedirect;  // (0 left / 1 right / 2 middle, up)
public static Action<int>          WheelRedirect;        // (delta, 120 per notch)
public static Action<char>         UnicodeRedirect;
public static Action<int, int>     MoveRelativeRedirect; // camera
public static void Key(ushort vk, bool up) { if (KeyRedirect != null) { KeyRedirect(vk, up); return; } /* SendInput as before */ }

BeetrootSkin and AlleviatedBackpacks have complete harnesses to copy from.

Settings

mods\BeDD\config\config.json, usually written by the harness (Install-BeDDMod does it). Without it the mod stays passive: background mode off, the pipe still answers. Install-BeDDMod and Start-BeDDGame.ps1 also switch the instance's LeviLamina to its built-in crash logger (modules.crashLogger.builtin in mods\LeviLamina\config\Config.json): the default CrashLogger.exe is a console program, and its console window would flash on the desktop at every game start.

{ "background": true, "placement": "back", "clientWidth": 1600, "clientHeight": 900, "pipeName": "BeDD" }
Key
backgroundkeep the game in the background and away from your real mouse and keyboard
placementback (behind your windows), offscreen or none
clientWidth, clientHeightgame window size (0 = leave it), so clicks land in the same place every run
pipeNameone per game instance when several run at once
loopbackOnlydefault true: the game stays on the PC, so no Windows Firewall prompt for each new instance, and game servers outside the PC are not queried (they could show up as "LAN worlds" ahead of your test world). Dedicated servers your harness starts still ask once per server folder; Cancel is fine
managerdefault true: in background mode the game shows up in the manager window when one runs, and its own window stays off screen and off the taskbar
mutedefault true: in background mode the game makes no sound (it is audible again while you take it over)
tracelog every input that reaches the game to logs\latest.log, for bug reports

More

More videos and pictures: https://levimc.org/mods/github.com/LiteLDev/BeDD/?tab=gallery

Building it yourself, the pipe protocol or how it works inside? See CONTRIBUTING.md.

License

LGPL-3.0-or-later © LeviMC. GameInput interface layouts follow Microsoft's public GameInput.h (v2); no Microsoft code is included.

Install Be.D.D.

Run this in your server folder with lip:

lip install github.com/LiteLDev/BeDD#client@0.3.1

On a client, install it through LeviLauncher

Download from GitHub