CLI¶
Entry Point¶
This page describes the main command-line entry points for data collection: run.sh (training data) and run_evals.sh (evaluation data).
run.sh¶
Runs the full training data collection pipeline. It works sequentially in batches. For each batch, it generates compose configs, starts Minecraft instances, collects episodes, and postprocesses them. When all batches are ready, it transforms, validates, and combines all of them into the final training dataset.
Usage¶
./run.sh [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
|
Base data directory for outputs |
|
|
Number of batches to run |
|
|
Number of flat worlds per batch |
|
|
Number of normal worlds per batch |
|
|
Number of episodes per batch |
|
|
Name of the output dataset under |
|
|
Whether to detect and exclude water episodes from the train dataset (see Water filtering) |
|
Show usage and exit |
Water filtering¶
When --filter-water-episodes true (the default), the script:
After all batches complete, runs detect_water_episodes_batch.py to detect episodes where either Alpha or Bravo shows underwater indicators (oxygen bar HUD). Results are written to
<output-dir>/data_collection/train/water_episodes.json.After
prepare_train_dataset.pyruns, runs filter_dataset.py to move detected water episodes into a<output-dir>/datasets/<dataset-name>/discarded/subdirectory, excluding them from the train dataset.
Use --filter-water-episodes false to skip detection and filtering and keep all episodes.
Output layout¶
Data is written under <output-dir>/. The following tree shows the directory structure:
<output-dir>/
├── data_collection/
│ └── train/
│ ├── batch_<batch_id>/
│ │ ├── aligned/
│ │ │ ├── <timestep>_<episode_id>_Alpha_instance_<instance_id>_camera.mp4
│ │ │ ├── <timestep>_<episode_id>_Alpha_instance_<instance_id>_camera_meta.json
│ │ │ ├── <timestep>_<episode_id>_Bravo_instance_<instance_id>_camera.mp4
│ │ │ ├── <timestep>_<episode_id>_Bravo_instance_<instance_id>_camera_meta.json
│ │ │ └── ... (other episodes)
│ │ ├── camera/
│ │ │ ├── data_alpha/
│ │ │ │ └── <instance_id>/
│ │ │ ├── data_bravo/
│ │ │ │ └── <instance_id>/
│ │ │ ├── output_alpha/
│ │ │ │ └── <instance_id>/
│ │ │ │ ├── camera_alpha.mkv
│ │ │ │ └── camera_alpha_meta.json
│ │ │ └── output_bravo/
│ │ │ └── <instance_id>/
│ │ ├── compose_configs/
│ │ │ ├── docker-compose-<instance_id>.yml
│ │ │ └── ... (one per instance)
│ │ ├── data/
│ │ │ └── <instance_id>/
│ │ ├── logs/
│ │ │ └── docker-compose-<instance_id>/
│ │ │ ├── controller_alpha_instance_<instance_id>.log
│ │ │ ├── controller_bravo_instance_<instance_id>.log
│ │ │ ├── camera_alpha_instance_<instance_id>.log
│ │ │ ├── camera_bravo_instance_<instance_id>.log
│ │ │ ├── act_recorder_alpha_instance_<instance_id>.log
│ │ │ ├── act_recorder_bravo_instance_<instance_id>.log
│ │ │ ├── mc_instance_<instance_id>.log
│ │ │ └── ...
│ │ └── output/
│ │ ├── <timestep>_<episode_id>_Alpha_instance_<instance_id>.json
│ │ ├── <timestep>_<episode_id>_Alpha_instance_<instance_id>_meta.json
│ │ ├── <timestep>_<episode_id>_Alpha_instance_<instance_id>_episode_info.json
│ │ ├── <timestep>_<episode_id>_Bravo_instance_<instance_id>.json
│ │ ├── <timestep>_<episode_id>_Bravo_instance_<instance_id>_meta.json
│ │ ├── <timestep>_<episode_id>_Bravo_instance_<instance_id>_episode_info.json
│ │ └── ... (other episodes)
│ └── water_episodes.json
└── datasets/
└── <dataset-name>/
├── train/
│ ├── batch_<batch_id>_<episode_id>_Alpha_instance_<instance_id>.mp4
│ ├── batch_<batch_id>_<episode_id>_Alpha_instance_<instance_id>.json
│ ├── batch_<batch_id>_<episode_id>_Alpha_instance_<instance_id>_episode_info.json
│ ├── batch_<batch_id>_<episode_id>_Bravo_instance_<instance_id>.mp4
│ ├── batch_<batch_id>_<episode_id>_Bravo_instance_<instance_id>.json
│ ├── batch_<batch_id>_<episode_id>_Bravo_instance_<instance_id>_episode_info.json
│ └── ... (other episodes)
├── test/
│ └── (same file patterns as train/)
├── annotated/
│ └── batch_<batch_id>_<episode_id>_instance_<instance_id>.mp4_combined.mp4
└── discarded/
└── (water episodes moved here)
Path (relative to |
Description |
|---|---|
|
Per-episode aligned camera videos and metadata: |
|
Minecraft client home directories for camera bots. Contains |
|
Raw camera recordings and metadata: |
|
Generated Docker Compose file. Produced by generate_compose.py. |
|
Minecraft server data (world, config, logs). |
|
Docker logs for every service: controller, camera, act_recorder, mc, spectator, etc. |
|
Controller actions (see Action file format): |
|
(When water filtering enabled) List of detected water episodes for filter_dataset.py. |
|
Prepared splits: |
|
Debug videos with overlaid actions (Alpha+Bravo concatenated). Produced by annotate_video_batch.py. |
|
Episodes excluded by water filtering (when enabled). |
Action file format¶
Action files (*_Alpha_instance_*.json, *_Bravo_instance_*.json) contain a JSON array of per-frame objects, one per timestep:
[
{
"x": -4425.5,
"y": 64,
"z": 2298.5,
"yaw": 4.636,
"pitch": 0,
"action": {
"forward": false,
"back": false,
"left": false,
"right": false,
"jump": false,
"sprint": false,
"sneak": false,
"camera": [0, 0],
"attack": false,
"use": false,
"mount": false,
"dismount": false,
"place_block": false,
"place_entity": false,
"mine": false,
"hotbar.1": false,
"hotbar.2": false,
"hotbar.3": false,
"hotbar.4": false,
"hotbar.5": false,
"hotbar.6": false,
"hotbar.7": false,
"hotbar.8": false,
"hotbar.9": false
},
"inventory": {
"quickBarSlot": 4,
"mainInventory": [],
"heldItem": null,
"offHandItem": null,
"hotbar": [
{
"type": 1,
"count": 64,
"name": "stone",
"displayName": "Stone",
"slot": 36
},
{
"type": 840,
"count": 1,
"name": "diamond_pickaxe",
"displayName": "Diamond Pickaxe",
"slot": 37
}
]
},
"renderTime": 1770812761734,
"physicsTime": 276613.613413,
"relativeTimeMs": 0.0,
"epochTime": 1770812761.734,
"worldAgeTicks": 5649,
"isInWater": false,
"frame_count": 0,
"episode_id": 0,
"extra_info": {
"seed": 42
}
}
]
The array contains one such object per frame.
Episode info file format¶
Episode info files (*_episode_info.json) contain a single JSON object:
{
"timestamp": "2026-02-11T12:25:11.506Z",
"bot_name": "Alpha",
"world_type": "normal",
"episode_number": 0,
"episode_type": "mine",
"instance_id": 1,
"encountered_error": false,
"peer_encountered_error": false,
"bot_died": false,
"episode_recording_started": true,
"eval_metadata": {}
}
run_evals.sh¶
Runs evaluation data collection for several episode types. It works sequentially per episode type, where an episode type acts as a batch. Just as in run.sh, for each batch, it generates compose configs, starts Minecraft instances, collects episodes, and postprocesses them. When all batches are ready, it prepares each batch (episode type)into a separate evaluation dataset.
Usage¶
./run_evals.sh [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
|
Base data directory for outputs |
|
Show usage and exit |
Environment¶
EVAL_TIME_SET_DAY— If set (e.g.1), episode start time is set to day for all eval episodes. Default:1.
Eval episode types¶
The script runs one batch per eval type:
rotationEvaltranslationEvalstructureEvalturnToLookEvalturnToLookOppositeEvalbothLookAwayEvaloneLooksAwayEval
For turnToLookEval and turnToLookOppositeEval the script uses 1 normal world and 32 episodes; for the rest, it uses 2 flatland worlds and 16 episodes per type.
Output layout¶
Data is written under <output-dir>/. The following tree shows the directory structure:
<output-dir>/
├── data_collection/
│ └── eval/
│ ├── rotationEval/
│ │ └── ...
│ ├── translationEval/
│ │ └── ...
│ ├── structureEval/
│ │ └── ...
│ └── ... (other eval types)
└── datasets/
└── eval/
├── rotationEval/
│ └── test/
│ └── ...
├── translationEval/
│ └── test/
│ └── ...
├── structureEval/
│ └── test/
│ └── ...
└── ... (other eval types)
Path (relative to |
Description |
|---|---|
|
Per-type batch directory. Structure under each |
|
Prepared eval datasets per type. Each |
Postprocessing¶
This section covers the postprocessing utilities that run as part of run.sh and run_evals.sh, and turn raw camera recordings and action files into final train/eval datasets and optional annotated videos.
process_recordings.py¶
Aligns raw Minecraft camera recordings with Mineflayer action episode files for a single bot, producing per-episode aligned camera videos. It can operate on a full directory of episodes or a single episode file.
Usage¶
python postprocess/process_recordings.py --actions-dir ACTIONS_DIR --camera-prefix CAMERA_DIR --bot {Alpha,Bravo} [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
Directory containing Mineflayer action files ( |
|
(required) |
Directory containing camera outputs (expects |
|
(required) |
Which bot to process. |
|
|
Base directory for aligned videos and metadata. |
|
|
Process a single episode JSON instead of scanning |
Output layout¶
<output-dir>/<episode>_camera.mp4— aligned camera video per episode.<output-dir>/<episode>_camera_meta.json— alignment metadata and diagnostics (including per‑frame mappings and quality stats).
detect_water_episodes_batch.py¶
Batch detects water episodes by detecting the oxygen bar HUD element in video frames. Uses multiprocessing to process all video files in all batch directories under a base path. Episodes are processed as Alpha‑Bravo pairs: if either video shows underwater indicators (oxygen bar), the entire pair is classified as a water episode. Outputs per‑batch JSON files and an aggregated water episodes list suitable for filter_dataset.py.
Usage¶
python postprocess/detect_water_episodes_batch.py --base-path BASE_PATH [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
Base path containing batch folders (each with an |
|
|
Cosine similarity threshold for water detection (oxygen bar match). |
|
|
Maximum number of frames to sample per video. |
|
CPU count |
Number of worker processes. |
|
|
Top N percentile for similarity thresholding (e.g. 10 = top 10%). |
|
|
Output path for aggregated water episodes JSON (list of |
Output layout¶
Per batch:
<batch_folder>/water_episodes.json— categorized water/non‑water episodes and metadata.Aggregated:
<out-path>— flat list of water episode keys for use by filter_dataset.py.
filter_dataset.py¶
Filters a multiplayer dataset by moving selected episodes into a discarded/ subdirectory. Expects a JSON list of episode keys (typically from detect_water_episodes_batch.py) with batch_id, episode_id, and instance_id. File names in the dataset directory must encode these fields, e.g. batch_0_000058_Bravo_instance_001_episode_info.json.
Usage¶
python postprocess/filter_dataset.py --episodes-json PATH dataset_dir
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
Path to JSON file with list of objects containing |
|
(required) |
Dataset directory containing files such as |
Output layout¶
Matching files are moved from <dataset_dir>/ into <dataset_dir>/discarded/. Only top‑level files are considered; subdirectories are ignored.
prepare_train_dataset.py¶
Validates and consolidates aligned camera videos and action JSONs into a single final dataset directory for training. It filters for episodes where both Alpha and Bravo have consistent video/action pairs and enforces one‑to‑one alignment between frames and actions.
Usage¶
python postprocess/prepare_train_dataset.py --source-dir SOURCE_DIR --destination-dir DEST_DIR [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
Directory that contains one or more episode runs with |
|
|
Optional list of instance IDs to include (space‑ or comma‑separated). |
|
|
Optional prefix prepended to destination filenames. |
|
(required) |
Target directory where the consolidated final dataset is written. |
|
|
Name used to identify the first bot in file paths. |
|
|
Name used to identify the second bot in file paths. |
Output layout¶
All validated per‑episode files (videos and JSONs for both players) are copied into <destination-dir>/ with timestamp prefixes stripped and an optional prefix applied. Only episodes where frame counts match action counts for both bots are included.
split_train_test.py¶
Splits a consolidated final dataset directory into train/test splits.
Usage¶
python postprocess/split_train_test.py FINAL_DIR [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
Path to final dataset produced by |
|
|
Percentage of (episode, instance) keys assigned to the test split. |
|
|
Random seed for deterministic splitting. |
|
|
Print the planned split without moving any files. |
Output layout¶
Creates <final_dir>/train/ and <final_dir>/test/ and moves entire episode‑instance groups into one of the two subdirectories.
prepare_eval_datasets.py¶
Prepares evaluation datasets from aligned eval episodes, mirroring the structure expected by Solaris model code. It filters, validates, and reshapes eval episodes into a unified directory layout.
Usage¶
python postprocess/prepare_eval_datasets.py --source-dir SOURCE_DIR --destination-dir DEST_DIR [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
Directory with eval runs (aligned videos and action JSONs). |
|
(required) |
Output directory for prepared eval datasets. |
annotate_video_batch.py¶
Batch annotates aligned camera videos with overlaid action information and vertically concatenates Alpha/Bravo views into a single debug video per episode. It can run on a single videos directory or over multiple subdirectories and supports parallel processing.
Usage¶
python postprocess/annotate_video_batch.py VIDEOS_DIR [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
Directory that has |
|
|
Number of parallel workers. |
|
|
Where to write annotated videos (per directory or per subdirectory). |
|
|
Maximum number of video pairs to process (stratified across instances). |
Output layout¶
Writes combined debug videos (Alpha on top, Bravo on bottom) under an annotated/ subdirectory (or the directory specified via --output-dir).
Docker Orchestration¶
This section documents the Python tools that generate and orchestrate the Docker Compose instances used by run.sh/run_evals.sh.
generate_compose.py¶
Generates multiple Docker Compose files, each describing a full ``SolarisEngine``(Minecraft server, controller bots, camera bots, spectators, and helper containers) for a single instance. It supports mixed flat/normal worlds, GPU‑backed camera rendering, and a wide range of episode customization options.
Usage¶
python generate_compose.py --data-dir DATA_DIR --output_dir OUTPUT_DIR \
--camera_output_alpha_base ALPHA_OUT --camera_output_bravo_base BRAVO_OUT [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
|
Number of instances to generate when world counts are not overridden. |
|
|
Number of flat‑world instances (overrides |
|
|
Number of normal‑world instances (overrides |
|
|
Directory to store generated |
|
|
Base Minecraft server port (one per instance, contiguous range). |
|
|
Base RCON port (one per instance, contiguous range). |
|
|
Act recorder port used inside the bridge network. |
|
|
Coordination port used by controller bots. |
|
(required) |
Base directory for per‑instance Minecraft server data. |
|
(required) |
Shared output directory for controller/act_recorder episode outputs. |
|
(required) |
Absolute base directory for per‑instance Camera Alpha outputs. |
|
(required) |
Absolute base directory for per‑instance Camera Bravo outputs. |
|
project default |
Base directory for Camera Alpha home/data (defaults under |
|
project default |
Base directory for Camera Bravo home/data (defaults under |
|
|
Number of episodes to run per instance. |
|
|
Starting episode ID. |
|
|
Time for servers/plugins to bootstrap before controllers start. |
|
|
High‑level episode category name. |
|
|
Comma‑separated episode types for controllers. |
|
|
Disable viewer rendering for controller/act_recorder (recommended for speed). |
|
|
If set, enable smoke‑test mode that exercises all episode types. |
|
|
If set, force eval episodes to start at day time. |
|
|
Disable structure generation in flat worlds. |
|
|
Minecraft render distance (chunks) for camera clients. |
|
|
Minecraft simulation distance (chunks). |
|
|
Minecraft graphics mode (Fast, Fancy, Fabulous). |
|
|
GPU rendering mode for camera containers. |
Output layout¶
<compose_dir>/docker-compose-XXX.yml— one Docker Compose file per instance.Per‑instance data and camera output/data directories are created under
--data_dirand the camera base paths;--output_diris created as the shared controller output root.
orchestrate.py¶
Orchestrates one or more generated Docker Compose instances produced by generate_compose.py. The script starts/stops them, captures logs, inspects status, and optionally runs postprocessing over their outputs.
Usage¶
python orchestrate.py {start,stop,status,logs,postprocess} [OPTIONS]
Options¶
Option |
Default |
Description |
|---|---|---|
|
(required) |
One of |
|
|
Directory containing the |
|
|
If set with |
|
|
Directory where per‑service logs are stored. |
|
|
Filter for a subset of instances when showing logs. |
|
|
Follow logs (for the |
|
|
Number of lines to show from saved logs. |
|
|
Parallel workers for the |
|
|
When running |
|
|
Extra logging for |
|
|
Base |
Behavior summary¶
start— starts all compose instances in parallel, waits for controller completion, captures per‑service logs, then shuts everything down.stop— stops all running instances and tears down volumes.status— reports how many instances have running containers.logs— tails saved per‑service logs (or falls back todocker compose logsif none are saved yet).postprocess— runs camera alignment over all episodes under a given--output-dirusing the postprocessing pipeline.