minecraft-gym 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. minecraft_gym-0.1.0/.gitattributes +3 -0
  2. minecraft_gym-0.1.0/.github/workflows/ci.yml +50 -0
  3. minecraft_gym-0.1.0/.gitignore +16 -0
  4. minecraft_gym-0.1.0/CONTRIBUTING.md +54 -0
  5. minecraft_gym-0.1.0/LICENSE +21 -0
  6. minecraft_gym-0.1.0/PKG-INFO +553 -0
  7. minecraft_gym-0.1.0/README.md +521 -0
  8. minecraft_gym-0.1.0/docs/farama-submission.md +42 -0
  9. minecraft_gym-0.1.0/docs/protocol.md +124 -0
  10. minecraft_gym-0.1.0/fabric/build.gradle +43 -0
  11. minecraft_gym-0.1.0/fabric/gradle/wrapper/gradle-wrapper.jar +0 -0
  12. minecraft_gym-0.1.0/fabric/gradle/wrapper/gradle-wrapper.properties +9 -0
  13. minecraft_gym-0.1.0/fabric/gradle.properties +11 -0
  14. minecraft_gym-0.1.0/fabric/gradlew +248 -0
  15. minecraft_gym-0.1.0/fabric/gradlew.bat +82 -0
  16. minecraft_gym-0.1.0/fabric/settings.gradle +12 -0
  17. minecraft_gym-0.1.0/fabric/src/client/java/dev/minecraftgym/bridge/BridgeLog.java +11 -0
  18. minecraft_gym-0.1.0/fabric/src/client/java/dev/minecraftgym/bridge/BridgeRuntime.java +465 -0
  19. minecraft_gym-0.1.0/fabric/src/client/java/dev/minecraftgym/bridge/BridgeServer.java +137 -0
  20. minecraft_gym-0.1.0/fabric/src/client/java/dev/minecraftgym/bridge/ControlState.java +224 -0
  21. minecraft_gym-0.1.0/fabric/src/client/java/dev/minecraftgym/bridge/MinecraftGymBridgeClient.java +34 -0
  22. minecraft_gym-0.1.0/fabric/src/client/java/dev/minecraftgym/bridge/ObservationEncoder.java +128 -0
  23. minecraft_gym-0.1.0/fabric/src/main/resources/fabric.mod.json +21 -0
  24. minecraft_gym-0.1.0/output/jupyter-notebook/minecraft-survival-gym-quickstart.ipynb +399 -0
  25. minecraft_gym-0.1.0/pyproject.toml +58 -0
  26. minecraft_gym-0.1.0/scripts/record_human.py +55 -0
  27. minecraft_gym-0.1.0/scripts/run_dev.sh +181 -0
  28. minecraft_gym-0.1.0/scripts/smoke_env.py +49 -0
  29. minecraft_gym-0.1.0/scripts/stop_dev.sh +100 -0
  30. minecraft_gym-0.1.0/src/minecraft_gym/__init__.py +19 -0
  31. minecraft_gym-0.1.0/src/minecraft_gym/actions.py +206 -0
  32. minecraft_gym-0.1.0/src/minecraft_gym/backend.py +166 -0
  33. minecraft_gym-0.1.0/src/minecraft_gym/env.py +177 -0
  34. minecraft_gym-0.1.0/src/minecraft_gym/recording.py +222 -0
  35. minecraft_gym-0.1.0/src/minecraft_gym/rewards.py +47 -0
  36. minecraft_gym-0.1.0/src/minecraft_gym/transport.py +208 -0
  37. minecraft_gym-0.1.0/tests/test_env.py +92 -0
  38. minecraft_gym-0.1.0/tests/test_recording.py +38 -0
  39. minecraft_gym-0.1.0/tests/test_transport.py +116 -0
  40. minecraft_gym-0.1.0/uv.lock +3082 -0
