Skip to content

Instantly share code, notes, and snippets.

@syule
Last active January 4, 2024 22:07
Show Gist options
  • Save syule/4acbc2e1aba251db6caa7d50a0afe546 to your computer and use it in GitHub Desktop.
Save syule/4acbc2e1aba251db6caa7d50a0afe546 to your computer and use it in GitHub Desktop.
// compile with: nvcc -ccbin=g++-5 -O3 -std=c++11 -arch compute_60 -x cu seedsearch.cpp -o seedsearch
// edit the flat_chunks variable with the x, z chunk coordinates of ocean monuments
// the tallest part of each monument is on the north-west corner of the center chunk
// reddit username osmotischen
#include <cuda.h>
#include <cuda_runtime.h>
#include <iostream>
#include <numeric>
#include <functional>
#include <fstream>
#include <stdio.h>
#include <cassert>
#include <vector>
#include <algorithm>
#include <chrono>
#include <inttypes.h>
#include <thrust/logical.h>
#include <thrust/sequence.h>
#include <thrust/functional.h>
#include <thrust/device_vector.h>
#include <thrust/device_ptr.h>
#include <thrust/extrema.h>
#include <thrust/device_malloc.h>
#include <thrust/device_free.h>
#include <thrust/execution_policy.h>
typedef int64_t lng;
typedef uint64_t ulng;
//2^28 checks per launch means we need 2^20 launches
const int lg_launches = 20;
const int lg_blocks = 23;
const int lg_threads = 5; //fits in a warp perfectly!
const int num_launches = 1 << lg_launches;
const int num_blocks = 1 << lg_blocks;
const int num_threads = 1 << lg_threads;
const int spacing = 32;
const int separation = 5;
const int gap = spacing - separation;
const lng struct_seed = 10387313;
const lng mask = (1LL << 48) - 1LL;
const lng mask32 = (1LL << 32) - 1LL;
const lng mask16 = (1LL << 16) - 1LL;
const lng lcg1 = 0x5DEECE66DLL;
const lng lcg2 = 0xBLL;
const lng lcg3 = 341873128712LL;
const lng lcg4 = 132897987541LL;
const lng inv_lcg1 = 0xDFE05BCB1365LL;
const bool check_all = true;
__device__ __host__ lng set_seed(lng seed) {
return (seed ^ lcg1) & mask;
}
__device__ __host__ lng update_seed(lng seed) {
return (seed * lcg1 + lcg2) & mask;
}
__device__ __host__ int nextInt(lng &seed) {
int bits;
int val;
do {
seed = update_seed(seed);
//unsigned to make this an arithmetic shift
bits = (int) ((ulng)seed >> (48-31));
val = bits % gap;
} while (bits-val+gap-1 < 0);
return val;
}
__device__ __host__ void rand4_for_seed(int arg1, int arg2, lng seed, int * buffer) {
//first compute the input seed
lng i = (lng)arg1 * lcg3 + (lng)arg2 * lcg4 + struct_seed + seed;
seed = set_seed(i);
for (int j = 0; j < 4; j++) {
buffer[j] = nextInt(seed);
}
}
__device__ __host__ bool check_chunk(int x, int z, lng world_seed) {
int i = x;
int j = z;
if (x < 0) {
x -= spacing - 1;
}
if (z < 0) {
z -= spacing - 1;
}
//rounding should be the same as in java
int k = x/spacing;
int l = z/spacing;
int rand4[4];
rand4_for_seed(k, l, world_seed, rand4);
k *= spacing;
l *= spacing;
k += (rand4[0] + rand4[1])/2;
l += (rand4[2] + rand4[3])/2;
return (i == k) && (j == l);
}
__device__ __host__ bool check_all_chunks(lng world_seed) {
const int flat_chunks[] = {
206, -39,
235, -83,
203, -127,
295, 47,
331, 52,
-11, -334,
-80, -307,
};
for (unsigned int i = 0; i < sizeof(flat_chunks)/sizeof(int)/2; i++) {
if (!check_chunk(flat_chunks[i*2], flat_chunks[i*2+1], world_seed)) {
return false;
}
}
return true;
}
__global__ void run_launch(int launch, bool * results) {
lng seed = ((lng)launch << (lg_blocks+lg_threads)) + ((lng)blockIdx.x << lg_threads) + threadIdx.x;
bool result = check_all_chunks(seed);
bool any_found = __any(result);
if (threadIdx.x == 0) {
results[blockIdx.x] = any_found;
}
}
lng seed_search() {
lng compatible_seed = -1;
bool *block_results;
bool max_elem;
cudaMalloc(&block_results, sizeof(bool)*num_blocks);
auto t0 = std::chrono::high_resolution_clock::now();
//can start at 624635 for debugging
for (int launch = 0; launch < num_launches; launch++) {
if (!(launch % (1 << 10))) {
auto t1 = std::chrono::high_resolution_clock::now();
long d0 = std::chrono::duration_cast<std::chrono::milliseconds>(t1-t0).count();
t0 = t1;
printf("seed %" PRIi64 ", launch %d, time %ld ms\n",
((lng)launch) << (lg_blocks + lg_threads),
launch, d0);
}
run_launch<<<num_blocks,num_threads>>>(launch, block_results);
thrust::device_vector<bool> thrust_results(block_results, block_results+num_blocks);
auto max_idx = thrust::max_element(thrust_results.begin(), thrust_results.end());
int index = max_idx - thrust_results.begin();
cudaMemcpy(&max_elem, block_results + index, sizeof(bool), cudaMemcpyDeviceToHost);
if (max_elem) {
lng seedstart = ((lng)launch << (lg_blocks+lg_threads)) + ((lng)index << lg_threads);
for (lng seed = seedstart; seed < seedstart+num_threads; seed++) {
if (check_all_chunks(seed)) {
if (!check_all) {
return seed;
} else if (compatible_seed == -1) {
printf("found candidate %" PRIi64 "\n", seed);
compatible_seed = seed;
} else {
printf("%" PRIi64 "\n", compatible_seed);
printf("%" PRIi64 "\n", seed);
return -2;
}
}
}
}
}
return compatible_seed;
}
void extend_seed(lng lower48) {
//assert(((lcg1 * inv_lcg1) & mask) == 1LL);
lng lower32 = lower48 & mask32;
lng upper32lower16 = (lower48 >> 32) & mask16;
for (lng i = 0; i < (1LL << 16); i++) {
lng seed2 = (lower32 << 16) | i;
lng seed1 = ((seed2-lcg2) * inv_lcg1) & mask;
lng upper32 = seed1 >> 16;
if (upper32lower16 == (upper32 & mask16)) {
lng candidate = (upper32 << 32) | lower32;
printf("candidate 64 bit extension: %" PRIi64 "\n", candidate);
}
}
}
int main(int argc, char **argv)
{
lng out = seed_search();
//lng out = 167675086332377LL;
//lng out = 255383536937374LL;
if (out == -1) {
printf("no compatible seeds found\n");
} else if (out == -2) {
printf("too many compatible seeds\n");
} else {
printf("lower 48 bits are %" PRIi64 "\n", out);
extend_seed((lng) out);
}
return 0;
}
@xdPhoenyx
Copy link

