Parsing and analyzing Minecraft ore distributions

Some months ago, my 6 year old son discovered Minecraft. His sister and I soon followed1. It’s a great game and there’s a ton of good content out there about it. Reddit and forums are active. it has an excellent wiki, and lots of YouTube stuff. Not surprising given how popular the game is.

One topic that is covered a bunch is how to best mine for diamonds. The thing is that beyond a graph of diamonds by layer, I don’t really see any data involved.

In this post, I talk about how I parsed a Minecraft Bedrock world database to get some more numbers. Topics include:

  • Pictures of some fun situations and overall distributions.
  • Some numbers concerning the densities/distributions diamond, other uncommon ores and spawners.
  • How to parse the data yourself.
    • Mojang/Microsoft has released their variant of Google’s leveldb, but it doesn’t compile out of the box and it doesn’t come with a reference parser.
    • The wiki is very helpful but I find that actual code samples tell me more.

A big caveat…

This post mentions data from only one Bedrock world which hasn’t been traveled much. The seed is “-1337710146”. I don’t remember where I got it but it was from a YouTube video. Basically, I loaded it in creative and flew around a bunch to trigger terrain creation.

In the end, my data represents:

  • 3705 16*16*256 block chunks
    • so an area of 3705*16*16 or about 1000×1000
  • 87,949,312 blocks are actually stored. This is less than the 242M blocks in the world. There’s no need to store subchunks of the sky.
  • 12324 diamonds or about 3.3 per chunk.

My main point is to enable others to parse their data

My main intent in this post to to share the code I used to compute these numbers. I’d be really surprised if I don’t have a big bug in there. Don’t trust my numbers, play with the code yourself.

At the same time, I realize that most minecraft players are not computer programmers. Hopefully, the stats I give are interesting to you.

See the second half of this post for instructions on how to parse minecraft bedrock data.

My code is available on github.

For non-programmers:

Some fun pictures

In my explorations playing the game, I hadn’t come across diamonds in lava. I’d known to watch out for diamonds over lava, but not swimming in it.

In this picture, there’s a diamond behind the cobblestone block, directly below flowing lava. There’s also one to the right of it.

This is the funnest one. My program gave me a list of diamonds under lava. I went to the location and found this… where’s the diamond?

Douse it with water.

Pick out the obsidian and there it is. You’d have to be incredibly lucky to find this one.

There’s only one diamond, so that luck wouldn’t have taken you very far.

I was also a bit surprised to find some spawners in lava.

Interesting stats

Given 87,949,312 stored blocks, here’s a high level breakdown:

Block TypeNumber in my worldpercentage overallpercentage ignoring air
diamond123240.0140126%0.0182668%
lapis lazuli145890.016588%0.021624%
stone5246566659.6544%77.7652%
air2048258823.2891%30.3595%
dirt39020474.4367%5.78366%
bedrock33177023.77229%4.91754%
gravel28633753.25571%4.24413%
leaves8067370.917275%1.19576%
coal_ore7211200.819927%1.06885%
grass6956760.790997%1.03114%
iron_ore3923750.446138%0.581583%
water3888140.442089%0.576305%
stained_hardened_clay3386190.385016%0.501905%
lava3364900.382595%0.49875%
hardened_clay2259810.256945%0.334952%
sand1975840.224657%0.292861%
vine1490900.169518%0.220983%
redstone_ore975400.110905%0.144575%
log956050.108705%0.141707%
sandstone952220.108269%0.141139%
tallgrass839560.0954595%0.124441%
gold_ore529830.0602427%0.078532%
bamboo419860.0477389%0.0622322%
snow_layer271660.0308882%0.0402658%

Clustering

Diamonds, and other ores, tend to be found in clusters. If you find a diamond, you should dig around a bit as there are usually a couple more nearby. I define a cluster as a set of ores in which every member is 2 blocks or less away from another member.

In the table below, for each size of cluster, the number of such clusters is given for each ore type. In the case of diamonds, if you find one you’ll usually find between 4 and 6.

 diamond_oreiron_orelapis_oreredstone_ore
125824671931773
223525572721779
326825823411740
4566739911074030
539864305412707
6478119735142923
759402855513
8354117962632278
93320319386
10929463269
1117880200
1206961212
1315460130
1416310126
150340039
160457067
170188028
180191015
19090014
20090016
2105707
2206407
2302805
2403402
2501702
2601601
2701000
280701
290600
300401