@@ -0,0 +1,3 @@
1
+ * text=auto
2
+ *.bat text eol=crlf whitespace=cr-at-eol
3
+ *.jar binary
@@ -0,0 +1,50 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ python:
14
+ name: Python ${{ matrix.python-version }}
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
20
+ steps:
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
24
+ with:
25
+ version: latest-known
26
+ enable-cache: true
27
+ - name: Install dependencies
28
+ run: uv sync --frozen --extra dev --python ${{ matrix.python-version }}
29
+ - name: Run tests
30
+ run: uv run --frozen --python ${{ matrix.python-version }} pytest
31
+ - name: Build distributions
32
+ if: matrix.python-version == '3.10'
33
+ run: uv build
34
+
35
+ fabric:
36
+ name: Fabric bridge
37
+ runs-on: ubuntu-latest
38
+ defaults:
39
+ run:
40
+ working-directory: fabric
41
+ steps:
42
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
43
+ - name: Set up JDK 21
44
+ uses: actions/setup-java@v5
45
+ with:
46
+ distribution: temurin
47
+ java-version: "21"
48
+ cache: gradle
49
+ - name: Build bridge mod
50
+ run: ./gradlew build --no-daemon
@@ -0,0 +1,16 @@
1
+ .venv/
2
+ .DS_Store
3
+ .idea/
4
+ .vscode/
5
+ .minecraft-gym/
6
+ AGENTS.md
7
+ sources/
8
+ __pycache__/
9
+ *.py[cod]
10
+ .pytest_cache/
11
+ .coverage
12
+ dist/
13
+ build/
14
+ datasets/
15
+ run/
16
+ fabric/.gradle/
@@ -0,0 +1,54 @@
1
+ # Contributing to Minecraft Survival Gym
2
+
3
+ Thank you for helping improve Minecraft Survival Gym. Contributions to the
4
+ Gymnasium API, Fabric bridge, documentation, tests, and research tooling are
5
+ welcome.
6
+
7
+ ## Development setup
8
+
9
+ Install the Python development environment from the repository root:
10
+
11
+ ```bash
12
+ uv sync --extra dev
13
+ ```
14
+
15
+ Run the test suite and the mock smoke test:
16
+
17
+ ```bash
18
+ uv run pytest
19
+ uv run python scripts/smoke_env.py --backend mock --steps 20
20
+ ```
21
+
22
+ The mock backend is the default choice for automated tests because it does not
23
+ require Minecraft. Changes to the real bridge should also be validated with
24
+ Minecraft Java 1.21, Fabric, and JDK 21.
25
+
26
+ Build the bridge with:
27
+
28
+ ```bash
29
+ cd fabric
30
+ ./gradlew build
31
+ ```
32
+
33
+ ## Pull requests
34
+
35
+ - Keep changes focused and include tests for observable behavior.
36
+ - Preserve the Gymnasium `reset()` and `step()` contracts.
37
+ - Update the protocol documentation when a bridge message changes.
38
+ - Do not commit Minecraft binaries, game assets, worlds, credentials, or
39
+ recorded data containing private information.
40
+ - Explain whether the change was tested with the mock backend, the real game,
41
+ or both.
42
+
43
+ ## Bug reports
44
+
45
+ Include minimal reproduction steps and the versions of Python, Gymnasium,
46
+ Minecraft, Fabric Loader, Fabric API, Java, and the operating system. Bridge
47
+ problems should include the relevant Minecraft and Python logs with secrets and
48
+ personal paths removed.
49
+
50
+ ## Environment compatibility
51
+
52
+ The canonical environment ID is `minecraft_gym/MinecraftSurvival-v0`.
53
+ `MinecraftSurvival-v0` is retained as a compatibility alias. Behavioral changes
54
+ that could invalidate benchmark comparisons require a new environment version.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rlsgarcia-code
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,553 @@
1
+ Metadata-Version: 2.5
2
+ Name: minecraft-gym
3
+ Version: 0.1.0
4
+ Summary: A Gymnasium environment and bridge protocol for controlling Minecraft Java Edition.
5
+ Project-URL: Homepage, https://github.com/rlsgarcia-code/Minecraft-Survival-Gym
6
+ Project-URL: Repository, https://github.com/rlsgarcia-code/Minecraft-Survival-Gym
7
+ Project-URL: Issues, https://github.com/rlsgarcia-code/Minecraft-Survival-Gym/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: embodied-ai,gymnasium,imitation-learning,minecraft,reinforcement-learning
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: gymnasium<2,>=1.1
23
+ Requires-Dist: numpy<3,>=1.26
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest<9,>=8; extra == 'dev'
26
+ Provides-Extra: notebook
27
+ Requires-Dist: ipykernel<8,>=6; extra == 'notebook'
28
+ Requires-Dist: jupyterlab<5,>=4; extra == 'notebook'
29
+ Requires-Dist: matplotlib<4,>=3.8; extra == 'notebook'
30
+ Requires-Dist: nbclient<1,>=0.10; extra == 'notebook'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Minecraft Survival Gym
34
+
35
+ > A Gymnasium environment for training reinforcement learning agents to survive in Minecraft Java, with visual observations, full player controls, and keyboard/mouse demonstration recording.
36
+
37
+ Minecraft Survival Gym connects Python policies to Minecraft Java 1.21 through a Fabric client mod and exposes the game as `minecraft_gym/MinecraftSurvival-v0`. It is designed as an experimental foundation for reinforcement learning, imitation learning, DAgger, and future VLM/LLM-driven objectives and rewards.
38
+
39
+ > [!IMPORTANT]
40
+ > This is an independent experimental project. It is not an official Minecraft product and is not affiliated with Mojang or Microsoft.
41
+
42
+ ## Features
43
+
44
+ - Gymnasium-compatible `reset()`, `step()`, `render()`, and `close()` API;
45
+ - RGB observations combined with structured player state;
46
+ - movement, camera, combat, item use, hotbar, and GUI actions;
47
+ - controlled simulation time with an exact number of ticks per action;
48
+ - agent, human, and DAgger control modes;
49
+ - atomic trajectory recording for behavior cloning and imitation learning;
50
+ - deterministic mock backend for development without Minecraft;
51
+ - pluggable reward functions decoupled from the game loop.
52
+
53
+ ## Architecture
54
+
55
+ ```text
56
+ RL policy / Human operator
57
+
58
+
59
+ MinecraftSurvivalEnv
60
+ (Gymnasium)
61
+ │ Local TCP / JSON
62
+
63
+ Fabric bridge mod
64
+
65
+
66
+ Minecraft Java — Survival
67
+
68
+ └── RGB + vitals + pose + inventory + events
69
+ ```
70
+
71
+ The bridge listens only on `127.0.0.1:25570`. Requests are processed sequentially to preserve the relationship between each action, the executed game ticks, and the returned observation.
72
+
73
+ ## Project status
74
+
75
+ The environment has been validated end to end against a real Minecraft client:
76
+
77
+ - Python-to-Fabric handshake;
78
+ - `128 × 128 × 3` RGB capture;
79
+ - exact four-tick advancement per action;
80
+ - player movement and camera rotation;
81
+ - DAgger execution;
82
+ - human episode recording;
83
+ - Gymnasium environment checker compliance;
84
+ - automated Python test suite.
85
+
86
+ ## Requirements
87
+
88
+ - Python 3.10 or newer;
89
+ - [`uv`](https://docs.astral.sh/uv/);
90
+ - JDK 21 — not only a JRE, and not Java 8 or 17;
91
+ - Minecraft Java Edition 1.21;
92
+ - Fabric Loader;
93
+ - Fabric API compatible with Minecraft 1.21.
94
+
95
+ ## Installation
96
+
97
+ ### 1. Clone the repository and install Python dependencies
98
+
99
+ ```bash
100
+ git clone https://github.com/rlsgarcia-code/Minecraft-Survival-Gym.git
101
+ cd Minecraft-Survival-Gym
102
+ uv sync --extra dev
103
+ ```
104
+
105
+ Verify the Gymnasium API without launching Minecraft:
106
+
107
+ ```bash
108
+ uv run python scripts/smoke_env.py --backend mock --steps 20
109
+ ```
110
+
111
+ ### 2. Select JDK 21
112
+
113
+ Check the active Java version:
114
+
115
+ ```bash
116
+ java -version
117
+ ```
118
+
119
+ The first line must report Java 21. On macOS with Homebrew:
120
+
121
+ ```bash
122
+ brew install openjdk@21
123
+ export JAVA_HOME="$(brew --prefix openjdk@21)/libexec/openjdk.jdk/Contents/Home"
124
+ export PATH="$JAVA_HOME/bin:$PATH"
125
+ java -version
126
+ ```
127
+
128
+ To keep this configuration across terminal sessions, add the two `export` lines to `~/.zshrc`.
129
+
130
+ ### 3. Build the Fabric mod
131
+
132
+ ```bash
133
+ cd fabric
134
+ ./gradlew build
135
+ cd ..
136
+ ```
137
+
138
+ The mod artifact is written to:
139
+
140
+ ```text
141
+ fabric/build/libs/minecraft-gym-bridge-0.1.0.jar
142
+ ```
143
+
144
+ ## Running the real environment
145
+
146
+ The real backend requires **two terminals plus the Minecraft window**:
147
+
148
+ | Component | Purpose | Must remain open? |
149
+ |---|---|---|
150
+ | Terminal 1 | launches Minecraft with the Fabric bridge | yes |
151
+ | Minecraft window | hosts the loaded single-player world | yes |
152
+ | Terminal 2 | runs the Python Gymnasium environment | while the agent is running |
153
+
154
+ Starting Minecraft is not enough: you must enter a single-player world and wait until the player HUD and terrain are visible before calling `env.reset()`.
155
+
156
+ ### One-command development launcher
157
+
158
+ The helper script starts both Terminal 1 services in the background: the
159
+ Minecraft Fabric development client and JupyterLab with the test notebook.
160
+
161
+ ```bash
162
+ ./scripts/run_dev.sh
163
+ ```
164
+
165
+ The script detects a Homebrew JDK 21 installation automatically, stores PID
166
+ files under `.minecraft-gym/`, opens JupyterLab, and writes service logs to:
167
+
168
+ ```text
169
+ .minecraft-gym/logs/minecraft.log
170
+ .minecraft-gym/logs/jupyter.log
171
+ ```
172
+
173
+ After it starts, enter a single-player Survival world in the Minecraft window.
174
+ The script cannot select a world on your behalf unless a development save name
175
+ is explicitly provided:
176
+
177
+ ```bash
178
+ MINECRAFT_GYM_QUICK_PLAY_WORLD=MyWorld ./scripts/run_dev.sh
179
+ ```
180
+
181
+ `MyWorld` must already exist under `fabric/run/saves/`. To inspect what would
182
+ be launched without starting processes:
183
+
184
+ ```bash
185
+ ./scripts/run_dev.sh --dry-run
186
+ ```
187
+
188
+ Stop both Minecraft and JupyterLab with:
189
+
190
+ ```bash
191
+ ./scripts/stop_dev.sh
192
+ ```
193
+
194
+ The stop script terminates only the process trees recorded by the launcher and
195
+ preserves the logs for debugging.
196
+
197
+ ### Option A — development client
198
+
199
+ This is the quickest way to run the project during development.
200
+
201
+ #### Terminal 1: start Minecraft
202
+
203
+ From the repository root:
204
+
205
+ ```bash
206
+ export JAVA_HOME="$(brew --prefix openjdk@21)/libexec/openjdk.jdk/Contents/Home"
207
+ export PATH="$JAVA_HOME/bin:$PATH"
208
+
209
+ cd fabric
210
+ ./gradlew runClient
211
+ ```
212
+
213
+ Leave Terminal 1 running. A separate Minecraft window will open.
214
+
215
+ #### Minecraft window: open a world
216
+
217
+ 1. Click **Singleplayer**.
218
+ 2. Create or open a world.
219
+ 3. Make sure the player is in **Survival** mode.
220
+ 4. Wait until the terrain and player HUD are fully visible.
221
+ 5. Leave Minecraft open inside the world.
222
+
223
+ The title screen does not satisfy this requirement. If Python connects while Minecraft is still at the title screen, the bridge returns:
224
+
225
+ ```text
226
+ Open a single-player world before using the bridge
227
+ ```
228
+
229
+ #### Terminal 2: run the Gym environment
230
+
231
+ Open a new terminal and return to the repository root:
232
+
233
+ ```bash
234
+ cd /path/to/Minecraft-Survival-Gym
235
+ uv run python scripts/smoke_env.py --steps 20
236
+ ```
237
+
238
+ Do not close Terminal 1 or the Minecraft window while this command is running.
239
+
240
+ A successful run starts with output similar to:
241
+
242
+ ```text
243
+ reset tick=... seed=... rgb=(128, 128, 3)
244
+ step=1 tick=... reward=... terminated=False truncated=False
245
+ ```
246
+
247
+ ### Option B — regular Minecraft installation
248
+
249
+ 1. Install Fabric Loader for Minecraft 1.21.
250
+ 2. Place Fabric API in that installation's `mods` directory.
251
+ 3. Copy `fabric/build/libs/minecraft-gym-bridge-0.1.0.jar` into the same `mods` directory.
252
+ 4. Launch Minecraft with the Fabric profile.
253
+ 5. Enter a single-player Survival world and wait for it to finish loading.
254
+ 6. Run the Python command from Terminal 2 as shown above.
255
+
256
+ ## Test notebook
257
+
258
+ The repository includes a guided notebook that validates observation shapes,
259
+ renders an RGB frame, executes a controlled action, checks tick advancement,
260
+ and optionally connects to the real Fabric bridge:
261
+
262
+ [`output/jupyter-notebook/minecraft-survival-gym-quickstart.ipynb`](output/jupyter-notebook/minecraft-survival-gym-quickstart.ipynb)
263
+
264
+ Launch it from the repository root:
265
+
266
+ ```bash
267
+ uv run --extra notebook jupyter lab \
268
+ output/jupyter-notebook/minecraft-survival-gym-quickstart.ipynb
269
+ ```
270
+
271
+ The notebook uses the mock backend by default, so **Run All** is safe without
272
+ Minecraft. For the real test, keep Terminal 1 running `./gradlew runClient`,
273
+ enter a loaded single-player world, and then set `REAL_BACKEND = True` in the
274
+ notebook.
275
+
276
+ ## Basic usage
277
+
278
+ ```python
279
+ import gymnasium as gym
280
+ import minecraft_gym # registers the environment
281
+
282
+ env = gym.make(
283
+ "minecraft_gym/MinecraftSurvival-v0",
284
+ backend="socket",
285
+ width=128,
286
+ height=128,
287
+ frame_skip=4,
288
+ max_episode_steps=9_000,
289
+ control_mode="agent",
290
+ render_mode="rgb_array",
291
+ )
292
+
293
+ observation, info = env.reset(seed=42)
294
+
295
+ terminated = False
296
+ truncated = False
297
+
298
+ while not (terminated or truncated):
299
+ action = env.action_space.sample()
300
+ observation, reward, terminated, truncated, info = env.step(action)
301
+
302
+ env.close()
303
+ ```
304
+
305
+ Use `backend="mock"` for fast and deterministic tests that do not require Minecraft.
306
+
307
+ `MinecraftSurvival-v0` remains available as a compatibility alias. New code
308
+ should use the namespaced ID to avoid collisions with other third-party
309
+ environment packages.
310
+
311
+ ## Action space
312
+
313
+ The action space is a 15-component `gymnasium.spaces.MultiDiscrete`:
314
+
315
+ ```text
316
+ MultiDiscrete([3, 3, 2, 2, 2, 2, 2, 2, 2, 5, 5, 10, 5, 5, 3])
317
+ ```
318
+
319
+ The value `0` is `NOOP` for every component.
320
+
321
+ | Index | Control | Values |
322
+ |---:|---|---|
323
+ | 0 | Strafe | idle, left, right |
324
+ | 1 | Movement | idle, forward, backward |
325
+ | 2 | Jump | no, yes |
326
+ | 3 | Sprint | no, yes |
327
+ | 4 | Sneak | no, yes |
328
+ | 5 | Attack | no, yes |
329
+ | 6 | Use | no, yes |
330
+ | 7 | Inventory | keep, toggle |
331
+ | 8 | Drop item | no, yes |
332
+ | 9 | Horizontal camera | neutral, ±6°, ±18° |
333
+ | 10 | Vertical camera | neutral, ±6°, ±18° |
334
+ | 11 | Hotbar | keep or select slots 1–9 |
335
+ | 12 | Horizontal GUI cursor | neutral, slow, or fast in either direction |
336
+ | 13 | Vertical GUI cursor | neutral, slow, or fast in either direction |
337
+ | 14 | GUI click | none, primary, secondary |
338
+
339
+ The canonical `ControlState` retains continuous mouse deltas. Human demonstrations therefore preserve more information than the discrete projection used by the initial policy space.
340
+
341
+ ## Observation space
342
+
343
+ The environment returns a `gymnasium.spaces.Dict`:
344
+
345
+ | Field | Type and shape | Contents |
346
+ |---|---|---|
347
+ | `rgb` | `uint8[H, W, 3]` | rendered RGB frame |
348
+ | `vitals` | `float32[8]` | health, hunger, armor, air, XP, and body flags |
349
+ | `pose` | `float32[10]` | position, velocity, camera, ground contact, and fall state |
350
+ | `inventory_ids` | `int32[36]` | item registry identifiers |
351
+ | `inventory_counts` | `int32[36]` | item count for each slot |
352
+ | `equipped_slot` | `Discrete(9)` | selected hotbar slot |
353
+ | `ui_mode` | `Discrete(8)` | gameplay, inventory, container, chat, death, or other screen |
354
+
355
+ The `info` dictionary includes:
356
+
357
+ - current tick and actual world seed;
358
+ - events such as damage, death, and inventory increases;
359
+ - individual reward terms;
360
+ - `policy_action`, `human_action`, and `executed_action`;
361
+ - `control_source`, indicating whether the agent or a human controlled the step.
362
+
363
+ ## Control modes
364
+
365
+ | Mode | Behavior |
366
+ |---|---|
367
+ | `agent` | executes only the action supplied by the policy |
368
+ | `human` | ignores the policy action and records keyboard/mouse input |
369
+ | `dagger` | uses the policy by default and accepts human intervention |
370
+
371
+ ### Recording demonstrations
372
+
373
+ Keep Minecraft focused and inside a loaded world. In Terminal 2, run:
374
+
375
+ ```bash
376
+ uv run python scripts/record_human.py \
377
+ --mode human \
378
+ --steps 9000 \
379
+ --output datasets/demonstrations
380
+ ```
381
+
382
+ To collect human corrections during policy execution:
383
+
384
+ ```bash
385
+ uv run python scripts/record_human.py \
386
+ --mode dagger \
387
+ --steps 9000 \
388
+ --output datasets/dagger
389
+ ```
390
+
391
+ Each episode produces a compressed `.npz` archive and a `.json` metadata file. Episodes are committed atomically to reduce the chance of partially written datasets.
392
+
393
+ Main arrays:
394
+
395
+ | Field | Purpose |
396
+ |---|---|
397
+ | `actions` | action originally submitted to the environment |
398
+ | `policy_actions` | policy action projected onto the discrete action space |
399
+ | `human_actions` | human action projected onto the discrete action space |
400
+ | `executed_actions` | action actually executed by the game |
401
+ | `policy_controls` | continuous canonical policy controls |
402
+ | `human_controls` | keyboard state and continuous mouse deltas |
403
+ | `executed_controls` | canonical controls actually applied |
404
+ | `human_action_present` | mask indicating human action availability/intervention |
405
+
406
+ > [!NOTE]
407
+ > Locking the screen does not prevent Python-only tests or training, but Minecraft may stop rendering. RGB capture and physical keyboard/mouse demonstrations require an unlocked graphical session.
408
+
409
+ ## Rewards
410
+
411
+ The default reward is deliberately conservative:
412
+
413
+ - a small reward for remaining alive;
414
+ - a penalty proportional to health lost;
415
+ - a larger penalty for death.
416
+
417
+ A different strategy can be injected without modifying the environment:
418
+
419
+ ```python
420
+ from minecraft_gym import MinecraftSurvivalEnv
421
+ from minecraft_gym.rewards import RewardResult
422
+
423
+
424
+ class MyReward:
425
+ def __call__(self, previous, transition):
426
+ collected = sum(
427
+ event.get("count", 0)
428
+ for event in transition.events
429
+ if event.get("type") == "inventory_increased"
430
+ )
431
+ return RewardResult(
432
+ total=float(collected),
433
+ terms={"collected_items": float(collected)},
434
+ )
435
+
436
+
437
+ env = MinecraftSurvivalEnv(reward_function=MyReward())
438
+ ```
439
+
440
+ This separation makes it possible to experiment with VLM/LLM-generated semantic rewards, intermediate objectives, and knowledge retrieved from survival guides without coupling those experiments to the Minecraft bridge.
441
+
442
+ ## Time and episode semantics
443
+
444
+ During a Gym session, the bridge freezes the integrated server and advances exactly `frame_skip` ticks for each `step()` call.
445
+
446
+ - `terminated=True`: the player died;
447
+ - `truncated=True`: an operational limit such as `max_episode_steps` was reached.
448
+
449
+ ### Reset behavior
450
+
451
+ The current version implements a **soft reset**. It:
452
+
453
+ - forces Survival mode;
454
+ - returns the player to the session's initial position;
455
+ - clears inventory and status effects;
456
+ - restores health, hunger, and saturation;
457
+ - restores time and weather.
458
+
459
+ The reset does not yet rebuild modified blocks or change the seed of the currently loaded world. `requested_seed_matches_world` reports whether the requested seed matches the actual world seed. For experiments requiring identical terrain, start each batch from a clean copy of the save.
460
+
461
+ ## Environment configuration
462
+
463
+ | Parameter | Default | Description |
464
+ |---|---:|---|
465
+ | `backend` | `"socket"` | real backend or `"mock"` |
466
+ | `host` | `127.0.0.1` | bridge address |
467
+ | `port` | `25570` | local TCP port |
468
+ | `bridge_timeout` | `30.0` | connection timeout in seconds |
469
+ | `width` | `128` | RGB observation width |
470
+ | `height` | `128` | RGB observation height |
471
+ | `frame_skip` | `4` | ticks executed per action |
472
+ | `max_episode_steps` | `9000` | internal episode limit |
473
+ | `control_mode` | `"agent"` | `agent`, `human`, or `dagger` |
474
+ | `render_mode` | `None` | use `"rgb_array"` for `render()` |
475
+ | `reward_function` | sparse survival | pluggable reward strategy |
476
+
477
+ ## Troubleshooting
478
+
479
+ ### `Gradle requires JVM 17 or later` / `configured to use JVM 8`
480
+
481
+ Gradle found an older Java installation. Select JDK 21 before running the wrapper:
482
+
483
+ ```bash
484
+ export JAVA_HOME="$(brew --prefix openjdk@21)/libexec/openjdk.jdk/Contents/Home"
485
+ export PATH="$JAVA_HOME/bin:$PATH"
486
+ java -version
487
+
488
+ cd fabric
489
+ ./gradlew build
490
+ ```
491
+
492
+ ### `ConnectionRefusedError: [Errno 61] Connection refused`
493
+
494
+ The Python package could not find the bridge at `127.0.0.1:25570`. Confirm that:
495
+
496
+ 1. Terminal 1 is still running `./gradlew runClient`, or Minecraft was launched from a Fabric installation containing the bridge mod;
497
+ 2. the Minecraft process has finished starting;
498
+ 3. no other process is using port `25570`.
499
+
500
+ ### `Open a single-player world before using the bridge`
501
+
502
+ Python successfully connected to the mod, but Minecraft is still at the title screen or not fully inside a world. In the Minecraft window, click **Singleplayer**, load or create a world, wait for the player HUD and terrain to appear, and then rerun the Python command from Terminal 2.
503
+
504
+ The `--backend mock` smoke test neither launches Minecraft nor tests the Fabric connection.
505
+
506
+ ## Development
507
+
508
+ Run the Python test suite:
509
+
510
+ ```bash
511
+ uv run pytest
512
+ ```
513
+
514
+ Build and validate the Fabric mod:
515
+
516
+ ```bash
517
+ cd fabric
518
+ ./gradlew build
519
+ ```
520
+
521
+ Repository structure:
522
+
523
+ ```text
524
+ src/minecraft_gym/ environment, actions, rewards, recorder, and transport
525
+ fabric/ Fabric mod and local bridge
526
+ scripts/smoke_env.py real or simulated smoke test
527
+ scripts/record_human.py human demonstration collection
528
+ scripts/run_dev.sh start Minecraft and JupyterLab
529
+ scripts/stop_dev.sh stop the development session
530
+ tests/ Gym contract and protocol tests
531
+ docs/protocol.md TCP protocol specification
532
+ ```
533
+
534
+ ## Roadmap
535
+
536
+ - hard resets and automatic world restoration;
537
+ - vectorized environments and multiple Minecraft instances;
538
+ - hierarchical and temporal action wrappers;
539
+ - behavior cloning and reinforcement learning baselines;
540
+ - VLM-based reward evaluation and generation;
541
+ - language-model subgoal planning with survival-guide retrieval;
542
+ - demonstration inspection, replay, and curation tools.
543
+
544
+ ## Protocol
545
+
546
+ The bridge specification is available in [`docs/protocol.md`](docs/protocol.md).
547
+
548
+ ## Contributing
549
+
550
+ Issues and pull requests are welcome. See [`CONTRIBUTING.md`](CONTRIBUTING.md)
551
+ for the development workflow. When reporting a problem, include the Minecraft,
552
+ Fabric Loader, Fabric API, Java, and operating system versions, along with
553
+ minimal reproduction steps.