Hey, I have no experience with C++ and have only ever coded using python or HTML. I was wondering if there is a simple way to run this as I don't really understand how to compile and run C++ code.

@NaNraptor
Copy link

// compile with: nvcc -ccbin=g++-5 -O3 -std=c++11 -arch compute_60 -x cu seedsearch.cpp -o seedsearch
// edit the flat_chunks variable with the x, z chunk coordinates of ocean monuments

You need a c++ compiler, this one is nvcc (NVIDIA CUDA Compiler), so download that and in command line run the command above

@end-user
Copy link

You said this was intended to search based on monument positions but that other things were possible. How would I make changes to match other structures; for example villages?

@felipemslima
Copy link

I've tried to run but had no output

@MrLFW
Copy link

MrLFW commented Aug 5, 2020

I've tried to run but had no output

same
i also tried running
nvcc seedsearch.cpp -o seedsearch
and these errors came out
seedsearch.cpp(128): error C2065: 'blockIdx': undeclared identifier
seedsearch.cpp(128): error C2065: 'threadIdx': undeclared identifier
seedsearch.cpp(130): error C3861: '__any': identifier not found
seedsearch.cpp(132): error C2065: 'threadIdx': undeclared identifier
seedsearch.cpp(133): error C2065: 'blockIdx': undeclared identifier
seedsearch.cpp(158): error C2059: syntax error: '<'

@syule
Copy link
Author

syule commented Aug 6, 2020

@end-user

You said this was intended to search based on monument positions but that other things were possible. How would I make changes to match other structures; for example villages?

It's been quite a long time so I don't remember all the details, but I believe spacing, separation, and struct_seed are specific to the type of structure -- e.g. end cities or villages would have a different set of values for this -- but that otherwise, the algorithm for what's a valid place to put a structure is the same (afaik, but could be wrong). You'd have to dig around in the source code to find these values.

@MrLFW

i also tried running
nvcc seedsearch.cpp -o seedsearch

Since the file extension is .cpp, nvcc will assume the file contains only cpu code. The flag -x cu is necessary (in fact most of the flags above are necessary) for correct compilation.

@felipemslima

I've tried to run but had no output

I would need a bit more information than this -- does it compile without error? Does it exit without any output when you run it, or does it hang?

@dany144
Copy link

dany144 commented Oct 24, 2020

Hi, i'm wondering how to know the program is running, because when i compile it in command prompt, there are no errors but nothing happens either, so i'm not sure if i need to wait until it prints the results or if there is something wrong.

@syule
Copy link
Author

syule commented Oct 24, 2020

Hi, i'm wondering how to know the program is running, because when i compile it in command prompt, there are no errors but nothing happens either, so i'm not sure if i need to wait until it prints the results or if there is something wrong.

Compiling code translates it from a human readable language to a computer readable language. The compilation process outputs an executable file in that computer readable format -- using the provided command, the executable is named "seedsearch".

You still have to run the executable.

When the executable is run, it should print some status message every few seconds. Roughly speaking, a message is printed out for every 0.1% of progress.

@VioletVitto
Copy link

Hi, thank you for the amazing resource. I would like to ask you if you could explain me how to run this command. I have zero experience with c++, and I don't even know what program to use (I downloaded CUDA toolkit, but I have no idea on what to do). I know basically nothing about programming so I was wondering if you could direct me step-by-step on what I have to do to make it work.
Looking forward to your reply, best regards.

@syule
Copy link
Author

syule commented Nov 7, 2020

Hi, thank you for the amazing resource. I would like to ask you if you could explain me how to run this command. I have zero experience with c++, and I don't even know what program to use (I downloaded CUDA toolkit, but I have no idea on what to do). I know basically nothing about programming so I was wondering if you could direct me step-by-step on what I have to do to make it work.
Looking forward to your reply, best regards.

To be honest, this isn't very user friendly, because I'm lazy, and also don't know anything about {various compiler/linker/toolchain things} to put together a binary which "just works" for everyone. And I'm not really fit to provide support for various cuda library issues, because compiler/linker errors give me headaches too.

If you want something you can just run without trouble, there's better stuff out there, for example this just came up in my google search (i've not tried it) https://old.reddit.com/r/technicalminecraft/comments/8pmqq7/legerts_l64_fast_seed_cracker_reverse_seed_finding/
or https://github.com/pruby/slime-seed/tree/7d1d076de85336d99c2844161c0430cb1fda898b unless you're dead set on using ocean monuments for whatever reason, I suggest you try those

If you're still here for some reason, basically you have to you have to

  1. have an NVIDIA gpu
  2. install the cuda toolkit
  3. install the gcc/g++ compiler. on Linux. apparently windows has an equivalent thing called mingw, but I don't use windows so I don't know anything about it
  4. edit the flat_chunks variable until it contains the (x,z) chunk coordinates of some ocean monuments
  5. run the compilation command at the top of the file, possibly specifying a different compute architecture depending on your GPU
  6. solve any compiler errors, probably by fiddling around with LIBRARY_PATH until gcc finds CUDA
  7. run the executable

@VioletVitto
Copy link

Hi, thank you for the amazing resource. I would like to ask you if you could explain me how to run this command. I have zero experience with c++, and I don't even know what program to use (I downloaded CUDA toolkit, but I have no idea on what to do). I know basically nothing about programming so I was wondering if you could direct me step-by-step on what I have to do to make it work.
Looking forward to your reply, best regards.

To be honest, this isn't very user friendly, because I'm lazy, and also don't know anything about {various compiler/linker/toolchain things} to put together a binary which "just works" for everyone. And I'm not really fit to provide support for various cuda library issues, because compiler/linker errors give me headaches too.

If you want something you can just run without trouble, there's better stuff out there, for example this just came up in my google search (i've not tried it) https://old.reddit.com/r/technicalminecraft/comments/8pmqq7/legerts_l64_fast_seed_cracker_reverse_seed_finding/
or https://github.com/pruby/slime-seed/tree/7d1d076de85336d99c2844161c0430cb1fda898b unless you're dead set on using ocean monuments for whatever reason, I suggest you try those

If you're still here for some reason, basically you have to you have to

  1. have an NVIDIA gpu
  2. install the cuda toolkit
  3. install the gcc/g++ compiler. on Linux. apparently windows has an equivalent thing called mingw, but I don't use windows so I don't know anything about it
  4. edit the flat_chunks variable until it contains the (x,z) chunk coordinates of some ocean monuments
  5. run the compilation command at the top of the file, possibly specifying a different compute architecture depending on your GPU
  6. solve any compiler errors, probably by fiddling around with LIBRARY_PATH until gcc finds CUDA
  7. run the executable

Thank you, but I have Radeon gpu so I guess I'll have to try another method or maybe ask a friend what kind of gpu he has.
I'm really grateful for all the help and support you gave me! I'll let you know if I'll be able to use your code.

@seansibbet
Copy link

I've got the same problem as above. Running the command line produces no errors (in Windows 10), but no executable file appears in the folder I run the script from (I've got the cl.exe in the path, and run the command line from the same folder that the seedsearch.cpp file is in)

missing

@jh34ghu43gu
Copy link

Compiling and running is fine, however the actual result appears to be wrong? Def. doesn't work for 1.17 sadly because of terrain changes (I'm guessing), but even running the given chunks and going back to 1.13.1 (the version I assume this was made for) I cannot find temples at the first 2 given chunks (206,-39 and 235,-83). Candidate seed I was given was 109098491073356249 with the lower 48 bits being 167675086332377.
Should have figured it wasn't going to work for 1.17 oh well, server I'm trying to figure out the seed for has horrendous hostile mob rates so finding slime chunks to use in that other seed cracker is impossible, if anyone finds another landmark-based seed cracker let me know, thanks.

@syule
Copy link
Author

syule commented Aug 15, 2021

Should have figured it wasn't going to work for 1.17

I just tested, and it still works on 1.17.1 -- none of the terrain changes affect ocean monuments, with the exception that before, the tallest part of an ocean monument spawned in the center of a chunk, and now the tallest part is located at the north-west corner of the "center chunk". So, you should go to the highest part of the monument, then move a few blocks south east before reading off the chunk coordinates.

I just generated a world with the seed 2238026489121923591, lower 48 bits are 18949295497735, with the ocean monument coordinates

    const int flat_chunks[] = {
        77, 141,
        -73, -41,
        -77, -82,
        -58, -181,
        -239, -48,
        184, 78,
        169, 16,
    };

and I can confirm that it succeeds at finding the lower 48 bits, but the extension is wrong (I probably just got some math wrong). Depending on your use case, you might not care about the upper 16 bits, since they don't affect other slime chunks or other structure locations. If you do care, you could look at pruby's code for extending the first 16 bits, which is probably more correct.

I should warn that spigot/paper servers have an option for using a different seed for each structure type, in which case the seed derived from monuments might not be useful for searching for slime chunks, for instance. I don't know if this is the default spigot behavior.

@jh34ghu43gu
Copy link

jh34ghu43gu commented Aug 16, 2021

Ah, thanks for the reply I will look into it again later.

Edit: It does work 👍 SE corner of them temple is correct if you have the chunk borders open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment