|
| 1 | +Craftax |
| 2 | +======== |
| 3 | + |
| 4 | +`Craftax <https://github.com/MichaelTMatthews/Craftax>`_ is a survival and |
| 5 | +crafting environment. Craftax Classic contains the original single-world |
| 6 | +survival game. Full Craftax adds nine floors, dungeons, equipment, elemental |
| 7 | +combat, spells, potions, and a final boss. |
| 8 | + |
| 9 | +EnvPool implements both games and their renderers in C++. The reference is |
| 10 | +Craftax v1.6.1, commit ``c3c2e0d038c4e641f9481320c158f457f30c28f3``. |
| 11 | +Craftax, JAX, and Flax are not runtime dependencies. The extension embeds only |
| 12 | +PNG textures referenced by the official renderer; no Python game code or |
| 13 | +training assets are loaded at runtime. The upstream MIT license is included |
| 14 | +in the wheel. |
| 15 | + |
| 16 | +Environments |
| 17 | +------------ |
| 18 | + |
| 19 | +.. list-table:: Primary environment names |
| 20 | + :header-rows: 1 |
| 21 | + :widths: 45 12 25 18 |
| 22 | + |
| 23 | + * - Name |
| 24 | + - Actions |
| 25 | + - Observation shape |
| 26 | + - Time limit |
| 27 | + * - ``Craftax-Classic-Symbolic-v1`` |
| 28 | + - 17 |
| 29 | + - ``(1345,)`` |
| 30 | + - 10,000 |
| 31 | + * - ``Craftax-Classic-Pixels-v1`` |
| 32 | + - 17 |
| 33 | + - ``(63, 63, 3)`` |
| 34 | + - 10,000 |
| 35 | + * - ``Craftax-Symbolic-v1`` |
| 36 | + - 43 |
| 37 | + - ``(8268,)`` |
| 38 | + - 100,000 |
| 39 | + * - ``Craftax-Pixels-v1`` |
| 40 | + - 43 |
| 41 | + - ``(130, 110, 3)`` |
| 42 | + - 100,000 |
| 43 | + |
| 44 | +All observations are ``float32``. Pixel observations use the official |
| 45 | +normalization to ``[0, 1]`` and include the inventory display. Symbolic |
| 46 | +observations contain the local map, entities, inventory, and player status. |
| 47 | +The declared symbolic bounds follow upstream; some equipment and status |
| 48 | +features can exceed one during play. |
| 49 | + |
| 50 | +Each name also has the official ``-AutoReset-v1`` variant, for example |
| 51 | +``Craftax-Symbolic-AutoReset-v1``. Every name has a ``Craftax/`` alias: |
| 52 | +``Craftax/Symbolic-v1`` and ``Craftax/Classic-Pixels-v1`` are examples. |
| 53 | +The registry is generated from the pinned upstream factory. |
| 54 | + |
| 55 | +Usage |
| 56 | +----- |
| 57 | + |
| 58 | +.. code-block:: python |
| 59 | +
|
| 60 | + import envpool |
| 61 | + import numpy as np |
| 62 | +
|
| 63 | + env = envpool.make_gymnasium( |
| 64 | + "Craftax-Symbolic-v1", |
| 65 | + num_envs=32, |
| 66 | + seed=0, |
| 67 | + render_mode="rgb_array", |
| 68 | + ) |
| 69 | + obs, info = env.reset() |
| 70 | + actions = np.zeros(32, dtype=np.int32) |
| 71 | + obs, reward, terminated, truncated, info = env.step(actions) |
| 72 | + frames = env.render(env_ids=[0, 3]) |
| 73 | + env.close() |
| 74 | +
|
| 75 | +Reset and termination |
| 76 | +--------------------- |
| 77 | + |
| 78 | +Primary names use EnvPool's usual reset on the step after an episode ends. |
| 79 | +That step returns the new initial observation, zero reward, and a first |
| 80 | +``dm_env`` timestep; its submitted action is not applied. |
| 81 | + |
| 82 | +The ``AutoReset`` names reset on the terminal step itself, as the official |
| 83 | +Craftax wrapper does. They return the new initial observation with the old |
| 84 | +episode's reward, terminal flag, and achievement information. The next action |
| 85 | +is applied to the new episode. Rendering after that step shows the new state. |
| 86 | +These names advertise ``SameStep`` in Gymnasium's autoreset metadata. |
| 87 | + |
| 88 | +Death, Classic lava, and full-game boss victory are terminations. A time |
| 89 | +limit without a simultaneous game termination is a truncation. The discount |
| 90 | +is zero at either boundary, matching the official oracle, including in the |
| 91 | +``dm_env`` API. ``info["discount"]`` retains that same value. |
| 92 | + |
| 93 | +Achievement information uses the official ``Achievements/<name>`` keys and |
| 94 | +reports 100 for an earned achievement only at the episode boundary. Classic |
| 95 | +also returns the official geometric-mean ``score``. In ``dm_env`` namedtuples, |
| 96 | +the usual EnvPool conversion replaces slashes in field names with underscores. |
| 97 | + |
| 98 | +Configuration and reproducibility |
| 99 | +--------------------------------- |
| 100 | + |
| 101 | +``max_episode_steps`` sets upstream ``max_timesteps``. Both games accept |
| 102 | +``day_length``, ``always_diamond``, ``mob_despawn_distance``, entity capacities, |
| 103 | +and ``fractal_noise_angles``. Classic uses the shared capacity names |
| 104 | +``max_melee_mobs``, ``max_passive_mobs``, ``max_ranged_mobs``, and |
| 105 | +``max_mob_projectiles`` for zombies, cows, skeletons, and arrows respectively. |
| 106 | +Classic also accepts the official mob health and spawn chance parameters. |
| 107 | +``god_mode`` and ``max_attribute`` apply to the full game. |
| 108 | + |
| 109 | +``map_size`` defaults to ``(64, 64)`` for Classic and ``(48, 48)`` for the full |
| 110 | +game. Maps must be square with a size divisible by 16, at least 16 for Classic |
| 111 | +and 48 for full Craftax's eight-room dungeon generator. The number of floors |
| 112 | +is fixed at one and nine respectively. Noise overrides are four flattened |
| 113 | +arrays in upstream order; an empty array selects random angles for that layer. |
| 114 | + |
| 115 | +Random draws use a native Threefry2x32 implementation with the pinned JAX |
| 116 | +partitionable counter layout. Each environment starts with |
| 117 | +``PRNGKey(seed + env_id)`` (or its explicit ``env_seed``). The first reset uses |
| 118 | +that key directly. Each following step splits the stream, keeps the left key, |
| 119 | +and uses the right key for the step or the next-step reset. The AutoReset |
| 120 | +wrapper further splits its step key into the official step and reset keys. |
| 121 | +Identical seeds and external actions therefore reproduce whole episodes, |
| 122 | +independently of thread count. |
| 123 | + |
| 124 | +Full Craftax's symbolic reset splits its input key once more than pixel |
| 125 | +reset, matching the official implementation. Consequently, the two observation |
| 126 | +variants can generate different worlds from the same external seed. |
| 127 | + |
| 128 | +Rendering |
| 129 | +--------- |
| 130 | + |
| 131 | +``render()`` produces batched ``uint8`` RGB frames. With the default |
| 132 | +``render_tile_size=16``, Classic frames are ``(144, 144, 3)`` and full Craftax |
| 133 | +frames are ``(208, 176, 3)``. ``render_tile_size=64`` selects the official human |
| 134 | +texture resolution. The standard ``render_width`` and ``render_height`` |
| 135 | +options resize the resulting frame by nearest-neighbour sampling. |
| 136 | + |
| 137 | +The renderer includes the official sprites, inventory digits, projectiles, |
| 138 | +light and night effects, sleep shading, and full-game floor visibility. |
| 139 | + |
| 140 | +.. image:: /_static/render_samples/craftax_official_compare.png |
| 141 | + :alt: EnvPool on the left and official Craftax on the right after gameplay |
| 142 | + |
| 143 | +EnvPool is on the left and the pinned official renderer is on the right. |
| 144 | +The documentation generator checks exact RGB equality after each displayed |
| 145 | +action sequence before writing the comparison image. |
| 146 | + |
| 147 | +Validation |
| 148 | +---------- |
| 149 | + |
| 150 | +Oracle tests use the pinned source and a separate dependency lock, including |
| 151 | +JAX/JAXlib 0.11.1 and Flax 0.12.9. They exercise all factory names, whole |
| 152 | +trajectories, crafting and resource interactions, every floor's combat, |
| 153 | +projectiles, potion and enchantment actions, plants, boss waves, and victory. |
| 154 | +The official texture cache is a test-only build artifact and is never shipped |
| 155 | +as a runtime dependency. |
| 156 | + |
| 157 | +Directed tests inject state only once, before the first external action. |
| 158 | +The ``initial_state`` configuration supports the same reset-only exchange |
| 159 | +through the actual pool; ``debug_state=True`` exposes its diagnostic encoding |
| 160 | +in ``info["state"]``. Neither option provides a mid-episode synchronization |
| 161 | +path. The diagnostic encoding is not a stable saved-game format. |
| 162 | + |
| 163 | +The only floating comparison exception is Classic pixel observations on |
| 164 | +macOS arm64. JAX changes the final blue-channel blend's fused multiply-add |
| 165 | +order between its reset/non-AutoReset step graphs and standalone renderer. |
| 166 | +Map blue is allowed one ULP at reset and two during steps; while sleeping, |
| 167 | +grayscale propagates that residual into map red/green, also bounded by two |
| 168 | +ULPs. Inventory pixels, awake red/green, AutoReset step observations, full |
| 169 | +Craftax observations, game state, rewards, information, and rendered uint8 |
| 170 | +RGB frames remain exact. The test records the operation that reproduces the |
| 171 | +difference; it does not use a general observation or gameplay tolerance. |
| 172 | + |
| 173 | +The implementation and acceptance record is maintained in |
| 174 | +``docs/plans/active/2026-08-27-craftax-native.md``. |
0 commit comments