structure seed cracking
This commit is contained in:
@@ -1,10 +1,24 @@
|
||||
package kaptainwutax.seedcracker;
|
||||
|
||||
import kaptainwutax.seedcracker.cracker.StructureData;
|
||||
import kaptainwutax.seedcracker.render.RenderQueue;
|
||||
import kaptainwutax.seedcracker.util.Rand;
|
||||
import kaptainwutax.seedcracker.util.math.LCG;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.biome.layer.BiomeLayerSampler;
|
||||
import net.minecraft.world.biome.layer.BiomeLayers;
|
||||
import net.minecraft.world.biome.source.BiomeSourceType;
|
||||
import net.minecraft.world.gen.ChunkRandom;
|
||||
import net.minecraft.world.level.LevelGeneratorType;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class SeedCracker implements ModInitializer {
|
||||
|
||||
public static final Logger LOG = LogManager.getLogger("Seed Cracker");
|
||||
@@ -14,4 +28,207 @@ public class SeedCracker implements ModInitializer {
|
||||
RenderQueue.get().add("hand", FinderQueue.get()::renderFinders);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
//91,94,82,85,88,79,97,76,100,103
|
||||
SeedCracker cracker = new SeedCracker();
|
||||
List<Integer> heights = new ArrayList<>();
|
||||
heights.add(91);
|
||||
heights.add(94);
|
||||
heights.add(82);
|
||||
heights.add(85);
|
||||
heights.add(88);
|
||||
heights.add(79);
|
||||
heights.add(97);
|
||||
heights.add(76);
|
||||
heights.add(100);
|
||||
heights.add(103);
|
||||
|
||||
List<StructureData> structureDataList = new ArrayList<>();
|
||||
structureDataList.add(new StructureData(new ChunkPos(-37, -95), StructureData.END_CITY));
|
||||
structureDataList.add(new StructureData(new ChunkPos(-57,-116), StructureData.END_CITY));
|
||||
structureDataList.add(new StructureData(new ChunkPos(-18, 204), StructureData.OCEAN_MONUMENT));
|
||||
structureDataList.add(new StructureData(new ChunkPos(-44, 109), StructureData.OCEAN_MONUMENT));
|
||||
structureDataList.add(new StructureData(new ChunkPos(14, -158), StructureData.DESERT_PYRAMID));
|
||||
|
||||
cracker.getSpikeSeeds(heights).forEach(seed -> {
|
||||
System.out.println("Found pillar seed: [" + seed + "].");
|
||||
|
||||
structureDataList.forEach(s -> {
|
||||
System.out.println("Structure data: [" + s.getSalt() + ", " + s.getOffsetX() + ", " + s.getOffsetZ() + "].");
|
||||
});
|
||||
|
||||
cracker.getStructureSeeds(seed, structureDataList).forEach(seed1 -> {
|
||||
System.out.println("Found structure seed: [" + seed1 + "].");
|
||||
|
||||
for(long i = 0; i < (1L << 16); i++) {
|
||||
long worldSeed = (i << 48) | seed1;
|
||||
BiomeLayerSampler[] biomeLayerSamplers = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT, BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings());
|
||||
System.out.println(worldSeed + ", " + biomeLayerSamplers[0].sample(0, 0));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public List<Long> getStructureSeeds(int pillarSeed, List<StructureData> structureDataList) {
|
||||
List<Long> structureSeeds = new ArrayList<>();
|
||||
ChunkRandom chunkRandom = new ChunkRandom();
|
||||
|
||||
for(long i = 0; i < (1L << 32); i++) {
|
||||
long structureSeed = this.timeMachine(i, pillarSeed);
|
||||
//if(structureSeed != 229625539606330L)continue;
|
||||
boolean goodSeed = true;
|
||||
|
||||
for(StructureData structureData: structureDataList) {
|
||||
chunkRandom.setStructureSeed(structureSeed, structureData.getRegionX(),
|
||||
structureData.getRegionZ(), structureData.getSalt());
|
||||
|
||||
if(!structureData.test(chunkRandom)) {
|
||||
goodSeed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(goodSeed) {
|
||||
structureSeeds.add(structureSeed);
|
||||
}
|
||||
}
|
||||
return structureSeeds;
|
||||
}
|
||||
|
||||
private LCG inverseLCG = Rand.JAVA_LCG.combine(-2);
|
||||
|
||||
public long timeMachine(long partialWorldSeed, int pillarSeed) {
|
||||
long currentSeed = 0L;
|
||||
currentSeed |= (partialWorldSeed & 0xFFFF0000L) << 16;
|
||||
currentSeed |= (long)pillarSeed << 16;
|
||||
currentSeed |= partialWorldSeed & 0xFFFFL;
|
||||
|
||||
currentSeed = inverseLCG.nextSeed(currentSeed);
|
||||
currentSeed ^= Rand.JAVA_LCG.multiplier;
|
||||
return currentSeed;
|
||||
}
|
||||
|
||||
|
||||
public List<Integer> getSpikeSeeds(List<Integer> heights) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
||||
for(int spikeSeed = 0; spikeSeed < (1 << 16); spikeSeed++) {
|
||||
List<Integer> h = this.getSpikeHeights(spikeSeed);
|
||||
if(h.equals(heights))result.add(spikeSeed);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Integer> getSpikeHeights(int spikeSeed) {
|
||||
List<Integer> indices = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
indices.add(i);
|
||||
}
|
||||
|
||||
Collections.shuffle(indices, new Random(spikeSeed));
|
||||
|
||||
List<Integer> heights = new ArrayList<>();
|
||||
|
||||
for (Integer index: indices) {
|
||||
heights.add(76 + index * 3);
|
||||
}
|
||||
|
||||
return heights;
|
||||
}
|
||||
|
||||
/*
|
||||
public List<Integer> getSpikeHeights(long worldSeed) {
|
||||
Random rand = new Random(worldSeed);
|
||||
long pillarSeed = rand.nextLong() & 65535L;
|
||||
|
||||
List<Integer> indices = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
indices.add(i);
|
||||
}
|
||||
|
||||
Collections.shuffle(indices, new Random(pillarSeed));
|
||||
|
||||
List<Integer> heights = new ArrayList<>();
|
||||
|
||||
for (Integer index: indices) {
|
||||
heights.add(76 + index * 3);
|
||||
}
|
||||
|
||||
return heights;
|
||||
}
|
||||
|
||||
|
||||
protected ChunkPos getStart(ChunkGenerator<?> chunkGenerator_1, Random rand, int chunkX, int chunkZ) {
|
||||
int templeDistance = 32;
|
||||
int templeSeparation = 8;
|
||||
|
||||
chunkX = chunkX < 0 ? chunkX - templeDistance + 1 : chunkX;
|
||||
chunkZ = chunkZ < 0 ? chunkZ - templeDistance + 1 : chunkZ;
|
||||
|
||||
//Pick out in which region the chunk is.
|
||||
int regionX = chunkX / templeDistance;
|
||||
int regionZ = chunkZ / templeDistance;
|
||||
|
||||
((ChunkRandom)rand).setStructureSeed(chunkGenerator_1.getSeed(), regionX, regionZ, this.getSeedModifier());
|
||||
|
||||
//Convert it back to a chunk pos.
|
||||
regionX *= templeDistance;
|
||||
regionZ *= templeDistance;
|
||||
|
||||
//Add a random chunk offset.
|
||||
regionX += rand.nextInt(templeDistance - templeSeparation);
|
||||
regionZ += rand.nextInt(templeDistance - templeSeparation);
|
||||
|
||||
return new ChunkPos(regionX, regionZ);
|
||||
}
|
||||
|
||||
public void getTempleCalls(ChunkPos chunkPos) {
|
||||
int templeDistance = 32;
|
||||
|
||||
int chunkX = chunkPos.x;
|
||||
int chunkZ = chunkPos.z;
|
||||
|
||||
chunkX = chunkX < 0 ? chunkX - templeDistance + 1 : chunkX;
|
||||
chunkZ = chunkZ < 0 ? chunkZ - templeDistance + 1 : chunkZ;
|
||||
|
||||
//Pick out in which region the chunk is.
|
||||
int regionX = (chunkX / templeDistance) * templeDistance;
|
||||
int regionZ = (chunkZ / templeDistance) * templeDistance;
|
||||
|
||||
int offsetX = chunkPos.x - regionX;
|
||||
int offsetZ = chunkPos.z - regionZ;
|
||||
}
|
||||
|
||||
public boolean shouldStartAt(ChunkGenerator<?> chunkGen, Random random_1, int chunkX, int chunkZ) {
|
||||
ChunkPos startPosition = this.getStart(chunkGen, random_1, chunkX, chunkZ);
|
||||
|
||||
if(chunkX == startPosition.x && chunkZ == startPosition.z) {
|
||||
Biome biome = chunkGen.getBiomeSource().getBiome(new BlockPos(chunkX * 16 + 9, 0, chunkZ * 16 + 9));
|
||||
|
||||
if(chunkGen.hasStructure(biome, this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public long setStructureSeed(long worldSeed, int regionX, int regionZ, int salt) {
|
||||
long seed = (long)regionX * 341873128712L + (long)regionZ * 132897987541L + worldSeed + (long)salt;
|
||||
seed = (seed ^ Rand.JAVA_LCG.multiplier) & (Rand.JAVA_LCG.modulo - 1);
|
||||
return seed;
|
||||
}
|
||||
|
||||
public void getStart(long worldSeed, int regionX, int regionZ, int salt) {
|
||||
long seed = this.setStructureSeed(worldSeed, regionX, regionZ, salt);
|
||||
int nextIntSeed = (int)(Rand.JAVA_LCG.nextSeed(seed) >>> (48 - 31));
|
||||
int chunkX = nextIntSeed % 24;
|
||||
nextIntSeed = (int)(Rand.JAVA_LCG.nextSeed(Rand.JAVA_LCG.nextSeed(seed)) >>> (48 - 31));
|
||||
int chunkZ = nextIntSeed % 24;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package kaptainwutax.seedcracker.cracker;
|
||||
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.gen.ChunkRandom;
|
||||
|
||||
public class StructureData {
|
||||
|
||||
private int regionX;
|
||||
private int regionZ;
|
||||
private int offsetX;
|
||||
private int offsetZ;
|
||||
private Feature feature;
|
||||
|
||||
public StructureData(ChunkPos chunkPos, Feature feature) {
|
||||
this.feature = feature;
|
||||
this.feature.buildCalls(this, chunkPos);
|
||||
}
|
||||
|
||||
public int getRegionX() {
|
||||
return this.regionX;
|
||||
}
|
||||
|
||||
public int getRegionZ() {
|
||||
return this.regionZ;
|
||||
}
|
||||
|
||||
public int getOffsetX() {
|
||||
return this.offsetX;
|
||||
}
|
||||
|
||||
public int getOffsetZ() {
|
||||
return this.offsetZ;
|
||||
}
|
||||
|
||||
public int getSalt() {
|
||||
return this.feature.salt;
|
||||
}
|
||||
|
||||
public boolean test(ChunkRandom rand) {
|
||||
return this.feature.test(rand, this.offsetX, this.offsetZ);
|
||||
}
|
||||
|
||||
public abstract static class Feature {
|
||||
public final int salt;
|
||||
public final int templeDistance;
|
||||
|
||||
public Feature(int salt, int templeDistance) {
|
||||
this.salt = salt;
|
||||
this.templeDistance = templeDistance;
|
||||
}
|
||||
|
||||
public void buildCalls(StructureData data, ChunkPos chunkPos) {
|
||||
int chunkX = chunkPos.x;
|
||||
int chunkZ = chunkPos.z;
|
||||
|
||||
chunkX = chunkX < 0 ? chunkX - this.templeDistance + 1 : chunkX;
|
||||
chunkZ = chunkZ < 0 ? chunkZ - this.templeDistance + 1 : chunkZ;
|
||||
|
||||
//Pick out in which region the chunk is.
|
||||
int regionX = (chunkX / this.templeDistance);
|
||||
int regionZ = (chunkZ / this.templeDistance);
|
||||
|
||||
data.regionX = regionX;
|
||||
data.regionZ = regionZ;
|
||||
|
||||
regionX *= this.templeDistance;
|
||||
regionZ *= this.templeDistance;
|
||||
|
||||
data.offsetX = chunkPos.x - regionX;
|
||||
data.offsetZ = chunkPos.z - regionZ;
|
||||
}
|
||||
|
||||
public abstract boolean test(ChunkRandom rand, int x, int z);
|
||||
}
|
||||
|
||||
|
||||
public static final Feature SWAMP_HUT = new Feature(14357620, 32) {
|
||||
@Override
|
||||
public boolean test(ChunkRandom rand, int x, int z) {
|
||||
return rand.nextInt(24) == x && rand.nextInt(24) == z;
|
||||
}
|
||||
};
|
||||
|
||||
public static final Feature DESERT_PYRAMID = new Feature(14357617, 32) {
|
||||
@Override
|
||||
public boolean test(ChunkRandom rand, int x, int z) {
|
||||
return rand.nextInt(24) == x && rand.nextInt(24) == z;
|
||||
}
|
||||
};
|
||||
|
||||
public static final Feature JUNGLE_TEMPLE = new Feature(14357619, 32) {
|
||||
@Override
|
||||
public boolean test(ChunkRandom rand, int x, int z) {
|
||||
return rand.nextInt(24) == x && rand.nextInt(24) == z;
|
||||
}
|
||||
};
|
||||
|
||||
public static final Feature END_CITY = new Feature(10387313, 20) {
|
||||
@Override
|
||||
public boolean test(ChunkRandom rand, int x, int z) {
|
||||
return (rand.nextInt(9) + rand.nextInt(9)) / 2 == x
|
||||
&& (rand.nextInt(9) + rand.nextInt(9)) / 2 == z;
|
||||
}
|
||||
};
|
||||
|
||||
public static final Feature OCEAN_MONUMENT = new Feature(10387313, 32) {
|
||||
@Override
|
||||
public boolean test(ChunkRandom rand, int x, int z) {
|
||||
return (rand.nextInt(27) + rand.nextInt(27)) / 2 == x
|
||||
&& (rand.nextInt(27) + rand.nextInt(27)) / 2 == z;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user