-
-
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; | |
} |
// 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
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?
I've tried to run but had no output
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: '<'
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.
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.
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?
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.
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.
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.
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
- have an NVIDIA gpu
- install the cuda toolkit
- 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
- edit the
flat_chunks
variable until it contains the(x,z)
chunk coordinates of some ocean monuments - run the compilation command at the top of the file, possibly specifying a different compute architecture depending on your GPU
- solve any compiler errors, probably by fiddling around with
LIBRARY_PATH
until gcc finds CUDA - run the executable
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 thoseIf you're still here for some reason, basically you have to you have to
- have an NVIDIA gpu
- install the cuda toolkit
- 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
- edit the
flat_chunks
variable until it contains the(x,z)
chunk coordinates of some ocean monuments- run the compilation command at the top of the file, possibly specifying a different compute architecture depending on your GPU
- solve any compiler errors, probably by fiddling around with
LIBRARY_PATH
until gcc finds CUDA- 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.
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.
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.
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.
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.