Depth/y/altitude

We’re told to mine at y=12. Here is a table that shows where the ores are in my particular world. The heading contains the total number of each ore. If you’re looking for diamonds, you can basically look anywhere between 5 and 12.

oretype(totalinworld)diamond(12324)iron(380887)lapis(14589)mob_spawner(163)redstone(97540)
00(0%)0(0%)0(0%)0(0%)0(0%)
10(0%)0(0%)0(0%)0(0%)0(0%)
2251(2.0367%)1656(0.43477%)78(0.53465%)0(0%)2337(2.3959%)
3578(4.69%)3320(0.87165%)150(1.0282%)0(0%)4466(4.5786%)
4789(6.4021%)4885(1.2825%)276(1.8918%)0(0%)6790(6.9612%)
51140(9.2502%)6683(1.7546%)470(3.2216%)0(0%)8849(9.0722%)
61087(8.8202%)6817(1.7898%)441(3.0228%)0(0%)8882(9.106%)
71090(8.8445%)6960(1.8273%)527(3.6123%)0(0%)9007(9.2342%)
81139(9.2421%)6888(1.8084%)584(4.003%)0(0%)8770(8.9912%)
91126(9.1366%)6874(1.8047%)828(5.6755%)0(0%)8569(8.7851%)
101096(8.8932%)6683(1.7546%)862(5.9086%)0(0%)8626(8.8436%)
111114(9.0393%)6626(1.7396%)740(5.0723%)2(1.227%)8943(9.1685%)
121125(9.1285%)6717(1.7635%)810(5.5521%)3(1.8405%)9036(9.2639%)
131060(8.6011%)6455(1.6947%)914(6.265%)4(2.454%)7928(8.1279%)
14608(4.9335%)6527(1.7136%)882(6.0457%)2(1.227%)4488(4.6012%)
15121(0.98182%)6622(1.7386%)901(6.1759%)4(2.454%)849(0.87041%)
160(0%)6754(1.7732%)835(5.7235%)2(1.227%)0(0%)
170(0%)6795(1.784%)805(5.5179%)5(3.0675%)0(0%)
180(0%)6637(1.7425%)798(5.4699%)4(2.454%)0(0%)
190(0%)6664(1.7496%)682(4.6748%)5(3.0675%)0(0%)
200(0%)6611(1.7357%)550(3.77%)6(3.681%)0(0%)
210(0%)6619(1.7378%)524(3.5917%)3(1.8405%)0(0%)
220(0%)6812(1.7885%)417(2.8583%)9(5.5215%)0(0%)
230(0%)6800(1.7853%)378(2.591%)7(4.2945%)0(0%)
240(0%)6743(1.7703%)358(2.4539%)1(0.6135%)0(0%)
250(0%)6740(1.7696%)312(2.1386%)2(1.227%)0(0%)
260(0%)6735(1.7682%)203(1.3915%)3(1.8405%)0(0%)
270(0%)6700(1.7591%)132(0.90479%)5(3.0675%)0(0%)
280(0%)6633(1.7415%)93(0.63747%)5(3.0675%)0(0%)
290(0%)6623(1.7388%)37(0.25362%)6(3.681%)0(0%)
300(0%)6408(1.6824%)2(0.013709%)5(3.0675%)0(0%)
310(0%)6448(1.6929%)0(0%)2(1.227%)0(0%)
320(0%)6667(1.7504%)0(0%)5(3.0675%)0(0%)
330(0%)6649(1.7457%)0(0%)3(1.8405%)0(0%)
340(0%)6247(1.6401%)0(0%)4(2.454%)0(0%)
350(0%)6600(1.7328%)0(0%)6(3.681%)0(0%)
360(0%)6835(1.7945%)0(0%)1(0.6135%)0(0%)
370(0%)6895(1.8102%)0(0%)5(3.0675%)0(0%)
380(0%)6823(1.7913%)0(0%)5(3.0675%)0(0%)
390(0%)6800(1.7853%)0(0%)0(0%)0(0%)
400(0%)6648(1.7454%)0(0%)4(2.454%)0(0%)
410(0%)6448(1.6929%)0(0%)3(1.8405%)0(0%)
420(0%)6581(1.7278%)0(0%)2(1.227%)0(0%)
430(0%)6802(1.7858%)0(0%)2(1.227%)0(0%)
440(0%)6811(1.7882%)0(0%)5(3.0675%)0(0%)
450(0%)6905(1.8129%)0(0%)2(1.227%)0(0%)
460(0%)6769(1.7772%)0(0%)1(0.6135%)0(0%)
470(0%)6990(1.8352%)0(0%)2(1.227%)0(0%)
480(0%)5792(1.5207%)0(0%)4(2.454%)0(0%)
490(0%)5860(1.5385%)0(0%)1(0.6135%)0(0%)
500(0%)5892(1.5469%)0(0%)1(0.6135%)0(0%)
510(0%)6101(1.6018%)0(0%)2(1.227%)0(0%)
520(0%)5898(1.5485%)0(0%)0(0%)0(0%)
530(0%)5820(1.528%)0(0%)1(0.6135%)0(0%)
540(0%)6017(1.5797%)0(0%)0(0%)0(0%)
550(0%)5994(1.5737%)0(0%)0(0%)0(0%)
560(0%)6149(1.6144%)0(0%)1(0.6135%)0(0%)
570(0%)6054(1.5894%)0(0%)2(1.227%)0(0%)
580(0%)5920(1.5543%)0(0%)3(1.8405%)0(0%)
590(0%)5637(1.48%)0(0%)0(0%)0(0%)
600(0%)5158(1.3542%)0(0%)2(1.227%)0(0%)
610(0%)4162(1.0927%)0(0%)3(1.8405%)0(0%)
620(0%)2112(0.5545%)0(0%)2(1.227%)0(0%)
630(0%)416(0.10922%)0(0%)0(0%)0(0%)
640(0%)0(0%)0(0%)1(0.6135%)0(0%)
650(0%)0(0%)0(0%)1(0.6135%)0(0%)
660(0%)0(0%)0(0%)0(0%)0(0%)
670(0%)0(0%)0(0%)1(0.6135%)0(0%)
680(0%)0(0%)0(0%)0(0%)0(0%)
690(0%)0(0%)0(0%)2(1.227%)0(0%)

