-
-
Save BrainStone/8f4a453b05189645a4d077d0ace72fcc to your computer and use it in GitHub Desktop.
out/ | |
.idea/ | |
*.iml |
import java.util.ArrayList; | |
import java.util.LinkedHashMap; | |
import java.util.Map; | |
public class Main { | |
public static void printTableForPublic( | |
MinecraftOreOffsetFinder.Disk disk, MinecraftOreOffsetFinder.Ore ore, int maxLines) { | |
int total = 0; | |
for (int i = 0; i < 16; i++) { | |
if (MinecraftOreOffsetFinder.residueOrSeedReliable(disk, ore, i)) { | |
total++; | |
} | |
} | |
System.out.println( | |
disk + " " + ore + " will work reliably on " + (total / 16.0 * 100) + "% of seeds."); | |
LinkedHashMap<ArrayList<Integer>, Double> offsets = | |
MinecraftOreOffsetFinder.getOffsets(disk, ore); | |
int i = 0; | |
for (Map.Entry<ArrayList<Integer>, Double> entry : offsets.entrySet()) { | |
if (++i > maxLines) { | |
break; | |
} | |
System.out.printf( | |
"Z offset %d occurs with probability %.2f%%\n", | |
entry.getKey().get(0), entry.getValue() * 100); | |
} | |
System.out.println(); | |
} | |
private static void printStatsForAllSeeds() { | |
final int MAX_LINES = 5; | |
for (MinecraftOreOffsetFinder.Disk disk : MinecraftOreOffsetFinder.Disk.values()) { | |
for (MinecraftOreOffsetFinder.Ore ore : MinecraftOreOffsetFinder.Ore.values()) { | |
printTableForPublic(disk, ore, MAX_LINES); | |
} | |
} | |
} | |
private static void printStatsForSeed(long seed) { | |
for (MinecraftOreOffsetFinder.Disk disk : MinecraftOreOffsetFinder.Disk.values()) { | |
System.out.println(disk + ":"); | |
for (MinecraftOreOffsetFinder.Ore ore : MinecraftOreOffsetFinder.Ore.values()) { | |
boolean reliable = MinecraftOreOffsetFinder.residueOrSeedReliable(disk, ore, seed); | |
int offset = MinecraftOreOffsetFinder.getOffsetsForSeed(disk, ore, seed).get(0); | |
System.out.printf("%s offset: %d%s reliable\n", ore, offset, reliable ? "" : " NOT"); | |
} | |
System.out.println(); | |
} | |
} | |
public static void main(String[] args) { | |
if (args.length == 0) { | |
printStatsForAllSeeds(); | |
} else { | |
printStatsForSeed(Long.parseLong(args[0])); | |
} | |
} | |
} |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.LinkedHashMap; | |
import java.util.Map; | |
import java.util.Random; | |
import java.util.stream.Collectors; | |
public class MinecraftOreOffsetFinder { | |
// Constant used in java.util.Random to multiply the current seed with and also to XOR the initial | |
// seed | |
private static final long lmult = 0x5deece66dL; | |
private static final long mask = (1L << 48) - 1; | |
private static final int seedsToSearch = 1000000; | |
public static enum Ore { | |
COAL(60005), | |
IRON(60006), | |
GOLD(60007), | |
REDSTONE(60008), | |
DIAMOND(60009), | |
LAPIS(60010); | |
public final int salt; | |
private Ore(int salt) { | |
this.salt = salt; | |
} | |
} | |
public enum Disk { | |
SWAMP_CLAY(60011), | |
RIVER_CLAY(60012), | |
GRAVEL(60013); | |
public final int salt; | |
private Disk(int salt) { | |
this.salt = salt; | |
} | |
} | |
private static int seedToOffset(long seed) { | |
final int precision = 16; | |
final long blockToSeed = (1L << 48) / precision; | |
long s1 = (seed * lmult) & mask; | |
long s2 = (s1 * lmult) & mask; | |
return (int) (s2 / blockToSeed); | |
} | |
private static ArrayList<Long> getOffsetsForSeedRaw(long[] salts, Ore ore, long seed) { | |
long targetSalt = ore.salt; | |
ArrayList<Long> offsets = new ArrayList<>(salts.length); | |
for (long salt : salts) { | |
offsets.add((((seed + targetSalt) ^ lmult) - ((seed + salt) ^ lmult)) & mask); | |
} | |
return offsets; | |
} | |
private static ArrayList<Integer> getOffsetsForSeed(long[] salts, Ore ore, long seed) { | |
return getOffsetsForSeedRaw(salts, ore, seed).stream() | |
.map(MinecraftOreOffsetFinder::seedToOffset) | |
.collect(Collectors.toCollection(ArrayList::new)); | |
} | |
public static ArrayList<Integer> getOffsetsForSeed(Disk disk, Ore ore, long seed) { | |
return getOffsetsForSeed(new long[] {disk.salt}, ore, seed); | |
} | |
private static HashMap<ArrayList<Long>, Integer> getOffsetsRaw(Disk disk, Ore ore) { | |
HashMap<ArrayList<Long>, Integer> offsets = new HashMap<>(); | |
Random r = new Random(); | |
long targetSalt = ore.salt; | |
long[] measuredSalts = {disk.salt}; // intent is eventually to handle multiple decorators | |
long seed; | |
for (int i = 0; i < seedsToSearch; i++) { | |
seed = r.nextLong() & mask; | |
ArrayList<Long> key = getOffsetsForSeedRaw(measuredSalts, ore, seed); | |
if (offsets.containsKey(key)) { | |
int current = offsets.get(key); | |
offsets.replace(key, current + 1); | |
} else { | |
offsets.put(key, 1); | |
} | |
} | |
return offsets; | |
} | |
public static LinkedHashMap<ArrayList<Integer>, Double> getOffsets(Disk disk, Ore ore) { | |
HashMap<ArrayList<Long>, Integer> rawOffsets = getOffsetsRaw(disk, ore); | |
return rawOffsets.entrySet().stream() | |
.sorted(Map.Entry.<ArrayList<Long>, Integer>comparingByValue().reversed()) | |
.collect( | |
Collectors.toMap( | |
entry -> | |
entry.getKey().stream() | |
.map(MinecraftOreOffsetFinder::seedToOffset) | |
.collect(Collectors.toCollection(ArrayList::new)), | |
entry -> entry.getValue() / ((double) seedsToSearch), | |
(u, v) -> u, | |
LinkedHashMap::new)); | |
} | |
public static boolean residueOrSeedReliable(Disk disk, Ore ore, long residueOrSeed) { | |
return ((disk.salt + residueOrSeed) & 0x10) == ((ore.salt + residueOrSeed) & 0x10); | |
} | |
} |
@joogle12 Pass the seed as the first start paramter.
@joogle12 Pass the seed as the first start paramter.
sorry, im new at this. can you show me how?
sorry, im new at this. can you show me how?
@joogle12 Well if you don't know how to run a java program from source, I can't really help you. This isn't some trivial task and does require some background knowledge.
If you do know how to run this program then I kinda also can't help you because how to specify a startup parameter depends heavily on how you run the program. Just know that if you run it through the command line you can specify the parameter as the last parameter. And if you run it through an IDE you can specify the start parameters in the run configuration somewhere.
sorry, im new at this. can you show me how?
@joogle12 Well if you don't know how to run a java program from source, I can't really help you. This isn't some trivial task and does require some background knowledge.
If you do know how to run this program then I kinda also can't help you because how to specify a startup parameter depends heavily on how you run the program. Just know that if you run it through the command line you can specify the parameter as the last parameter. And if you run it through an IDE you can specify the start parameters in the run configuration somewhere.
hey. thanks for the help man. I made a 1.17 version by taking a few tips and updating the salts.
@joogle12 not sure why you didn't just use my gist, to update the salts there. Then you'd still have the dual program.
What needs to be done to update for 1.17?
hey. how can you print the offsets on a certain seed?