Description
Explorer's Nightmare
The world does not exist until you touch it.
<video controls="controls" width="600" height="300"> <source src="</video>" rel="noopener nofollow" target="_blank">https://www.youtube.com/shorts/VAis3xfAIVw"></video>
A Fabric mod for Minecraft 26.2 that stops the game from generating terrain at all. Chunks arrive completely empty — an endless void from bedrock to build limit. Terrain only becomes real where something makes contact with it: where you walk, where a mob wanders, where an arrow flies overhead. Each contact carves out one full-height column of the real world, from the bottom of the world to the top, and everything around it stays nothing.
Walk forward and a narrow ribbon of ground unrolls beneath your feet, suspended in empty space. Throw a snowball and watch a line of terrain tear itself out of the void along its arc. Step off the path and you fall forever.
This is not a cosmetic filter over a normal world. Untouched terrain is never generated in the first place — it costs no CPU and no disk until something reaches it.
Contents
- What actually happens
- How it works
- Installation
- Configuration
- Commands
- What triggers a reveal
- Spawning
- Performance and disk
- Compatibility and caveats
- Building from source
- License
What actually happens
| Vanilla | Explorer's Nightmare | |
|---|---|---|
| Chunk within render distance | fully generated | generated empty, costs almost nothing |
| Terrain you have never touched | exists | has never been computed |
| Standing on a block | ordinary | reveals the full-height column under you, and nothing else |
| Arrow in flight | ordinary | reveals every column it passes over |
| Blocks you mine | stay mined | stay mined — reveals are remembered, they do not grow back |
| Villages, caves, ores, structures | present | present, exactly where the seed puts them |
The terrain that appears is genuine vanilla worldgen for your seed. Nothing is approximated: you get the same village, the same ravine, the same diamond vein you would have found in an ordinary world at those coordinates — you just have to physically reach each column to see any of it.
How it works
Two halves.
1. The visible world generates nothing.
A mixin on ChunkStatusTasks short-circuits every generation step that would write blocks — noise, surface, carvers, features and mob spawning — for any dimension the config marks as a nightmare. Biomes, lighting and heightmaps still run, because the client needs biomes for grass colour, fog and music, and the light engine needs its bookkeeping intact. A chunk therefore arrives in the world already empty, and preparing the spawn area takes a couple of seconds instead of a couple of minutes.
2. A hidden shadow dimension does the real generating, on demand.
For each nightmare dimension the mod opens a twin ServerLevel — same seed, same generator, same dimension type — registered as explorers_nightmare:shadow_<namespace>_<path>. Nobody ever goes there. When something touches a column, the mod asks the shadow world for that chunk, and only that chunk. Because the shadow is an ordinary level, the complete vanilla pipeline runs there: neighbour chunks, structure starts, feature placement, the lot. What comes back is real terrain.
The shadow world's own region files double as the terrain store, so a chunk is generated at most once, ever. A small per-chunk bitmask (33 bytes, its own region files) records which of a chunk's 256 columns have already been handed over, so mined blocks stay mined.
Why not just generate normally and hide it? That was the first design and it works, but it generates every chunk in render distance whether or not you ever touch it. The shadow approach means a player standing still generates ~25 chunks instead of ~625.
Why can't generation be done per-column without a shadow world? Minecraft cannot generate one chunk in isolation — reaching full status needs neighbours generated to intermediate statuses out to a radius of 8, roughly 289 chunk-steps. Vanilla only makes that cheap by amortising the neighbourhood inside ChunkMap. A second level is the only way to reuse that machinery instead of reimplementing it.
Installation
Requires:
| Minecraft | 26.2 |
| Fabric Loader | 0.19.3+ |
| Fabric API | 0.157.0+26.2 |
| Java | 25+ |
Drop the jar into mods/ alongside Fabric API.
This mod is entirely server-side. Clients receive ordinary chunk packets and need nothing installed — it works on a dedicated server with vanilla clients, and in single-player with only you having it.
Start a new world. The mod only empties chunks generated after it is installed. Adding it to an existing world leaves everything already explored exactly as it is, and only the frontier becomes void. That is a legitimate way to play it, but it is not the intended experience.
Configuration
Written to config/explorers_nightmare.json on first launch. Every option can also be changed live with /explorersnightmare set <option> <value> — no restart, no file editing.
Reveal shape
| Option | Default | What it does |
|---|---|---|
revealRadius |
1 |
How wide a patch each touch reveals, counted inclusively. 1 reveals only the columns something is actually standing in or passing through — nothing appears before you reach it. 2 → 3×3, 3 → 5×5. Anything above 1 shows you ground ahead of you. |
spawnRevealRadius |
1 |
How wide a patch is revealed instantly under a player who joins, respawns or changes dimension, counted the same inclusive way. 1 gives them the single column they stand on and nothing more. See Spawning. |
revealAlongMovementPath |
true |
Follow the swept path an entity crossed this tick rather than only its final block. This is what makes fast arrows reveal a continuous line instead of dots. |
columnMinY |
null |
Lowest Y a reveal will fill in. null means the world's own bottom. Set to 0 and everything below Y 0 stays void. |
columnMaxY |
null |
Highest Y a reveal will fill in. null means the world's own top. |
revealParticles |
false |
Puff a small cloud particle at the top of each newly revealed column. |
Dimensions
| Option | Default | What it does |
|---|---|---|
enableOverworld |
true |
Overworld is a nightmare. |
enableNether |
true |
Nether is a nightmare. |
enableTheEnd |
true |
End is a nightmare. |
enableAllDimensions |
true |
Apply to every dimension including modded ones, ignoring the three flags above. Turn this off if you only want the three vanilla dimensions. |
extraDimensions |
[] |
Extra dimension ids to include, e.g. ["mymod:cavern"]. Set from chat with a comma-separated list. |
Turning a dimension off later does not put back what was already emptied — chunks that were generated blank stay blank. Use
/explorersnightmare restore <radius>to fill an area back in.
What counts as a touch
| Option | Default | What it does |
|---|---|---|
revealFromPlayers |
true |
Players carve terrain as they move. |
revealFromMobs |
true |
Any living non-player entity carves terrain. |
revealFromProjectiles |
true |
Arrows, snowballs, tridents, ender pearls, fireballs — anything extending Projectile — carve along their flight. |
revealFromOtherEntities |
true |
Items, boats, minecarts, primed TNT, falling blocks and other loose entities. |
revealFromBlockInteraction |
true |
Right-clicking or breaking a block reveals around it. At revealRadius 1 this reveals nothing new, since the block you clicked is already revealed — it only does something at wider radii. |
Performance
| Option | Default | What it does |
|---|---|---|
maxColumnRevealsPerTick |
64 |
Ceiling on columns materialised per dimension per tick. Raise for faster reveals at large radii, lower if the server struggles. |
maxQueuedColumns |
65536 |
Backlog cap. Requests past this are dropped rather than allowed to pile up. |
shadowPrefetchRadius |
2 |
Chunk radius around each player kept generated in the shadow world in the background, so walking never has to wait. Raise if players outrun generation (elytra, boats on ice); lower to generate even less. |
archiveCacheSize |
256 |
Shadow-world chunk snapshots kept in memory per dimension. Roughly 30 KB each. |
Commands
Requires gamemaster permission (op level 2). /enm is an alias for everything below.
| Command | What it does |
|---|---|
/explorersnightmare config |
List every option and its current value. |
/explorersnightmare set <option> <value> |
Change an option and save it. Tab-completes option names. Use null to clear columnMinY / columnMaxY. |
/explorersnightmare reload |
Re-read the config file from disk and apply it. |
/explorersnightmare status |
Per-dimension counters: columns revealed, queue depth, and shadow-world chunks generated / cached / in flight. |
/explorersnightmare reveal [radius] |
Materialise a radius around yourself right now, ignoring the per-tick budget. Defaults to 8. |
/explorersnightmare restore <radius> |
Fill in every column in a radius, turning the area back into an ordinary world. The escape hatch. |
Examples:
/enm set revealRadius 4 # 7x7 around each touch
/enm set enableNether true
/enm set extraDimensions mymod:cavern, othermod:sky
/enm set columnMinY 0
/enm restore 64
What triggers a reveal
Any entity in the list above, every tick it enters a new block column. For each such entity the mod reveals:
- the column it stands in,
- every column its bounding box overlaps (so standing on a block edge reveals both),
- every column along the straight line from where it was at the start of the tick to where it is now,
each expanded by revealRadius - 1 blocks (so not at all, at the default).
Because reveals follow the entity's bounding box rather than a single point, a player straddling a block boundary reveals both columns they overlap. This is real contact, not lookahead, and it is what lets you step up onto a block that has not appeared yet — but it does mean the ground under your leading foot can materialise a fraction of a block before your centre crosses onto it.
The swept path uses a proper voxel traversal, so nothing is skipped no matter how fast the entity is moving. Teleports over 512 blocks reveal only the destination.
Ground directly under a player is materialised on the spot rather than queued — a queued reveal there would mean falling through a floor that has not arrived yet. Everything else goes through the per-tick budget.
Nothing is ever revealed ahead of contact at the default settings. If you want to see terrain before you reach it, raise revealRadius.
Falling into the void is self-correcting: because a reveal is a full column, terrain appears below a falling player as well as beside them, and they land.
Spawning
Vanilla chooses the world spawn point while the dimension is still completely empty, so the Y it picks is meaningless — on a test seed it landed on y=64 where the real ground turned out to be at y=75, which buries the first player to join eleven blocks inside solid rock. Two things prevent that:
- The spawn point is corrected once. When a dimension's shadow world opens, the mod reads the real surface height at the spawn X/Z and moves the spawn point there, keeping X and Z. This is written to
level.dat, so it is a one-time fix rather than a per-join patch. - Arrivals are settled, with retries. A joining player's chunk has not loaded yet at the moment they join, so their ground cannot be revealed on the spot. The mod keeps retrying every tick until the chunk is there, reveals the column, and if the player still ends up inside solid terrain, moves them to the top of their own column. Players merely hanging in the air are left to fall onto it, and a player who legitimately respawned in a cave is not dragged to the surface.
Performance and disk
CPU. Untouched terrain is never generated, so a stationary player costs roughly (2 × shadowPrefetchRadius + 1)² generated chunks — 25 at defaults — against vanilla's several hundred for the same render distance. Empty chunks are cheap to generate, cheap to light and cheap to send. Preparing the spawn area of a fresh world takes about 2.5 seconds.
Hitches. Walking into a chunk whose shadow twin has not been generated yet blocks the server thread until it finishes. shadowPrefetchRadius exists to make that rare; /explorersnightmare status reports a waits counter so you can tell whether it is happening. Teleporting a long distance will always cost one such wait.
Disk. Two extra stores per nightmare dimension:
dimensions/explorers_nightmare/shadow_<dimension>/— the shadow world. Only ever holds chunks something touched, so it grows with exploration, not with render distance.<dimension>/explorers_nightmare/— reveal masks, 33 bytes per chunk before compression. Negligible.
Do not delete the shadow dimension folder. It is where the terrain lives. Deleting it does not break the world, but every chunk you revisit will regenerate its terrain from scratch.
Compatibility and caveats
- Server-side only. No client mod needed, no client-side rendering changes, no custom packets.
- Shadow dimensions are real, registered dimensions.
/execute in explorers_nightmare:shadow_minecraft_overworldwill work, and an operator could teleport into one. There is nothing interesting there — it is your world, fully generated, with no players. Do not build in it. - Structures are planned but not placed in the nightmare dimension itself, so
/locatethere will not find anything. The structures themselves are present in the terrain you reveal, because they were placed in the shadow world. - No natural mob spawning at worldgen time. Runtime spawning works normally on revealed ground.
- Revealed blocks are placed without neighbour or shape updates, deliberately: terrain should appear exactly as generation left it rather than immediately collapsing into gravel falls and water floods.
- Block entities are restored with their contents, so revealed chests keep their loot.
- Other worldgen mods should work — the mod does not replace the chunk generator, it skips the vanilla steps that call it, and the shadow world uses whatever generator your dimension actually has.
- Chunk-rewriting mods (chunk pregenerators, world-editing tools that force-generate large areas) will pull huge regions through the shadow world and defeat the point.
Building from source
git clone https://github.com/AB-70/ExplorersNightmare
cd ExplorersNightmare
./gradlew build
The jar lands in build/libs/. ./gradlew runServer starts a dev dedicated server.
Project layout:
src/main/java/dev/sattar/explorersnightmare/
├── ExplorersNightmare.java entry point, event wiring
├── command/NightmareCommand.java /explorersnightmare
├── config/
│ ├── NightmareConfig.java every option
│ └── NightmareConfigManager.java load, save, reflective set
├── mixin/
│ ├── ChunkStatusTasksMixin.java skips block-writing generation steps
│ └── MinecraftServerAccessor.java reaches the level map to register shadows
└── world/
├── NightmareManager.java which dimensions are nightmares
├── NightmareLevel.java reveal queue, triggers, column placement
├── ShadowWorld.java the hidden generating twin
├── ChunkTerrain.java an immutable chunk snapshot
├── RevealMask.java 256-bit per-chunk revealed set
└── RevealMaskStore.java mask persistence
License
All Rights Reserved. Copyright (c) 2026 AB-70.
You may download and use this mod in your own game. You may not copy, modify, redistribute, re-upload, or include it or its source code in modpacks or other projects without prior written permission. See LICENSE.
