splosh

minecraft9 min read

Minecraft rain gives away your coordinates

If you stand still in the rain for about a second in a Minecraft video, I can tell you the exact block you are standing on. Not from the terrain and not from the F3 screen. Just from the rain.

The picture above is what my detector drew on a clip of mine. Every label is one column of rain it recognised: the block that column is over, and how fast its rain falls. The answer is in the top right corner.

This post explains how, without assuming you know how the game works inside. There are a few things to play with on the way down. Part two is about a second thing the rain leaks: what tick the game is on.

Rain is not random

Rain in Minecraft looks like thousands of drops. It is really much simpler. Around the player, every block gets one flat, see-through sheet with a picture of raindrops on it, and the picture slides downward. That is all rain is: a few hundred sliding pictures.

Here is the part that matters. Every sheet slides at its own speed. One block's rain falls a little faster than its neighbour's. You never notice, because the difference is small and it all looks like rain.

Below are six neighbouring blocks, slowed down. Each has one green drop so you can follow it. Press Line them up and watch them drift apart.

Real rain is hard to see in a recording, because it is blue on a blue sky. So here is a clip of mine with a trick applied: everything that does not move has been subtracted, which leaves only the rain, in white.

the real thing, four times slower. Every streak belongs to one of those sheets

Now keep every streak from a second and a half of that clip in one picture, and you get the path each drop took:

The path of every raindrop over a second and a half, drawn as white lines on black
every drop's path over a second and a half. They all fall straight down, the fan shape is only perspective. The little arcs at the bottom are splashes

Each drop stays in its own lane. That is what a sliding picture looks like.

Where the speed comes from

So where does a block get its speed? The game makes it up from the block's coordinates. Here is the code that does it. It is Java, from a class in the game called WeatherEffectRenderer. The comments are mine.

javaWeatherEffectRenderer, 26.3
// every block around the camera gets one sheet of rain
for (int z = cameraZ - radius; z <= cameraZ + radius; z++) {
    for (int x = cameraX - radius; x <= cameraX + radius; x++) {
        // mash the block's x and z into one number (^ is XOR)
        int seed = (x * x * 3121 + x * 45238971)
                 ^ (z * z * 418711 + z * 13761);
        // restart the random number generator from that number
        random.setSeed(seed);
        // the first number out is 0 to 1. add 3, that is the speed
        float speed = 3.0F + random.nextFloat();
    }
}

I cut the lines about terrain height, biomes and lighting, folded a small helper method into the loop, and renamed a few variables. The numbers and the order of the steps are the game's.

Look at the seed line again. The only things that go in are x and z. Not the world seed. Not the server. Not the time of day. Nothing secret at all.

setSeed and nextFloat look like magic, but inside they are three lines of arithmetic:

javaSingleThreadedRandomSource, 26.3
// setSeed: scramble the seed, keep the lowest 48 bits
long state = (seed ^ 0x5DEECE66DL) & 0xFFFFFFFFFFFFL;
// nextFloat: multiply, add 11, keep 48 bits again
state = (state * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL;
// then take the top 24 bits and scale them to 0 up to 1
float first = (int) (state >> 24) * 5.9604645E-8F;

It is the same generator as plain Java's java.util.Random, so you can check all of this without the game. Save this as Rain.java and run java Rain.java:

java
import java.util.Random;

public class Rain {
    // the game's two steps: seed from the block, first number out
    static float rainSpeed(int x, int z) {
        Random random = new Random();
        random.setSeed((x * x * 3121 + x * 45238971)
                     ^ (z * z * 418711 + z * 13761));
        return 3.0F + random.nextFloat();
    }

    public static void main(String[] args) {
        System.out.println(rainSpeed(1234, -5678));   // 3.650455
    }
}

So the block at X 1234, Z -5678 has a rain speed of 3.6505 in your world, in my world, on every server, forever.

Type any coordinates here and you get the real speeds the game uses around that spot:

Why that is a fingerprint

One speed on its own tells you nothing. Millions of blocks have a speed close to 3.65.

But you are never looking at one block's rain. You are looking at the rain over the eight blocks around you, and the ones behind those. A handful of speeds, in a particular arrangement. That combination is like a fingerprint: it only exists in one place.

Try it. Pick somewhere to hide. The box shows the eight speeds a camera would read there, rounded off the way a real video measurement would be. Then press Find me. The search does not get your coordinates, only those eight numbers, and it tries every block in a 4001 by 4001 area:

Watch the counts. The first number alone fits a quarter of a million places. Two numbers together fit a few thousand. By the fifth there is usually one block left, and it is yours.

The whole search is this. It is not the game's code any more, it is what my tool does, and it uses the rainSpeed function from above:

javathe search
// what the video told us: where each rain column is,
// in blocks from the player, and how fast it falls
int[] dx = {-1, 0, 1};
int[] dz = {-1, -1, -1};
float[] seen = {3.264F, 3.778F, 3.102F};   // 15 to 20 in a real video

// try every block the player could be standing on
for (int x = -100_000; x <= 100_000; x++) {
    for (int z = -100_000; z <= 100_000; z++) {
        boolean fits = true;
        // would the game give those columns these speeds from here?
        for (int i = 0; i < seen.length && fits; i++) {
            float real = rainSpeed(x + dx[i], z + dz[i]);
            fits = Math.abs(real - seen[i]) < 0.008F;
        }
        if (fits) System.out.println("found: " + x + ", " + z);
    }
}

That is 40 billion places. The real tool, RainCoords, does the same loop in C++ and gets through it in about ten seconds.

Getting the speeds out of a video

The hard part is not the search. It is reading those speeds off a video to three decimal places, when the rain is a faint blue smear over a compressed stream.

A patch of sky from a recording, as recorded on the left and with the background subtracted on the right
left: a patch of sky from a 4K recording, which is what the detector has to work with. right: the same patch with the background subtracted and the contrast turned up

Here is the trick. Hold the camera still and stare at one pixel. Drops pass through it, so the pixel blinks. Because the raindrop picture repeats as it slides, the blinking repeats too, at a steady rate:

java
// each tick slides the picture by speed / 32, and there are 20 a second
float blinksPerSecond = speed / 32.0F * 20;   // 1.9 to 2.5

So measuring speed turns into measuring how fast pixels blink, and computers are very good at that. A video has thousands of pixels looking at each sheet of rain, and they all blink at that sheet's rate.

Before that works, the detector has to figure out which pixels belong to which block. For that it needs to know how the sheets are laid out:

How the rain sheets stand around the player, seen from above
seen from above: one sheet per block, each one turned to face the block the player is in

Each sheet is one block wide, goes through the middle of its block, and is turned to face the player's block. Since everything is locked to the block grid, the detector can work out the camera's field of view, which way it is tilted, and where inside its block the player stands, all from the rain. I will spare you the details. The short version is that it finds each sheet, measures how far away it is, and then fits a grid to them.

Does it work

On real footage, yes.

Footage What happened
A stranger's year-old stream, 1080p Found the block. It gave the same answer from three different moments in the video, and still worked when given a single second.
My own 4K clip Found the exact block I was standing on. It also worked out my FOV setting: 110.
A second clip of mine with the minimap showing Matched the coordinates on the minimap.
An edited YouTube video where I assumed the rain was a stock effect It was real rain. Ten columns matched one spot, under two hundred blocks from that world's 0, 0.
16 fake test clips at random places 16 out of 16.

How sure is it? In the clip below 21 columns were read and all 21 match the game's speeds at that spot. The odds of that happening by luck somewhere in a 200,000 block wide area are about one in ten billion billion billion.

X -1080, Z -3840. Each label is a rain column, with the block it is over and how fast it falls

What stops it

  • Moving. It needs the camera to stay on the same block. Turning to look around can be undone, though I have only tested that on footage I rotated myself. Walking cannot.
  • Very short stops. Heavy rain on a decent stream needs about one second. Thin rain on a blurry video needs a few.
  • Resource packs that change the rain. The detector matches the pattern of drops in the rain picture. My own pack had quietly removed two thirds of the drops, and it took me a while to notice why my clips were harder than the stream.
  • Snow. Snow uses different maths. I have not looked at it.
  • Height. It finds X and Z, not Y.

How to not get found

The leak is in how your own game draws rain, so only you can fix it:

  • Do not stand still in the rain on stream. One second is enough.
  • A resource pack that makes the rain picture fully invisible should hide the sheets completely. A pack that only thins the rain, like mine, does not help.
  • A stream delay does nothing. The information is in the picture, whenever people see it.

The proper fix is Mojang's: mix something that is different in every world into that seed line, and all of this stops working.

The detector is open source. The code is on GitHub at skippyznjiffy/raincoords, MIT licensed.

Next: the rain is also a clock.