Skip to content

Instantly share code, notes, and snippets.

@EDDxample
Last active January 4, 2019 00:17
Show Gist options
  • Save EDDxample/bdaa429949fd2cccbc3c2bfb0a8470f9 to your computer and use it in GitHub Desktop.
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
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