diff --git a/src/main/java/kaptainwutax/seedcracker/SeedCracker.java b/src/main/java/kaptainwutax/seedcracker/SeedCracker.java index 2feb20a..959fa8f 100644 --- a/src/main/java/kaptainwutax/seedcracker/SeedCracker.java +++ b/src/main/java/kaptainwutax/seedcracker/SeedCracker.java @@ -1,9 +1,10 @@ package kaptainwutax.seedcracker; +import kaptainwutax.seedcracker.cracker.BiomeData; +import kaptainwutax.seedcracker.cracker.PillarData; import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.TimeMachine; 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; @@ -15,19 +16,100 @@ 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"); + public List worldSeeds = null; + public List structureSeeds = null; + public List pillarSeeds = null; + + private TimeMachine timeMachine = new TimeMachine(); + private List structureCache = new ArrayList<>(); + private List biomeCache = new ArrayList<>(); + @Override public void onInitialize() { RenderQueue.get().add("hand", FinderQueue.get()::renderFinders); } + public void reset() { + this.worldSeeds = null; + this.structureSeeds = null; + this.pillarSeeds = null; + this.structureCache.clear(); + this.biomeCache.clear(); + } + + public void onPillarData(PillarData pillarData) { + if(this.pillarSeeds == null) { + this.pillarSeeds = pillarData.getPillarSeeds(); + this.onStructureData(null); + } + } + + public void onStructureData(StructureData structureData) { + if(structureData != null) { + this.structureCache.add(structureData); + } + + if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() >= 3) { + this.structureSeeds = new ArrayList<>(); + + this.pillarSeeds.forEach(pillarSeed -> { + timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.structureSeeds); + }); + + this.structureCache.clear(); + this.onBiomeData(null); + } else if(this.structureSeeds != null && structureData != null) { + this.structureSeeds.removeIf(structureSeed -> { + ChunkRandom chunkRandom = new ChunkRandom(); + chunkRandom.setStructureSeed(structureSeed, structureData.getRegionX(), structureData.getRegionZ(), structureData.getSalt()); + return !structureData.test(chunkRandom); + }); + + this.structureCache.clear(); + this.onBiomeData(null); + } + } + + public void onBiomeData(BiomeData biomeData) { + if(biomeData != null) { + this.biomeCache.add(biomeData); + } + + if(this.worldSeeds == null && this.structureSeeds != null && this.biomeCache.size() >= 3) { + this.worldSeeds = new ArrayList<>(); + + this.structureSeeds.forEach(structureSeed -> { + for(long i = 0; i < (1L << 16); i++) { + long worldSeed = (i << 48) | structureSeed; + boolean goodSeed = true; + + for(BiomeData data: this.biomeCache) { + if(!data.test(worldSeed)) { + goodSeed = false; + break; + } + } + + if(goodSeed) { + this.worldSeeds.add(worldSeed); + } + } + }); + + this.biomeCache.clear(); + } else if(this.worldSeeds != null && biomeData != null) { + this.worldSeeds.removeIf(worldSeed -> !biomeData.test(worldSeed)); + } + } + + + public static void main(String[] args) { //91,94,82,85,88,79,97,76,100,103 SeedCracker cracker = new SeedCracker(); @@ -69,73 +151,7 @@ public class SeedCracker implements ModInitializer { }); } - public List getStructureSeeds(int pillarSeed, List structureDataList) { - List structureSeeds = new ArrayList<>(); - ChunkRandom chunkRandom = new ChunkRandom(); - for(long i = 0; i < (1L << 32); i++) { - long structureSeed = this.timeMachine(i, pillarSeed); - 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 getSpikeSeeds(List heights) { - List result = new ArrayList<>(); - - for(int spikeSeed = 0; spikeSeed < (1 << 16); spikeSeed++) { - List h = this.getSpikeHeights(spikeSeed); - if(h.equals(heights))result.add(spikeSeed); - } - - return result; - } - - public List getSpikeHeights(int spikeSeed) { - List indices = new ArrayList<>(); - - for (int i = 0; i < 10; i++) { - indices.add(i); - } - - Collections.shuffle(indices, new Random(spikeSeed)); - - List heights = new ArrayList<>(); - - for (Integer index: indices) { - heights.add(76 + index * 3); - } - - return heights; - } /* public List getSpikeHeights(long worldSeed) { diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java b/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java new file mode 100644 index 0000000..ed5b238 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java @@ -0,0 +1,45 @@ +package kaptainwutax.seedcracker.cracker; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class PillarData { + + private List heights; + + public PillarData() { + + } + + public List getPillarSeeds() { + List result = new ArrayList<>(); + + for(int pillarSeed = 0; pillarSeed < (1 << 16); pillarSeed++) { + List h = this.getPillarHeights(pillarSeed); + if(h.equals(heights))result.add(pillarSeed); + } + + return result; + } + + public List getPillarHeights(int spikeSeed) { + List indices = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + indices.add(i); + } + + Collections.shuffle(indices, new Random(spikeSeed)); + + List heights = new ArrayList<>(); + + for (Integer index: indices) { + heights.add(76 + index * 3); + } + + return heights; + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/StructureData.java b/src/main/java/kaptainwutax/seedcracker/cracker/StructureData.java index c896748..60ee3fc 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/StructureData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/StructureData.java @@ -73,7 +73,6 @@ public class StructureData { public abstract boolean test(ChunkRandom rand, int x, int z); } - public static final Feature DESERT_PYRAMID = new Feature(14357617, 32) { @Override public boolean test(ChunkRandom rand, int x, int z) { @@ -102,17 +101,17 @@ public class StructureData { } }; - public static final Feature OCEAN_RUIN = new Feature(14357621, 32) { + public static final Feature OCEAN_RUIN = new Feature(14357621, 16) { @Override public boolean test(ChunkRandom rand, int x, int z) { - return rand.nextInt(24) == x && rand.nextInt(24) == z; + return rand.nextInt(8) == x && rand.nextInt(8) == z; } }; - public static final Feature SHIPWRECK = new Feature(165745295, 32) { + public static final Feature SHIPWRECK = new Feature(165745295, 16) { @Override public boolean test(ChunkRandom rand, int x, int z) { - return rand.nextInt(24) == x && rand.nextInt(24) == z; + return rand.nextInt(8) == x && rand.nextInt(8) == z; } }; diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java b/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java new file mode 100644 index 0000000..86ea901 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java @@ -0,0 +1,53 @@ +package kaptainwutax.seedcracker.cracker; + +import kaptainwutax.seedcracker.util.Rand; +import kaptainwutax.seedcracker.util.math.LCG; +import net.minecraft.world.gen.ChunkRandom; + +import java.util.List; + +public class TimeMachine { + + private LCG inverseLCG = Rand.JAVA_LCG.combine(-2); + + public TimeMachine() { + + } + + public List buildStructureSeeds(int pillarSeed, List structureDataList, List structureSeeds) { + ChunkRandom chunkRandom = new ChunkRandom(); + + for(long i = 0; i < (1L << 32); i++) { + long structureSeed = this.timeMachine(i, pillarSeed); + 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; + } + + 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; + } + +}