Closed MiranCZ closed 2 months ago
It's been some time but I can probably still give an overview. You're correct in that I combine seeds in sets of 2^12. And only iterate over the upper 2^36 bits.
First of all, the floating point conversion is unnecessary, annoying and can be left out like this: ((mainSeed ^ MathHelper.hashCode(x,y,z)) * MULTIPLY + ADD & MASK) < HEIGHT_VALUE_INT
If you look at the code, you'll notice that two consecutive seeds(changing the last bit) can only result in two outputs that are at max one times the multiplier away from each other.
Formulated in code: abs((mainSeed ^ MathHelper.hashCode(x,y,z)) MULTIPLY + ADD & MASK) - ((mainSeed^1) ^ MathHelper.hashCode(x,y,z)) MULTIPLY + ADD & MASK)) <= 1*MULTIPLY
4 consecutive seeds(changing the bottom 2 bits) result in a range of outputs, that is not wider than 3*MULTIPLY
8 consecutive seeds(changing the bottom 3 bits) result in a range of outputs, that is not wider than 7*MULTIPLY
Changing the bottom N bits results in 2^^N consecutive seeds and a range of outputs that is (2^^N - 1)*Multiply big
This range is the maximal amount of error that you get when comparing to a value with a truncated seed.
In code: long out = ((truncatedSeed ^ MathHelper.hashCode(x,y,z)) MULTIPLY + ADD & MASK); long max_error = (2^^N - 1)Multiply; // Account for overflow if (out + max_error < HEIGHT_VALUE_INT || (out - max_error)%MASK < HEIGHT_VALUE_INT) { //check against the next block } else { //all seeds in this range are invalid }
After checking that a seed range is valid for all blocks, I split the range in half and run both halves through the checks again. This time the checks are more precise due to having one lower bit less. Doing this just recursively until the seed ranges consist of single seeds. If all checks pass, the seeds get displayed.
I hope I could help you. There might be some inaccuracies since it's been a while
Oh my god, that's smart!! Thank you so much
Hello, I was thinking about making a mod in Java with the same functionality... If you don't mind, I would just like to ask what is the general idea behind the algorithm to get the "main seed" of the generator for the bedrock? I have looked at the Minecraft's code, to see how it generates the bedrock in the nether and I think I have at least surface level understanding on how it works... If I understood it correctly, the only information you are given is that
(((mainSeed ^ MathHelper.hashCode(x,y,z)) * MULTIPLY + ADD & MASK) >> 24) * (1f/(1<<24)) < HEIGHT_VALUE
whereHEIGHT_VALUE
is calculated based on they
coordinate and the range where the bedrock generates. AndmainSeed
is unknown... The naive approach I thought of was just to go trough all 2^48 possibilities and calculate if it fits the bedrock pattern for each one, but I feel like there must be some better approach to this. I tried to look at the source code of this repository, but I don't really understand Rust😅... I ended up going through thelib.rs
andlayer.rs
files and it almost seems like you are discarding the 12 bottom bits and just calculating with the upper 36? I completely understand it you don't want to answer...