Last active
January 4, 2019 00:17
-
-
Save EDDxample/bdaa429949fd2cccbc3c2bfb0a8470f9 to your computer and use it in GitHub Desktop.
Simulates Minecraft's dungeon generation to find dungeons that are close enough to get multiple chests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.reflect.Field; | |
import java.util.ArrayList; | |
import java.util.Random; | |
import java.util.concurrent.atomic.AtomicLong; | |
public final class TripleChestFinder | |
{ | |
static long seed; | |
static boolean stop, shouldStop; | |
static Random rng = new Random(); | |
public static void main(String[] args) | |
{ | |
seed = 8234323457654343121L; | |
int x = 0, z = 0, width = 2, depth = 1; | |
checkAround(x,z); | |
while (!stop) | |
{ | |
for (int i = 1; i <= width; i++) checkAround(x + i, z); | |
x += width; | |
for (int i = 1; i <= depth; i++) checkAround(x, z + i); | |
z += depth; | |
width++; | |
depth++; | |
for (int i = 1; i <= width; i++) checkAround(x - i, z); | |
x -= width; | |
for (int i = 1; i <= depth; i++) checkAround(x, z - i); | |
z -= depth; | |
width++; | |
depth++; | |
} | |
} | |
public static void checkAround(final int cx, final int cz) | |
{ | |
ArrayList<Integer> base = genPosList(cx, cz); | |
for (int i = -1; i < 2; i++) | |
{ | |
for (int j = -1; j < 2; j++) | |
{ | |
if (i == 0 && j == 0) continue; | |
compareLists(base, genPosList(cx + i, cz + j)); | |
if (stop) return; | |
} | |
} | |
} | |
public static void compareLists(final ArrayList<Integer> base, final ArrayList<Integer> list) | |
{ | |
for (int i = 0; i < base.size() / 5; i++) | |
{ | |
for (int j = 0; j < list.size() / 5; j++) | |
{ | |
/* Check for Y's */ | |
final int y1 = base.get(i * 5 + 1), | |
y2 = list.get(j * 5 + 1); | |
if (y1 == y2) | |
{ | |
final int x1 = base.get(i * 5), | |
x2 = list.get(j * 5), | |
radX1 = base.get(i * 5 + 3) + 1, | |
radX2 = list.get(j * 5 + 3) + 1; | |
/* Check if it's in range */ | |
if (Math.abs(x2 - x1) < radX1 + radX2) | |
{ | |
final int z1 = base.get(i * 5 + 2), | |
z2 = list.get(j * 5 + 2), | |
radZ1 = base.get(i * 5 + 4) + 1, | |
radZ2 = list.get(j * 5 + 4) + 1; | |
if (Math.abs(z2 - z1) < radX1 + radX2) | |
{ | |
/* Check if it doesn't need to generate a previous spawner */ | |
if ((i / 8 - 1) == -1 && (j / 8 - 1) == -1) | |
{ | |
final int minX = x1 < x2 ? x2 - radX2 : x1 - radX1, | |
minZ = z1 < z2 ? z2 - radZ2 : z1 - radZ1, | |
maxX = x1 < x2 ? x1 + radX1 : x2 + radX2, | |
maxZ = z1 < z2 ? z1 + radZ1 : z2 + radZ2; | |
//checkChests((x1 - 8) >> 4, (z1 - 8) >> 4, (i / 8 - 1), i % 8, minX, minZ, maxX, maxZ); | |
//checkChests((x2 - 8) >> 4, (z2 - 8) >> 4, (j / 8 - 1), j % 8, minX, minZ, maxX, maxZ); | |
// Get shared area = if (x1 < x2) maxX = x1 + radX1; and so | |
System.out.println("Mossy = " + (i / 8 - 1) + ", pos = (" + x1 + ", " + y1 + ", " + z1 + ")"); | |
System.out.println("Mossy = " + (j / 8 - 1) + ", pos = (" + x2 + ", " + y2 + ", " + z2 + ")\n--"); | |
return; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
public static void checkChests(final int cx, final int cz, final int mossy, final int iter, final int minX, final int minZ, final int maxX, final int maxZ) | |
{ | |
/* Set the seed */ | |
setAndSkip(cx, cz); | |
int x = 0, y = 0, z = 0, radX = 0, radZ = 0; | |
for (int i = 0; i < iter; i++) | |
{ | |
/* Basic random calls for any attempt */ | |
x = rng.nextInt(16) + 8 + (cx << 4); | |
y = rng.nextInt(256); | |
z = rng.nextInt(16) + 8 + (cz << 4); | |
radX = rng.nextInt(2) + 2; | |
radZ = rng.nextInt(2) + 2; | |
/* check if should generate the 1st spawner */ | |
if (i == 0) | |
{ | |
for (int m = 0; i < mossy; m++) rng.nextInt(); | |
if (mossy >= 0) | |
{ | |
for (int chestAttempt = 0; chestAttempt < 6; chestAttempt++) | |
{ | |
rng.nextInt(radX * 2 + 1); | |
rng.nextInt(radZ * 2 + 1); | |
} | |
} | |
} | |
} | |
final long resetSeed = getActualSeed(); | |
/* Check chest with and without generating mossy */ | |
for (int i = 0; i <= (radX + 1)*(radZ + 1); i++) | |
{ | |
rng.setSeed(resetSeed); | |
for (int m = 0; i < i; m++) rng.nextInt(); | |
final long resetSeed2 = getActualSeed(); | |
/* Generate Chests */ | |
for (int j = 0; j < 3; j++) | |
{ | |
rng.setSeed(resetSeed2); | |
int chestX = 0, chestZ = 0; | |
for (int chestIter = -1 ; chestIter < j; chestIter++) | |
{ | |
chestX = x + rng.nextInt(radX * 2 + 1) - radX; | |
chestZ = z + rng.nextInt(radZ * 2 + 1) - radZ; | |
} | |
/* if the chest is located in the mid area */ | |
if (minX <= chestX && chestX <= maxX && minZ <= chestZ && chestZ <= maxZ) | |
{ | |
rng.nextLong(); | |
final long resetSeed3 = getActualSeed(); | |
for (int k = 0; k < 3; k++) | |
{ | |
rng.setSeed(resetSeed2); | |
int chestX2 = 0, chestZ2 = 0; | |
for (int chestIter = -1; chestIter < k; chestIter++) | |
{ | |
chestX2 = x + rng.nextInt(radX * 2 + 1) - radX; | |
chestZ2 = z + rng.nextInt(radZ * 2 + 1) - radZ; | |
} | |
/* If it generates a double chest */ | |
if (((chestX - 1 == chestX2 || chestX + 1 == chestX2) && chestZ == chestZ2) || ((chestZ - 1 == chestZ2 || chestZ + 1 == chestZ2) && chestX == chestX2)) | |
{ | |
System.out.println("DoubleChest found using " + i + " mossyCobble at ("+ chestX + ", " + chestZ + ") and (" + chestX2 + "," + chestZ2 + ")"); | |
shouldStop = true; | |
return; | |
} | |
} | |
} | |
} | |
} | |
shouldStop = false; | |
} | |
public static ArrayList<Integer> genPosList(final int cx, final int cz) | |
{ | |
/* Set the seed */ | |
setAndSkip(cx, cz); | |
/* Basic random calls for any attempt */ | |
final int x = rng.nextInt(16) + 8 + (cx << 4), | |
y = rng.nextInt(256), | |
z = rng.nextInt(16) + 8 + (cz << 4); | |
final int radX = rng.nextInt(2) + 2, | |
radZ = rng.nextInt(2) + 2; | |
ArrayList<Integer> spawnerPositions = new ArrayList<Integer>(8*(radX + 1)*(radZ + 1) + 8); | |
final long resetSeed = getActualSeed(); | |
for (int genMossy = -1; genMossy <= (radX + 1)*(radZ + 1); genMossy++) | |
{ | |
rng.setSeed(resetSeed); | |
//x, y, z, radX, radZ... 8 items = mossy++ | |
spawnerPositions.add(x); | |
spawnerPositions.add(y); | |
spawnerPositions.add(z); | |
spawnerPositions.add(radX); | |
spawnerPositions.add(radZ); | |
/* genMossy = -1: don't generate the 1st spawner at all */ | |
if (genMossy > 0) for (int mossyGenerated = 0; mossyGenerated < genMossy; mossyGenerated++) rng.nextInt(); | |
if (genMossy >= 0) | |
{ | |
for (int chestAttempt = 0; chestAttempt < 6; chestAttempt++) | |
{ | |
rng.nextInt(radX * 2 + 1); | |
rng.nextInt(radZ * 2 + 1); | |
} | |
} | |
/* Rest of the dungeons */ | |
for (int i = 1; i < 8; i++) | |
{ | |
final int _x = rng.nextInt(16) + 8 + (cx << 4), | |
_y = rng.nextInt(256), | |
_z = rng.nextInt(16) + 8 + (cz << 4); | |
final int _radX = rng.nextInt(2) + 2, | |
_radZ = rng.nextInt(2) + 2; | |
spawnerPositions.add(_x); | |
spawnerPositions.add(_y); | |
spawnerPositions.add(_z); | |
spawnerPositions.add(_radX); | |
spawnerPositions.add(_radZ); | |
} | |
} | |
return spawnerPositions; | |
} | |
public static void setAndSkip(final int cx, final int cz) | |
{ | |
rng.setSeed(seed); | |
final long i = rng.nextLong() / 2L * 2L + 1L, | |
j = rng.nextLong() / 2L * 2L + 1L; | |
rng.setSeed((long)cx * i + (long)cz * j ^ seed); | |
/* Water Lakes*/ | |
if (rng.nextInt(4) == 0) | |
{ | |
rng.nextInt(); | |
rng.nextInt(); | |
rng.nextInt(); | |
for (int k = 0; k < (rng.nextInt(4) + 4) * 6; k++) rng.nextDouble(); | |
} | |
/* Lava Lakes */ | |
if (rng.nextInt(8) == 0) | |
{ | |
rng.nextInt(); | |
int k = rng.nextInt(rng.nextInt(248) + 8); | |
rng.nextInt(); | |
if ((k < 63) || (rng.nextInt(10) == 0)) | |
{ | |
k = rng.nextInt(4) + 4; | |
for (int i1 = 0; i1 < k * 6; i1++) rng.nextDouble(); | |
} | |
} | |
} | |
public static long getActualSeed() | |
{ | |
long theSeed; | |
try | |
{ | |
Field field = Random.class.getDeclaredField("seed"); | |
field.setAccessible(true); | |
AtomicLong scrambledSeed = (AtomicLong) field.get(rng); //this needs to be XOR'd with 0x5DEECE66DL | |
theSeed = scrambledSeed.get(); | |
return theSeed ^ 0x5DEECE66DL; | |
} | |
catch (Exception e) | |
{ | |
//handle exception | |
} | |
System.out.println("Failed to get RNG's seed"); | |
return 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment