├── .gitignore
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── dependency-reduced-pom.xml
├── pom.xml
└── src
└── main
└── java
└── com
└── mike
├── BedrockBlock.java
├── BedrockReader.java
├── Main.java
├── extracted
├── AbstractRandom.java
├── GaussianGenerator.java
├── MathHelper.java
├── RandomDeriver.java
├── RandomProvider.java
├── RandomSeed.java
├── Xoroshiro128PlusPlusRandom.java
└── Xoroshiro128PlusPlusRandomImpl.java
└── recreated
├── BlockPos.java
└── Identifier.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "code-runner.executorMap": {
3 | "java": "mvn package && java -jar ./target/bedrockformation-1.2.jar 123 0 0 1000 1000 -64 -60"
4 | }
5 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 mika.dev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Minecraft Bedrock Finder (1.18-1.21)
2 | This repo contains the code snippet to generate a Minecraft map of the Bedrock for a given seed in a given region.
3 |
4 | ## Usage
5 | This code is just a demo and needs to be modified to be used effectively.
6 |
7 | The main class is the [`BedrockReader`](https://github.com/Developer-Mike/minecraft-bedrock-generator/blob/main/src/main/java/com/mike/BedrockReader.java) class and has a `.isBedrock(int x, int y, int z)` method that returns true if the block at the given coordinates is bedrock.
8 | ```java
9 | BedrockReader bedrockReader = new BedrockReader(seed);
10 | boolean bedrock = bedrockReader.isBedrock(x, y, z);
11 | ```
12 |
13 | To compile the code to a jar file, you can use the following command:
14 | ```bash
15 | mvn package
16 | ```
--------------------------------------------------------------------------------
/dependency-reduced-pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | mike
5 | bedrockgen
6 | 1.0
7 |
8 |
9 |
10 | maven-jar-plugin
11 | 3.2.2
12 |
13 |
14 |
15 | com.mike.Main
16 |
17 |
18 |
19 |
20 |
21 | maven-shade-plugin
22 | 3.2.4
23 |
24 |
25 | package
26 |
27 | shade
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 17
36 | 17
37 |
38 |
39 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | mike
8 | bedrockgen
9 | 1.0
10 |
11 |
12 | 17
13 | 17
14 |
15 |
16 |
17 |
18 | com.google.guava
19 | guava
20 | 31.0.1-jre
21 |
22 |
23 |
24 |
25 |
26 |
27 | org.apache.maven.plugins
28 | maven-jar-plugin
29 | 3.2.2
30 |
31 |
32 |
33 | com.mike.Main
34 |
35 |
36 |
37 |
38 |
39 |
40 | org.apache.maven.plugins
41 | maven-shade-plugin
42 | 3.2.4
43 |
44 |
45 | package
46 |
47 | shade
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/BedrockBlock.java:
--------------------------------------------------------------------------------
1 | package com.mike;
2 |
3 | public class BedrockBlock {
4 | int x;
5 | int y;
6 | int z;
7 | boolean shouldBeBedrock;
8 |
9 | // Example 1,0,2:1
10 | public BedrockBlock(String arg) {
11 | String[] coordinates = arg.split(":")[0].split(",");
12 | x = Integer.parseInt(coordinates[0]);
13 | y = Integer.parseInt(coordinates[1]);
14 | z = Integer.parseInt(coordinates[2]);
15 |
16 | shouldBeBedrock = Integer.parseInt(arg.split(":")[1]) == 1;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return "BedrockBlock{" +
22 | "x=" + x +
23 | ", y=" + y +
24 | ", z=" + z +
25 | ", shouldBeBedrock=" + shouldBeBedrock +
26 | '}';
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/BedrockReader.java:
--------------------------------------------------------------------------------
1 | package com.mike;
2 |
3 | import com.mike.extracted.AbstractRandom;
4 | import com.mike.extracted.MathHelper;
5 | import com.mike.extracted.RandomDeriver;
6 | import com.mike.extracted.RandomProvider;
7 | import com.mike.recreated.Identifier;
8 |
9 | public class BedrockReader {
10 | RandomDeriver floorRandomDeriver;
11 | RandomDeriver roofRandomDeriver;
12 |
13 | public BedrockReader(long seed) {
14 | floorRandomDeriver = RandomProvider.XOROSHIRO
15 | .create(seed).createRandomDeriver()
16 | .createRandom(BedrockType.BEDROCK_FLOOR.id.toString()).createRandomDeriver();
17 |
18 | roofRandomDeriver = RandomProvider.XOROSHIRO
19 | .create(seed).createRandomDeriver()
20 | .createRandom(BedrockType.BEDROCK_ROOF.id.toString()).createRandomDeriver();
21 | }
22 |
23 | boolean isBedrock(int x, int y, int z) {
24 | double probabilityValue = 0;
25 |
26 | BedrockType bedrockType = y < 0 ? BedrockType.BEDROCK_FLOOR : BedrockType.BEDROCK_ROOF;
27 | if (bedrockType == BedrockType.BEDROCK_FLOOR) {
28 | if (y == bedrockType.min) return true;
29 | if (y > bedrockType.max) return false;
30 |
31 | probabilityValue = MathHelper.lerpFromProgress(y, bedrockType.min, bedrockType.max, 1.0, 0.0);
32 | } else if (bedrockType == BedrockType.BEDROCK_ROOF) {
33 | if (y == bedrockType.min) return true;
34 | if (y < bedrockType.max) return false;
35 |
36 | probabilityValue = MathHelper.lerpFromProgress(y, bedrockType.max, bedrockType.min, 1.0, 0.0);
37 | }
38 |
39 | RandomDeriver randomDeriver = bedrockType == BedrockType.BEDROCK_FLOOR ? floorRandomDeriver : roofRandomDeriver;
40 | AbstractRandom abstractRandom = randomDeriver.createRandom(x, y, z);
41 | return (double)abstractRandom.nextFloat() < probabilityValue;
42 | }
43 |
44 | public enum BedrockType {
45 | BEDROCK_FLOOR(new Identifier("bedrock_floor"), -64, -64 + 5),
46 | BEDROCK_ROOF(new Identifier("bedrock_roof"), 128, 128 - 5);
47 |
48 | public final Identifier id;
49 | public final int min;
50 | public final int max;
51 |
52 | BedrockType(Identifier id, int min, int max) {
53 | this.id = id;
54 | this.min = min;
55 | this.max = max;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/Main.java:
--------------------------------------------------------------------------------
1 | package com.mike;
2 |
3 | public class Main {
4 | public static void main(String[] args) {
5 | long seed = Long.parseLong(args[0]);
6 | int x = Integer.parseInt(args[1]);
7 | int z = Integer.parseInt(args[2]);
8 | int xSize = Integer.parseInt(args[3]);
9 | int zSize = Integer.parseInt(args[4]);
10 | int minY = Integer.parseInt(args[5]);
11 | int maxY = Integer.parseInt(args[6]);
12 |
13 | boolean[][][] bedrock = getBedrockMap(seed, x, z, xSize, zSize, minY, maxY);
14 |
15 | while (true) {
16 | try {
17 | String coordinates = System.console().readLine();
18 | String[] splitCoordinates = coordinates.split(" ");
19 |
20 | int xCoord = Integer.parseInt(splitCoordinates[0]) - x;
21 | int zStartCoord = Integer.parseInt(splitCoordinates[1]) - z;
22 | int zEndCoord = Integer.parseInt(splitCoordinates[2]) - z;
23 |
24 | // For y values, we will just print the bedrock value at the first y value
25 | for (int yCoord = maxY; yCoord >= minY; yCoord--) {
26 | String row = "";
27 |
28 | for (int zCoord = zStartCoord; zCoord <= zEndCoord; zCoord++) {
29 | row += bedrock[xCoord][yCoord - minY][zCoord] ? "X" : " ";
30 | }
31 |
32 | System.out.println(row);
33 | }
34 | } catch (NumberFormatException e) {
35 | System.out.println("Invalid input");
36 | } catch (ArrayIndexOutOfBoundsException e) {
37 | System.out.println("Coordinates out of bounds");
38 | }
39 | }
40 | }
41 |
42 | static boolean[][][] getBedrockMap(long seed, int x, int z, int xSize, int zSize, int minY, int maxY) {
43 | BedrockReader bedrockReader = new BedrockReader(seed);
44 |
45 | boolean[][][] bedrock = new boolean[xSize][maxY - minY + 1][zSize];
46 |
47 | for (int i = 0; i < xSize; i++) {
48 | for (int j = 0; j < zSize; j++) {
49 | for (int k = 0; k < maxY - minY + 1; k++) {
50 | bedrock[i][k][j] = bedrockReader.isBedrock(x + i, minY + k, z + j);
51 | }
52 | }
53 | }
54 |
55 | return bedrock;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/AbstractRandom.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | public interface AbstractRandom {
4 | public AbstractRandom derive();
5 |
6 | public RandomDeriver createRandomDeriver();
7 |
8 | public void setSeed(long var1);
9 |
10 | public int nextInt();
11 |
12 | public int nextInt(int var1);
13 |
14 | default public int nextBetween(int min, int max) {
15 | return this.nextInt(max - min + 1) + min;
16 | }
17 |
18 | public long nextLong();
19 |
20 | public boolean nextBoolean();
21 |
22 | public float nextFloat();
23 |
24 | public double nextDouble();
25 |
26 | public double nextGaussian();
27 |
28 | default public void skip(int count) {
29 | for (int i = 0; i < count; ++i) {
30 | this.nextInt();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/GaussianGenerator.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | public class GaussianGenerator {
4 | public final AbstractRandom baseRandom;
5 | private double nextNextGaussian;
6 | private boolean hasNextGaussian;
7 |
8 | public GaussianGenerator(AbstractRandom baseRandom) {
9 | this.baseRandom = baseRandom;
10 | }
11 |
12 | public void reset() {
13 | this.hasNextGaussian = false;
14 | }
15 |
16 | public double next() {
17 | double e;
18 | double d;
19 | double f;
20 | if (this.hasNextGaussian) {
21 | this.hasNextGaussian = false;
22 | return this.nextNextGaussian;
23 | }
24 | do {
25 | d = 2.0 * this.baseRandom.nextDouble() - 1.0;
26 | e = 2.0 * this.baseRandom.nextDouble() - 1.0;
27 | } while ((f = MathHelper.square(d) + MathHelper.square(e)) >= 1.0 || f == 0.0);
28 | double g = Math.sqrt(-2.0 * Math.log(f) / f);
29 | this.nextNextGaussian = e * g;
30 | this.hasNextGaussian = true;
31 | return d * g;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/MathHelper.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | public class MathHelper {
4 | public static double getLerpProgress(double value, double start, double end) {
5 | return (value - start) / (end - start);
6 | }
7 |
8 | public static double lerp(double delta, double start, double end) {
9 | return start + delta * (end - start);
10 | }
11 |
12 | public static double lerpFromProgress(double lerpValue, double lerpStart, double lerpEnd, double start, double end) {
13 | return MathHelper.lerp(MathHelper.getLerpProgress(lerpValue, lerpStart, lerpEnd), start, end);
14 | }
15 |
16 | public static double square(double n) {
17 | return n * n;
18 | }
19 |
20 | public static long hashCode(int x, int y, int z) {
21 | long l = (long)(x * 3129871) ^ (long)z * 116129781L ^ (long)y;
22 | l = l * l * 42317861L + l * 11L;
23 | return l >> 16;
24 | }
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/RandomDeriver.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | import com.mike.recreated.BlockPos;
4 | import com.mike.recreated.Identifier;
5 |
6 | public interface RandomDeriver {
7 | default public AbstractRandom createRandom(BlockPos pos) {
8 | return this.createRandom(pos.x, pos.y, pos.z);
9 | }
10 |
11 | default public AbstractRandom createRandom(Identifier id) {
12 | return this.createRandom(id.toString());
13 | }
14 |
15 | public AbstractRandom createRandom(String var1);
16 |
17 | public AbstractRandom createRandom(int var1, int var2, int var3);
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/RandomProvider.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | import java.util.function.LongFunction;
4 |
5 | public enum RandomProvider {
6 | XOROSHIRO(Xoroshiro128PlusPlusRandom::new);
7 |
8 | private final LongFunction provider;
9 |
10 | private RandomProvider(LongFunction provider) {
11 | this.provider = provider;
12 | }
13 |
14 | public AbstractRandom create(long seed) {
15 | return this.provider.apply(seed);
16 | }
17 | }
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/RandomSeed.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | import java.util.concurrent.atomic.AtomicLong;
4 |
5 | public final class RandomSeed {
6 | public static final long XOROSHIRO64_SEED_LO_FALLBACK = -7046029254386353131L;
7 | public static final long XOROSHIRO64_SEED_HI_FALLBACK = 7640891576956012809L;
8 | private static final AtomicLong SEED_UNIQUIFIER = new AtomicLong(8682522807148012L);
9 |
10 | public static long nextSplitMix64Int(long seed) {
11 | seed = (seed ^ seed >>> 30) * -4658895280553007687L;
12 | seed = (seed ^ seed >>> 27) * -7723592293110705685L;
13 | return seed ^ seed >>> 31;
14 | }
15 |
16 | public static XoroshiroSeed createXoroshiroSeed(long seed) {
17 | long l = seed ^ 0x6A09E667F3BCC909L;
18 | long m = l + -7046029254386353131L;
19 | return new XoroshiroSeed(RandomSeed.nextSplitMix64Int(l), RandomSeed.nextSplitMix64Int(m));
20 | }
21 |
22 | public static long getSeed() {
23 | return SEED_UNIQUIFIER.updateAndGet(seedUniquifier -> seedUniquifier * 1181783497276652981L) ^ System.nanoTime();
24 | }
25 |
26 | public record XoroshiroSeed(long seedLo, long seedHi) {
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/Xoroshiro128PlusPlusRandom.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | import com.google.common.base.Charsets;
4 | import com.google.common.hash.HashFunction;
5 | import com.google.common.hash.Hashing;
6 | import com.google.common.primitives.Longs;
7 |
8 | public class Xoroshiro128PlusPlusRandom implements AbstractRandom {
9 | private static final float FLOAT_MULTIPLIER = 5.9604645E-8f;
10 | private static final double DOUBLE_MULTIPLIER = (double) 1.110223E-16f;
11 | private Xoroshiro128PlusPlusRandomImpl implementation;
12 | private final GaussianGenerator gaussianGenerator = new GaussianGenerator(this);
13 |
14 | public Xoroshiro128PlusPlusRandom(long seed) {
15 | this.implementation = new Xoroshiro128PlusPlusRandomImpl(RandomSeed.createXoroshiroSeed(seed));
16 | }
17 |
18 | public Xoroshiro128PlusPlusRandom(long seedLo, long seedHi) {
19 | this.implementation = new Xoroshiro128PlusPlusRandomImpl(seedLo, seedHi);
20 | }
21 |
22 | @Override
23 | public AbstractRandom derive() {
24 | return new Xoroshiro128PlusPlusRandom(this.implementation.next(), this.implementation.next());
25 | }
26 |
27 | @Override
28 | public com.mike.extracted.RandomDeriver createRandomDeriver() {
29 | return new RandomDeriver(this.implementation.next(), this.implementation.next());
30 | }
31 |
32 | @Override
33 | public void setSeed(long l) {
34 | this.implementation = new Xoroshiro128PlusPlusRandomImpl(RandomSeed.createXoroshiroSeed(l));
35 | this.gaussianGenerator.reset();
36 | }
37 |
38 | @Override
39 | public int nextInt() {
40 | return (int) this.implementation.next();
41 | }
42 |
43 | @Override
44 | public int nextInt(int i) {
45 | if (i <= 0) {
46 | throw new IllegalArgumentException("Bound must be positive");
47 | }
48 | long l = Integer.toUnsignedLong(this.nextInt());
49 | long m = l * (long) i;
50 | long n = m & 0xFFFFFFFFL;
51 | if (n < (long) i) {
52 | int j = Integer.remainderUnsigned(~i + 1, i);
53 | while (n < (long) j) {
54 | l = Integer.toUnsignedLong(this.nextInt());
55 | m = l * (long) i;
56 | n = m & 0xFFFFFFFFL;
57 | }
58 | }
59 | long o = m >> 32;
60 | return (int) o;
61 | }
62 |
63 | @Override
64 | public long nextLong() {
65 | return this.implementation.next();
66 | }
67 |
68 | @Override
69 | public boolean nextBoolean() {
70 | return (this.implementation.next() & 1L) != 0L;
71 | }
72 |
73 | @Override
74 | public float nextFloat() {
75 | return (float) this.next(24) * 5.9604645E-8f;
76 | }
77 |
78 | @Override
79 | public double nextDouble() {
80 | return (double) this.next(53) * (double) 1.110223E-16f;
81 | }
82 |
83 | @Override
84 | public double nextGaussian() {
85 | return this.gaussianGenerator.next();
86 | }
87 |
88 | @Override
89 | public void skip(int count) {
90 | for (int i = 0; i < count; ++i) {
91 | this.implementation.next();
92 | }
93 | }
94 |
95 | private long next(int bits) {
96 | return this.implementation.next() >>> 64 - bits;
97 | }
98 |
99 | public static class RandomDeriver implements com.mike.extracted.RandomDeriver {
100 | private static final HashFunction MD5_HASHER = Hashing.md5();
101 | private final long seedLo;
102 | private final long seedHi;
103 |
104 | public RandomDeriver(long seedLo, long seedHi) {
105 | this.seedLo = seedLo;
106 | this.seedHi = seedHi;
107 | }
108 |
109 | @Override
110 | public AbstractRandom createRandom(int x, int y, int z) {
111 | long l = MathHelper.hashCode(x, y, z);
112 | long m = l ^ this.seedLo;
113 | return new Xoroshiro128PlusPlusRandom(m, this.seedHi);
114 | }
115 |
116 | @Override
117 | public AbstractRandom createRandom(String string) {
118 | byte[] bs = MD5_HASHER.hashString(string, Charsets.UTF_8).asBytes();
119 | long l = Longs.fromBytes(bs[0], bs[1], bs[2], bs[3], bs[4], bs[5], bs[6], bs[7]);
120 | long m = Longs.fromBytes(bs[8], bs[9], bs[10], bs[11], bs[12], bs[13], bs[14], bs[15]);
121 | return new Xoroshiro128PlusPlusRandom(l ^ this.seedLo, m ^ this.seedHi);
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/extracted/Xoroshiro128PlusPlusRandomImpl.java:
--------------------------------------------------------------------------------
1 | package com.mike.extracted;
2 |
3 | public class Xoroshiro128PlusPlusRandomImpl {
4 | private long seedLo;
5 | private long seedHi;
6 |
7 | public Xoroshiro128PlusPlusRandomImpl(RandomSeed.XoroshiroSeed seed) {
8 | this(seed.seedLo(), seed.seedHi());
9 | }
10 |
11 | public Xoroshiro128PlusPlusRandomImpl(long seedLo, long seedHi) {
12 | this.seedLo = seedLo;
13 | this.seedHi = seedHi;
14 | if ((this.seedLo | this.seedHi) == 0L) {
15 | this.seedLo = -7046029254386353131L;
16 | this.seedHi = 7640891576956012809L;
17 | }
18 | }
19 |
20 | public long next() {
21 | long l = this.seedLo;
22 | long m = this.seedHi;
23 | long n = Long.rotateLeft(l + m, 17) + l;
24 | this.seedLo = Long.rotateLeft(l, 49) ^ (m ^= l) ^ m << 21;
25 | this.seedHi = Long.rotateLeft(m, 28);
26 | return n;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/recreated/BlockPos.java:
--------------------------------------------------------------------------------
1 | package com.mike.recreated;
2 |
3 | public class BlockPos {
4 | public int x;
5 | public int y;
6 | public int z;
7 |
8 | public BlockPos(int x, int y, int z) {
9 | this.x = x;
10 | this.y = y;
11 | this.z = z;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/mike/recreated/Identifier.java:
--------------------------------------------------------------------------------
1 | package com.mike.recreated;
2 |
3 | public class Identifier {
4 | static final String DEFAULT_NAMESPACE = "minecraft";
5 | String id;
6 |
7 | public Identifier(String path) {
8 | this.id = DEFAULT_NAMESPACE + ":" + path;
9 | }
10 |
11 | @Override
12 | public String toString() {
13 | return this.id;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------