Caves vs mining

In various forums, there’s the question of how many diamonds will you find just by exploring caves. To find an ore in caves, it needs to be next to 2 an air block. According to my data, out of 2661 diamond clusters, 77 of them had a member next to an air block. This represents 311 diamond ores or a little over 10%.

Mining strategy

Online, there’s a lot of talk about the best branch mining strategy. Tunneling every 4 blocks guarantees seeing everything on your level and one above. But… it doesn’t take into account that if you find a desired ore, you’ll continue digging the area. Clustering.

So, I added some code to see how many clusters you’ll find with each branch mining spacing. If you find one member of a cluster, you’ll find the whole cluster.

So, the table below is kind busy.

  • The rows represent the y/altitude level of your feet.
  • The columns represent the number of blocks between each branch. So if you have zero blocks between each branch, you’re mining two complete layers. One block means, branch/block/branch/block…
  • The heading tells you the number of blocks between branches and what percentage of the two layers you’re mining.
  • The table cells have two numbers.
    • The percentage of all diamonds you’d find for that level and branch spacing. Since Diamonds are distributed over 10+ levels, you wouldn’t get them all.
    • On average, how many blocks you’d have to mine per diamond found. The numbers seemed low to me after first. 125 blocks per diamond was not my experience. Remember however that diamonds are usually next to friends. If you think of 4/cluster, that means you’d have to dig 500 blocks to find a a cluster.

Sorry that the heading font is so big. I couldn’t find a way to get TablePress to make it smaller.

In the end, it doesn’t really seem to matter much how many blocks you skip, though it does seem that digging a little deeper is helpful.

When computing these numbers, I consider that you’ll find diamonds if:

  • A cluster member is in the branch you’re mining.
  • directly above or below
  • directly left or right.
 0/ 1001/ 502/ 33.333/ 254/ 205/ 16.676/ 14.297/ 12.58/ 11.119/ 1010/ 9.091
