Exploring the world through a Minecraft Plugin
Despite Minecraft being a game where the world is made out of large cubes and you can punch trees with your fist that later end up floating, it’s always been a really immersive experience for me. Seriously, sometimes I’ve actually dreamed in Minecraft. Though that’s probably also because I play the game too much.
Anyway, this all got me thinking one day: what if it were possible to explore the real world in Minecraft? The game has a diverse block palette that would make it possible to represent a wide variety of landscapes. And the world itself has a total area of around 3.6 billion square kilometers, or around seven times the surface area of the Earth. So even on a 1:1 scale, a Minecraft world would easily have enough space to store the entire Earth.
Something like this has already been done before; there’s the Terra 1-to-1 mod, which recreates the Earth at a 1:1 scale (1 block = 1 meter). That being said, I still wanted to try and do it myself.
My First Attempt (Fall 2019)
After some Googling online, one way I found to do this was to use a command to place down the necessary blocks. I first had to figure out how to get the elevation data for any given point on the Earth’s surface, and initially the best way I found to do this was using the Google Maps Elevation API. The only problem with this is that you only got a limited amount of free API calls, and after that it cost money to use. So I had to use a much coarser scale (around 1:10k) so I wouldn’t use up too many API calls.
Once I did this, I could simply specify the bounding box of the region I wanted in the command arguments, grab the necessary data from the API by calling it at every latitude and longitude increment, and then place down blocks at the appropriate height. And it ended up working… sort of. (This version of the project can be found at https://github.com/shishir03/minecraft-mapper.)
There were a couple of major drawbacks to the method I was using. For one thing, APIs like the Google Maps are rate-limited, and exceeding 100 requests per second gives you a server error; this places an upper limit on how fast the program can run. Also, with how many requests even a region on my coarse scale required, it would be impossible to generate regions any larger than about the size of the Bay Area without running out of free API calls. Finally, using a command to generate the world meant that while I was waiting for the API calls to finish, I kind of just had to sit there for a couple minutes. At the time, I wasn’t really sure how to solve these problems, so I ended up pretty much abandoning the project for almost two years.
Picking up not quite where I left off (Fall 2021)
For some reason, last fall I decided to revisit the project and completely rewrite the code from scratch. This time, instead of using a command to generate the terrain, I modified world generation directly. This meant that all the API calls would be done during server startup, when the chunks surrounding spawn were generated, rather than when a command was called. I also decided to use the Open Elevation API, which was free and also not rate limited.
With these changes, the plugin was working a lot better. Not only could I improve the scale to 1:1000, I could generate much larger areas now, going as far as all of California and Nevada (though this took around 15 minutes). I also added biomes, although very simplistic and based only on elevation. Similarly, water was only filled in for areas below sea level, turning Death Valley and parts of the Central Valley into a lake and Lake Tahoe into a dry basin. Welcome to climate change everyone.
Better Biomes
Clearly there was still plenty of room for improvement. First, I decided to improve the biomes. There were some good climate datasets (at least for the US) like the PRISM gridded data. With some help from Brian Brettschneider, who often uses this data for creating various climate maps, I was able to obtain the data from an API. Since the PRISM data had a lower resolution than the Open Elevation API, I used a weighted average to smooth out the boundaries between biomes.
The biomes were defined based on average annual temperatures as follows:
- Temperature < 45°F: tundra
- Precipitation < 10" (or temp > 70°F and precip < 20"): desert
- 10" < precip < 20" (or temp > 70°F and precip < 40"): savanna
- 45°F < temp < 70°F and 20" < precip < 40": plains
- 45°F < temp < 70°F and precip > 40": forest
- Temp > 70°F and precip > 40": jungle
With these changes, the biomes weren’t entirely perfect but they were looking a lot better.
A New Data Source
Next up was improving the speed and resolution. Inspired by Sebastian Lague’s video on making a geography game, I decided to check out some other datasets, and the GEBCO bathymetry dataset seemed like it had what I was looking for. It solved a lot of my problems; it had a higher resolution, which would allow me to increase the scale to 1:460. Another nice feature was that it had data for ocean depth as well, which meant I could have an actual sea floor instead of just a layer of water above bedrock. Therefore, I also raised the sea level from y = 0 to y = 130 to accommodate the ocean terrain (which had the additional side effect of stopping the slime spawning which only occurs below y = 40).
With the GEBCO data implemented, the world was looking a lot better. There was just one problem: memory usage. The netcdf file that stored all the data was 7.5 GB, so it took around an hour to download off the internet. In exchange I got much faster runtime, since I could read data directly off the filesystem instead of having to access the internet through an API call each time I wanted to obtain a data point. I guess eventually it was worth it, since you only had to download the file once. All this meant I could generate vast areas in not too much time, being able to generate the entire United States in just a few minutes. With the total area I had to work with being so large now, I added commands to teleport to specified latitude and longitude coordinates as well as getting the current coordinates, just to make it easier to get around.
Elevation Scaling
I should probably take a moment to discuss the scaling of the elevation, rather than just the horizontal scaling. I was developing this plugin for Minecraft version 1.17, so I had 256 blocks of vertical space to play with (1.18 and 1.19, which increased the total world height to 384 blocks, hadn’t released yet). With the lowest elevation being the Marianas Trench at around 11000 meters below sea level and the highest being Mount Everest at around 8850 meters. This resulted in an elevation range of roughly 19850 meters, so the largest vertical scale I could use was 1:77. In order to make the terrain less steep, however, I went with 1:100.
This meant that while I was using the old horizontal scale of 1:1000, elevation would be stretched out by a factor of 10. As shown in the screenshot above, this actually made some of the mountain terrain look similar to how it does in vanilla Minecraft, and this is because vanilla Minecraft terrain is actually really steep compared to real life. With the new 1:460 horizontal scale, most mountains looked a lot rounder, with the Sierra Nevada looking more like a gradual slope upwards as you went east. One thing that stayed the same, however, is that the valleys were mostly completely flat. In contrast, the plains biomes in vanilla Minecraft (pre-1.18) often have small hills and can change in elevation by around 10–15 blocks.
Improving Water Generation
The final improvement I decided to make was having my bodies of water be more realistic. I was still just generating water only in areas below sea level; this worked okay some of the time, but there were some significant issues. The Great Lakes, for instance, have a surface above sea level, so they were looking a lot more anemic. Conversely, dry areas below sea level like Death Valley and parts of the Central Valley were filled with water.
While an easy way to approach this would have been to compare the bathymetry data against surface elevation data (and if the surface elevation was greater then there was a body of water present), I wasn’t sure where to find surface elevation data. If anyone knows any sources for surface elevation data please let me know. But I decided to look through satellite images, and fill in any blue areas with water. There were a lot of different shades of blue in lakes and rivers, but most of the bigger ones were the same shade of dark blue.
And so, I read the necessary pixels from each image and determined its color, and whether it was similar enough to the proper shade of blue. I had different similarity thresholds based on whether the point was above or below sea level; the ocean varied quite a bit in color so the threshold was lower below sea level. Lakes also came in a bunch of different colors above sea level, but I wanted to avoid false positives (water where there wasn’t supposed to be any), especially since forests were pretty similar in color to water, so the threshold was much tighter.
Conclusion
So this brings me to where I am with the project today. My solution wasn’t perfect; you can notice in the above screenshot that the water level in Crater Lake is a little uneven. This is because I don’t have surface elevation data and so all lakes are just one layer of water above the lake bottom. This generally works okay for shallower lakes but not as much for deeper lakes like Crater Lake. Loading the images is also a pretty slow process and it took a while for me to come up with a process that had decent runtime. It still ended up being really demanding memory-wise, and it was kind of a tradeoff between memory usage and runtime.
I don’t know if I’ll continue the project anytime soon, though I definitely plan to improve the water generation when I do. Also, the world is noticeably bare of any vegetation, and I was never able to get the tree generation code working. Either way, I’m quite proud of how far I’ve taken this project. It was really fun seeing the places I know and love through a new perspective, and I definitely hope that I can find something in the future that will help me develop and polish it even further.
Source code: https://github.com/shishir03/MinecraftMapperRemastered