level 217.96/ 857.214.96/ 514.410.39/ 493.68.747/ 439.96.994/ 440.15.631/ 455.65.023/ 437.84.073/ 472.43.968/ 4313.611/ 426.33.205/ 436.6
level 327.84/ 552.925.12/ 306.418.19/ 28215.97/ 24113.21/ 23310.32/ 248.69.453/ 232.68.009/ 240.26.913/ 247.46.362/ 2426.045/ 231.5
level 435.56/ 432.832.36/ 237.823.79/ 215.721.34/ 180.319.18/ 160.514.37/ 178.512.88/ 170.811.05/ 174.19.25/ 184.99.12/ 168.88.244/ 169.7
level 540.97/ 375.738.15/ 201.828.51/ 179.925.66/ 15023.81/ 129.317.8/ 144.115.55/ 141.413.59/ 141.611.69/ 146.311.77/ 130.810.29/ 136
level 645.77/ 336.341.85/ 183.932.11/ 159.827.47/ 140.123.64/ 130.219.01/ 134.918.23/ 120.614.26/ 13513.46/ 12711.73/ 131.211.09/ 126.2
level 747.03/ 327.343.29/ 177.832.43/ 158.228.81/ 133.625.02/ 12320.49/ 125.217.48/ 125.815.45/ 124.513.32/ 128.412.7/ 121.210.94/ 127.9
level 846.56/ 330.643.35/ 177.532.88/ 156.129.02/ 132.625.98/ 118.521.15/ 121.316.57/ 132.716.06/ 119.813.84/ 123.513.56/ 113.510.65/ 131.3
level 947.36/ 32543.47/ 177.133.72/ 152.128.51/ 13525.37/ 121.421.06/ 121.816.82/ 130.715.08/ 127.615.25/ 112.113.28/ 115.910.81/ 129.5
level 1047.53/ 323.943.7/ 176.132.58/ 157.529.19/ 131.824/ 128.321.14/ 121.417.15/ 128.215.27/ 12614.69/ 116.412.82/ 120.110.87/ 128.7
level 1144.81/ 343.541.74/ 184.431.45/ 163.128.22/ 136.424.69/ 124.719.82/ 129.416.7/ 131.714.82/ 129.813.92/ 122.913.06/ 117.910.16/ 137.7
level 1238.27/ 402.236.45/ 211.128.12/ 182.426.05/ 147.722.52/ 136.718.09/ 141.815.79/ 139.314.44/ 133.212.92/ 132.411.41/ 134.98.901/ 157.2
level 1329.07/ 529.427.61/ 278.721.43/ 239.420.49/ 187.816.7/ 184.314.57/ 17612.49/ 176.111.04/ 174.210.42/ 164.28.634/ 178.37.562/ 185
level 1419.99/ 770.218.56/ 414.713.88/ 369.612.94/ 297.310.97/ 280.69.226/ 278.17.806/ 281.77.23/ 266.16.142/ 278.45.721/ 269.14.998/ 280
level 1510.78/ 14278.804/ 874.26.313/ 812.85.956/ 646.14.187/ 735.33.708/ 691.83.181/ 691.33.457/ 556.62.475/ 691.12.434/ 632.32.045/ 684.3

Parsing the code yourself/the code

There are three parts to the code you may care about3:

  • Getting Mojang’s leveldb code to work
  • Parsing the actual structures
  • computing statistics

Getting Mojang’s leveldb code to work

Mojang was “kind enough” to release the leveldb code. Super helpful except it doesn’t compile for me to use it out of the box.

Why do I put quotes around “kind enough”? Because I want to go on what I think is an interesting tangent.

A tangent on open source software

I used to work at Intel Corp as a computer programmer. Intel’s design team uses A LOT of Perl code. Until 5 years ago, when I left, it was mostly Perl 5.8.5 but that was beginning to change. I believe the version was 8 years old at the time. It was mostly a matter of libraries/packages compatibility.

Anyway, I really liked Perl and I wrote a lot of it. Over time, I cooked up some packages that I thought others in the Perl community would find useful. So I contacted the folks in my division who deal with open source stuff. After one conversation with the guy it became clear to me, “Intel really doesn’t want to release anything into open source”

Intel is dependent on open source software. Design has always been done on various flavors of unix/linux. Redhat and SUSE are two that I remember.  Lots of other related software. Boost, GNU, the list is long. Still, Intel really doesn’t want to release anything.

Do you feel outraged? Don’t be. The reasons are not Intel’s fault.

Intel goes through great lengths to pay for free open source software. Intel searches for someone to pay for everthing they use. GNU… they pay someone (FSF?, Redhat/SUSE?) They pay Nokia to use QT. If you want to use a piece of OSS, you find need to find someone who will take money for “support”, but it’s not about support, it’s about paying for what Intel uses.4

But why? Intel is a large company with lots of money. If they were taken to court, it’d be easy to convince a jury that big bad Intel is taking advantage of people. So they insist on paying for everything.

During my 22 years there, I heard the following several times, “if you ever end up on the stand in court, there will be a lawyer who is much much smarter than you who will make you look like an evil idiot”

So why couldn’t I release my Perl module on github or wherever?

How do I know my module is 100% my code? How do I know I didn’t copy some code from Stackoverflow. By releasing my module, I’d (as someone working at Intel) be open sourcing someone else’s code. That someone did not give Intel permission to do that.

When I was discouraged from opening my code, it wasn’t about being overprotective about Intel’s IP. There’s very little that I know that would be of any interest to NVidia, AMD/ATI, TSMC, Apple… To get what I know, all they’d have to do is hire me. I know lots of people that have switched to those companies.

It wasn’t about protecting Intel’s IP, it was about protecting the IP of others, or more accurately, not stepping on the rights of others ourselves. Don’t want to end up on the stand against the smart lawyer.

Thankfully, since leveldb was already open sourced by Google, Mojang had no choice but to release their own changes.

As far as I can tell, the only changes they made was to add some additional compression to the format. If they hadn’t done that, I imagine we wouldn’t have gotten a leveldb from them at all. We’d have no idea which version of the code applies.

I do believe that Mojang wants to be open. It’s core to the philosophy of Minecraft.

End tangent

Getting leveldb-mcpe to compile/work

Although it burned a bunch of time figuring it out, the answer is easy. Two things:

  • The existing code includes <snappy/snappy.h>. On my ArchLinux system, I need to include <snappy.h> instead.
  • There’s a file table_test.cc which wants the function port::Snappy_Compress, but it’s missing. Just comment that line out. It’s only benchmarking stuff and doesn’t matter if you’re just trying to parse a minecraft world.

Stupid easy, but my experience as a programmer didn’t let me believe it at first. I searched for old versions and figured that if one thing’s missing, what’s next.

Parsing the actual data

Big/little endian

On the minecraft wiki, several mentions are made towards both big and little endian, but all of the data I came across is the same format. I use this function to extract all 4 byte numbers:

int32_t get_intval(leveldb::Slice slice, uint32_t offset)
 {
     int32_t retval = 0;
     for(int i=0; i<4; i++) {         // if I don't do the static cast, the top bit will be sign extended.         retval |= (static_cast(slice[offset+i])<<i*8);
     }
     return retval;
 }
NBT Data

All NBT elements have a name. That name is often a zero length string, but there’s a name. No big deal.

NBT strings also have a name. So basically two strings combined into one.

Parsing the rest

I won’t write anything about that. it’s either covered on the Minecraft wiki or easy to get out my code. The relevant file is this one. Note that I only pay attention to the block code. Mobs and players are ignored in the current version.

It’s not a particularly large file.

Clustering ores

To cluster the ores, I used an algorithm that’s probably overkill. I compute a Euclidean Minimum Spanning Tree. The algorithm for MST is one that CS majors learn but that algorithm requires a graph. The easy answer is a complete graph but if you have 1000 nodes, that’s a million edges. Instead you run on a triangulation. Specifically the Delaunay triangulation. CGAL and Boost libraries to the rescue.

I guess that’s it. It feels kind of abrupt, but I can’t think of additional relevant details. Comments and questions are welcome.

Next Steps

Minecraft behavior is often a mystery. One thought I have is creating a module that could occasionally run on a server that scrapes interesting data about your world and maybe presents it on a website. One example that comes to mind is village data. Where are your village centers? Perhaps you accidentally merged multiple villages. Is it cheating to find out?

Would this be interesting?

Please like, share, comment and subscribe. And don’t forget to click the notification bell.

Oh wait, this is a blog. I’d love to get comments though.


  1. I actually bought it for my daughter on the Google playstore probably five years ago, but she wasn’t interested. Now, she’s as hooked as the rest of us.

  2. “next to” does not include diagonal

  3. There are three kinds of people in the world. Those that can do math, and those that can’t

  4. Sadly, they really want to pay a company. We once tried to get Intel to pay a gdb developer to fix some bugs that were biting us. No luck.