diff --git a/src/main/java/kaptainwutax/seedcracker/SeedCracker.java b/src/main/java/kaptainwutax/seedcracker/SeedCracker.java index 1f93945..220f6c3 100644 --- a/src/main/java/kaptainwutax/seedcracker/SeedCracker.java +++ b/src/main/java/kaptainwutax/seedcracker/SeedCracker.java @@ -1,199 +1,213 @@ package kaptainwutax.seedcracker; -import io.netty.util.internal.ConcurrentSet; -import kaptainwutax.seedcracker.cracker.*; -import kaptainwutax.seedcracker.cracker.population.DecoratorData; -import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; import kaptainwutax.seedcracker.finder.FinderQueue; import kaptainwutax.seedcracker.render.RenderQueue; -import kaptainwutax.seedcracker.util.Log; -import kaptainwutax.seedcracker.util.Rand; import net.fabricmc.api.ModInitializer; -import net.minecraft.world.level.LevelProperties; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; public class SeedCracker implements ModInitializer { private static final SeedCracker INSTANCE = new SeedCracker(); - - public long hashedWorldSeed = -1; - - public List worldSeeds = null; - public Set structureSeeds = null; - public List pillarSeeds = null; - - private TimeMachine timeMachine = new TimeMachine(); - private List structureCache = new ArrayList<>(); - private List decoratorCache = new ArrayList<>(); - private List biomeCache = new ArrayList<>(); + private DataStorage dataStorage = new DataStorage(); @Override public void onInitialize() { RenderQueue.get().add("hand", FinderQueue.get()::renderFinders); - DecoratorCache.get().initialize(); + + /* + long ss = 5718603440394L; + LCG lcg = Rand.JAVA_LCG.combine(-5); + + for(int i = 0; i < 8; i++) { + System.out.println("n"); + PopulationReversal.getWorldSeeds(ss, 31 * 16, 19 * 16).forEach(seed -> { + System.out.println("Structure seed: " + seed); + + for(int u = 0; u < 1 << 16; u++) { + long worldSeed = ((long)u << 48) | seed; + + if(RandomSeed.isRandomSeed(worldSeed)) { + System.out.println("nextLong() equivalent: " + worldSeed); + } + } + }); + + ss = lcg.nextSeed(ss); + }*/ + + /* + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(new File("all_mineral.txt"))); + + StructureData t = new StructureData(new ChunkPos(0, 0), StructureFeatures.BURIED_TREASURE); + StructureData s = new StructureData(new ChunkPos(0, 0), StructureFeatures.SHIPWRECK); + StructureData v = new StructureData(new ChunkPos(1, 1), StructureFeatures.VILLAGE); + + BiomeData b1 = new BiomeData(new BlockPos(9, 0, 9), biome -> biome.hasStructureFeature(Feature.BURIED_TREASURE)); + BiomeData b2 = new BiomeData(new BlockPos(9, 0, 9), biome -> biome.hasStructureFeature(Feature.SHIPWRECK)); + BiomeData b3 = new BiomeData(new BlockPos(9 + 16, 0, 9 + 16), biome -> biome.hasStructureFeature(Feature.VILLAGE)); + + SpawnPointData spawn = new SpawnPointData(BlockPos.ORIGIN, 50); + + ChestLootData loot = new ChestLootData( + MCLootTables.BURIED_TREASURE_CHEST, + new ChestLootData.Stack(Items.EMERALD, Predicates.MORE_OR_EQUAL_TO, 3), + new ChestLootData.Stack(Items.IRON_INGOT, Predicates.MORE_OR_EQUAL_TO, 4), + new ChestLootData.Stack(Items.GOLD_INGOT, Predicates.MORE_OR_EQUAL_TO, 3), + new ChestLootData.Stack(Items.TNT, Predicates.MORE_OR_EQUAL_TO, 1), + new ChestLootData.Stack(Items.DIAMOND, Predicates.MORE_OR_EQUAL_TO, 1) + ); + + int count = 0; + Rand rand = new Rand(0L, false); + + for(long seed = (1L << 48) - 1; seed >= 0; seed--) { + if(!t.test(seed, rand))continue; + if(!s.test(seed, rand))continue; + if(!v.test(seed, rand))continue; + + if(!loot.test(seed + 20002L, rand))continue; + + for(long u = 0L; u < 1L << 16; u++) { + long worldSeed = (u << 48) | seed; + FakeBiomeSource source = new FakeBiomeSource(worldSeed); + if(!b1.test(source))continue; + if(!b2.test(source))continue; + if(!b3.test(source))continue; + if(!spawn.test(source))continue; + String s2 = "[" + (++count) + "] " + worldSeed + " with structure seed " + seed + "\n"; + System.out.print(s2); + writer.write(s2); + writer.flush(); + break; + } + } + } catch(Exception e) { + e.printStackTrace(); + }*/ + + /* + long seed = 1_000_000_000_000_000L; + int distance = 80; + + Predicate[] trees = new Predicate[] { + biome -> biome instanceof ForestBiome || biome instanceof WoodedHillsBiome, //OAK TREE + biome -> biome instanceof SavannaBiome || biome instanceof SavannaPlateauBiome, //ACACIA TREE + biome -> biome instanceof DarkForestHillsBiome || biome instanceof DarkForestBiome, //DARK OAK TREE + biome -> biome instanceof SnowyTaigaBiome || biome instanceof TaigaBiome, //SPRUCE TREE + biome -> biome instanceof JungleBiome || biome instanceof JungleHillsBiome || biome instanceof ModifiedJungleBiome, //JUNGLE TREE + }; + + Set ids = new HashSet<>(); + + do { + FakeBiomeSource source = new FakeBiomeSource(seed); + BlockPos spawn = SpawnPointData.getSpawnPoint(source); + int x = spawn.getX(); + int z = spawn.getZ(); + + //X direction + for(int s = -1; s != 1; s = 1) { + for(int d = 0; d < distance; d++) { + Biome biome = BiomeData.sampleBiome(source, x + s * d, 0, z); + + for(int j = 0; j < trees.length; j++) { + if(!ids.contains(j) && trees[j].test(biome)) { + ids.add(j); + } + } + } + + if(ids.size() >= trees.length - 1) { + System.out.println(seed + ", " + ids); + ids.clear(); + break; + } + + ids.clear(); + + //Z direction + for(int d = 0; d < distance; d++) { + Biome biome = BiomeData.sampleBiome(source, x, 0, z + s * d); + + for(int j = 0; j < trees.length; j++) { + if(!ids.contains(j) && trees[j].test(biome)) { + ids.add(j); + } + } + } + + if(ids.size() >= trees.length - 1) { + System.out.println(seed + ", " + ids); + ids.clear(); + break; + } + + ids.clear(); + } + + seed++; + } while(seed != 0L);*/ + + /* + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(new File("season_7_seeds_negative.txt"))); + int count = 0; + + long seed = 0L; + BiomeData m1 = new BiomeData(new BlockPos(-200, 0, 0), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome); + BiomeData m2 = new BiomeData(new BlockPos(200, 0, 0), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome); + BiomeData m3 = new BiomeData(new BlockPos(0, 0, -200), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome); + BiomeData m4 = new BiomeData(new BlockPos(0, 0, 200), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome); + + do { + FakeBiomeSource source = new FakeBiomeSource(seed); + + if(m1.test(source) && m2.test(source) && m3.test(source) && m4.test(source)) { + String s = "[" + (++count) + "] " + seed + "\n"; + System.out.println(s); + writer.write(s); + writer.flush(); + } + + seed--; + } while(seed != 0L); + + writer.close(); + } catch(Exception e) { + ; + }*/ + + /* + long popSeed = 107038380818082L; + + for(int x = 0; x < 10000; x++) { + StructureData b = new StructureData(new ChunkPos(x, 0), StructureFeatures.BURIED_TREASURE); + BiomeData b1 = new BiomeData(new BlockPos(16 * x + 9, 0, 9), Biomes.BEACH); + + List worldSeeds = Magic.getSeedFromChunkseed(popSeed, x * 16, 0); + + int finalX = x; + worldSeeds.forEach(structureSeed -> { + if(b.test(structureSeed, new Rand(0L))) { + System.out.println("structure seed " + structureSeed + " at x " + (finalX * 16)); + for(long u = 0L; u < 1L << 16; u++) { + long worldSeed = (u << 48) | structureSeed; + FakeBiomeSource source = new FakeBiomeSource(worldSeed); + if(!b1.test(source))continue; + System.out.println(worldSeed + " with structure seed " + structureSeed + " at x " + (finalX * 16)); + } + } + }); + }*/ } public static SeedCracker get() { return INSTANCE; } - public void clear() { - this.hashedWorldSeed = -1; - this.worldSeeds = null; - this.structureSeeds = null; - this.pillarSeeds = null; - this.structureCache.clear(); - this.biomeCache.clear(); - this.decoratorCache.clear(); - } - - public synchronized boolean onPillarData(PillarData pillarData) { - if(pillarData != null && (this.pillarSeeds == null || this.pillarSeeds.isEmpty())) { - Log.warn("Looking for pillar seeds..."); - - this.pillarSeeds = pillarData.getPillarSeeds(); - - if(this.pillarSeeds.size() > 0) { - Log.warn("Finished search with " + this.pillarSeeds + (this.pillarSeeds.size() == 1 ? " seed." : " seeds.")); - } else { - Log.error("Finished search with no seeds."); - } - - this.onStructureData(null); - return true; - } - - return false; - } - - public synchronized boolean onStructureData(StructureData structureData) { - boolean added = false; - - if(structureData != null && !this.structureCache.contains(structureData)) { - this.structureCache.add(structureData); - added = true; - } - - if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() + this.decoratorCache.size() >= 5) { - this.structureSeeds = new ConcurrentSet<>(); - Log.warn("Looking for structure seeds with " + this.structureCache.size() + " structure features."); - Log.warn("Looking for structure seeds with " + this.decoratorCache.size() + " decorator features."); - - this.pillarSeeds.forEach(pillarSeed -> { - timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.decoratorCache, this.structureSeeds); - }); - - if(this.structureSeeds.size() > 0) { - Log.warn("Finished search with " + this.structureSeeds + (this.structureSeeds.size() == 1 ? " seed." : " seeds.")); - } else { - Log.error("Finished search with no seeds."); - } - - this.structureCache.clear(); - this.onDecoratorData(null); - this.onBiomeData(null); - } else if(this.structureSeeds != null && structureData != null) { - this.structureSeeds.removeIf(structureSeed -> { - Rand rand = new Rand(0L); - return !structureData.test(structureSeed, rand); - }); - - this.onBiomeData(null); - } - - return added; - } - - public synchronized boolean onDecoratorData(DecoratorData decoratorData) { - boolean added = false; - - if(decoratorData != null && !this.decoratorCache.contains(decoratorData)) { - this.decoratorCache.add(decoratorData); - added = true; - } - - this.onStructureData(null); - return added; - } - - public synchronized boolean onBiomeData(BiomeData biomeData) { - boolean added = false; - - if(biomeData != null && !this.biomeCache.contains(biomeData)) { - this.biomeCache.add(biomeData); - added = true; - } - - if(this.worldSeeds == null && this.structureSeeds != null && this.biomeCache.size() >= 5) { - this.worldSeeds = new ArrayList<>(); - - if(this.hashedWorldSeed != -1) { - Log.warn("SHA2 seed was found."); - Log.warn("Looking for world seeds with hash [" + this.hashedWorldSeed + "]."); - - for(long structureSeed: this.structureSeeds) { - for(long j = 0; j < (1L << 16); j++) { - long worldSeed = (j << 48) | structureSeed; - long hash = LevelProperties.sha256Hash(worldSeed); - - if(hash == this.hashedWorldSeed) { - this.worldSeeds.add(worldSeed); - Log.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds.")); - return added; - } - } - } - - Log.error("Finished search with no seeds, reverting to biomes."); - } - - Log.warn("Looking for world seeds with " + this.biomeCache.size() + " biomes."); - - this.structureSeeds.forEach(structureSeed -> { - for(long j = 0; j < (1L << 16); j++) { - long worldSeed = (j << 48) | structureSeed; - boolean goodSeed = true; - - FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed); - - for(BiomeData data : this.biomeCache) { - if(!data.test(fakeBiomeSource)) { - goodSeed = false; - break; - } - } - - if(goodSeed) { - this.worldSeeds.add(worldSeed); - } - } - }); - - if(this.worldSeeds.size() > 0) { - Log.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds.")); - } else { - Log.error("Finished search with no seeds."); - } - } else if(this.worldSeeds != null && biomeData != null) { - this.worldSeeds.removeIf(worldSeed -> { - FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed); - return !biomeData.test(fakeBiomeSource); - }); - } else if(this.worldSeeds != null) { - this.worldSeeds.removeIf(worldSeed -> { - for(BiomeData data: this.biomeCache) { - FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed); - if(!data.test(fakeBiomeSource))return true; - } - - return false; - }); - } - - return added; + public DataStorage getDataStorage() { + return this.dataStorage; } } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java b/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java index d472466..be3a50f 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java @@ -1,12 +1,16 @@ package kaptainwutax.seedcracker.cracker; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.ISeedStorage; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.source.VoronoiBiomeAccessType; import java.util.function.Predicate; -public class BiomeData { +public class BiomeData implements ISeedStorage { private BlockPos pos; @@ -18,6 +22,12 @@ public class BiomeData { this.biome = biome; } + public BiomeData(BlockPos pos, int biomeId) { + this.pos = pos; + this.biome = Registry.BIOME.get(biomeId); + } + + public BiomeData(BlockPos pos, Predicate biomePredicate) { this.pos = pos; this.biomePredicate = biomePredicate; @@ -40,7 +50,12 @@ public class BiomeData { } public static Biome sampleBiome(FakeBiomeSource source, int x, int y, int z) { - return VoronoiBiomeAccessType.INSTANCE.getBiome(source.getHashedSeed(), z, y, x, source); + return VoronoiBiomeAccessType.INSTANCE.getBiome(source.getHashedSeed(), x, y, z, source); + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.BIOMES); } @Override @@ -54,4 +69,12 @@ public class BiomeData { return false; } + @Override + public int hashCode() { + if(this.biomePredicate == null) { + return this.biome.getName().asFormattedString().hashCode(); + } + + return super.hashCode(); + } } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/ChestLootData.java b/src/main/java/kaptainwutax/seedcracker/cracker/ChestLootData.java index c2f0330..6f42829 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/ChestLootData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/ChestLootData.java @@ -13,7 +13,7 @@ import net.minecraft.util.math.BlockPos; import java.util.*; import java.util.function.BiPredicate; -public class ChestLootData implements ISeedData { +public class ChestLootData { private LootTable lootTable; private Map> stacksMap = new HashMap<>(); @@ -32,9 +32,8 @@ public class ChestLootData implements ISeedData { } } - @Override - public boolean test(long seed, Rand rand) { - rand.setSeed(seed, true); + public boolean test(long lootSeed, Rand rand) { + rand.setSeed(lootSeed, true); LootContext lootContext = new LootBuilder().setRandom(rand.toRandom()) .put(LootContextParameters.POSITION, new BlockPos(0, 0, 0)).build(LootContextTypes.CHEST); diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/DecoratorCache.java b/src/main/java/kaptainwutax/seedcracker/cracker/DecoratorCache.java deleted file mode 100644 index 261bfec..0000000 --- a/src/main/java/kaptainwutax/seedcracker/cracker/DecoratorCache.java +++ /dev/null @@ -1,69 +0,0 @@ -package kaptainwutax.seedcracker.cracker; - -import kaptainwutax.seedcracker.util.Log; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.gen.GenerationStep; -import net.minecraft.world.gen.decorator.Decorator; -import net.minecraft.world.gen.feature.ConfiguredFeature; -import net.minecraft.world.gen.feature.DecoratedFeatureConfig; -import net.minecraft.world.gen.feature.FeatureConfig; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class DecoratorCache { - - public static int INVALID = -1; - - private static DecoratorCache INSTANCE = new DecoratorCache(); - private boolean initialized = false; - - private Map, Integer>> decoratorSaltMap = new HashMap<>(); - - public static DecoratorCache get() { - return INSTANCE; - } - - public void initialize() { - Registry.BIOME.forEach(biome -> { - this.decoratorSaltMap.put(biome, new HashMap<>()); - - for(GenerationStep.Feature genStep: GenerationStep.Feature.values()) { - this.initializeBiomeStep(biome, genStep); - } - }); - - this.initialized = true; - } - - private void initializeBiomeStep(Biome biome, GenerationStep.Feature genStep) { - List> features = biome.getFeaturesForStep(genStep); - - for(int i = 0; i < features.size(); i++) { - FeatureConfig config = features.get(i).config; - if(!(config instanceof DecoratedFeatureConfig))continue; - this.decoratorSaltMap.get(biome).put(((DecoratedFeatureConfig)config).decorator.decorator, i + genStep.ordinal() * 10000); - } - } - - public int getSalt(Biome biome, Decorator feature, boolean debug) { - if(!this.initialized) { - this.initialize(); - } - - Integer salt = this.decoratorSaltMap.get(biome).get(feature); - - if(salt == null) { - if(debug) { - Log.error(biome.getClass().getSimpleName() + " does not have decorator " + feature + "."); - } - - salt = INVALID; - } - - return salt; - } - -} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/FakeBiomeSource.java b/src/main/java/kaptainwutax/seedcracker/cracker/FakeBiomeSource.java index 76eb2f7..9e43c3e 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/FakeBiomeSource.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/FakeBiomeSource.java @@ -43,7 +43,7 @@ public class FakeBiomeSource extends BiomeSource { } static { - BIOMES = ImmutableSet.of(Biomes.OCEAN, Biomes.PLAINS, Biomes.DESERT, Biomes.MOUNTAINS, Biomes.FOREST, Biomes.TAIGA, Biomes.SWAMP, Biomes.RIVER, Biomes.FROZEN_OCEAN, Biomes.FROZEN_RIVER, Biomes.SNOWY_TUNDRA, Biomes.SNOWY_MOUNTAINS, Biomes.MUSHROOM_FIELDS, Biomes.MUSHROOM_FIELD_SHORE, Biomes.BEACH, Biomes.DESERT_HILLS, Biomes.WOODED_HILLS, Biomes.TAIGA_HILLS, Biomes.MOUNTAIN_EDGE, Biomes.JUNGLE, Biomes.JUNGLE_HILLS, Biomes.JUNGLE_EDGE, Biomes.DEEP_OCEAN, Biomes.STONE_SHORE, Biomes.SNOWY_BEACH, Biomes.BIRCH_FOREST, Biomes.BIRCH_FOREST_HILLS, Biomes.DARK_FOREST, Biomes.SNOWY_TAIGA, Biomes.SNOWY_TAIGA_HILLS, Biomes.GIANT_TREE_TAIGA, Biomes.GIANT_TREE_TAIGA_HILLS, Biomes.WOODED_MOUNTAINS, Biomes.SAVANNA, Biomes.SAVANNA_PLATEAU, Biomes.BADLANDS, Biomes.WOODED_BADLANDS_PLATEAU, Biomes.BADLANDS_PLATEAU, Biomes.WARM_OCEAN, Biomes.LUKEWARM_OCEAN, Biomes.COLD_OCEAN, Biomes.DEEP_WARM_OCEAN, Biomes.DEEP_LUKEWARM_OCEAN, Biomes.DEEP_COLD_OCEAN, Biomes.DEEP_FROZEN_OCEAN, Biomes.SUNFLOWER_PLAINS, Biomes.DESERT_LAKES, Biomes.GRAVELLY_MOUNTAINS, Biomes.FLOWER_FOREST, Biomes.TAIGA_MOUNTAINS, Biomes.SWAMP_HILLS, Biomes.ICE_SPIKES, Biomes.MODIFIED_JUNGLE, Biomes.MODIFIED_JUNGLE_EDGE, Biomes.TALL_BIRCH_FOREST, Biomes.TALL_BIRCH_HILLS, Biomes.DARK_FOREST_HILLS, Biomes.SNOWY_TAIGA_MOUNTAINS, Biomes.GIANT_SPRUCE_TAIGA, Biomes.GIANT_SPRUCE_TAIGA_HILLS, Biomes.MODIFIED_GRAVELLY_MOUNTAINS, Biomes.SHATTERED_SAVANNA, Biomes.SHATTERED_SAVANNA_PLATEAU, Biomes.ERODED_BADLANDS, Biomes.MODIFIED_WOODED_BADLANDS_PLATEAU, Biomes.MODIFIED_BADLANDS_PLATEAU); + BIOMES = ImmutableSet.of(Biomes.OCEAN, Biomes.PLAINS, Biomes.DESERT, Biomes.MOUNTAINS, Biomes.FOREST, Biomes.TAIGA, new Biome[]{Biomes.SWAMP, Biomes.RIVER, Biomes.FROZEN_OCEAN, Biomes.FROZEN_RIVER, Biomes.SNOWY_TUNDRA, Biomes.SNOWY_MOUNTAINS, Biomes.MUSHROOM_FIELDS, Biomes.MUSHROOM_FIELD_SHORE, Biomes.BEACH, Biomes.DESERT_HILLS, Biomes.WOODED_HILLS, Biomes.TAIGA_HILLS, Biomes.MOUNTAIN_EDGE, Biomes.JUNGLE, Biomes.JUNGLE_HILLS, Biomes.JUNGLE_EDGE, Biomes.DEEP_OCEAN, Biomes.STONE_SHORE, Biomes.SNOWY_BEACH, Biomes.BIRCH_FOREST, Biomes.BIRCH_FOREST_HILLS, Biomes.DARK_FOREST, Biomes.SNOWY_TAIGA, Biomes.SNOWY_TAIGA_HILLS, Biomes.GIANT_TREE_TAIGA, Biomes.GIANT_TREE_TAIGA_HILLS, Biomes.WOODED_MOUNTAINS, Biomes.SAVANNA, Biomes.SAVANNA_PLATEAU, Biomes.BADLANDS, Biomes.WOODED_BADLANDS_PLATEAU, Biomes.BADLANDS_PLATEAU, Biomes.WARM_OCEAN, Biomes.LUKEWARM_OCEAN, Biomes.COLD_OCEAN, Biomes.DEEP_WARM_OCEAN, Biomes.DEEP_LUKEWARM_OCEAN, Biomes.DEEP_COLD_OCEAN, Biomes.DEEP_FROZEN_OCEAN, Biomes.SUNFLOWER_PLAINS, Biomes.DESERT_LAKES, Biomes.GRAVELLY_MOUNTAINS, Biomes.FLOWER_FOREST, Biomes.TAIGA_MOUNTAINS, Biomes.SWAMP_HILLS, Biomes.ICE_SPIKES, Biomes.MODIFIED_JUNGLE, Biomes.MODIFIED_JUNGLE_EDGE, Biomes.TALL_BIRCH_FOREST, Biomes.TALL_BIRCH_HILLS, Biomes.DARK_FOREST_HILLS, Biomes.SNOWY_TAIGA_MOUNTAINS, Biomes.GIANT_SPRUCE_TAIGA, Biomes.GIANT_SPRUCE_TAIGA_HILLS, Biomes.MODIFIED_GRAVELLY_MOUNTAINS, Biomes.SHATTERED_SAVANNA, Biomes.SHATTERED_SAVANNA_PLATEAU, Biomes.ERODED_BADLANDS, Biomes.MODIFIED_WOODED_BADLANDS_PLATEAU, Biomes.MODIFIED_BADLANDS_PLATEAU}); } } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/ISeedData.java b/src/main/java/kaptainwutax/seedcracker/cracker/ISeedData.java deleted file mode 100644 index e52614a..0000000 --- a/src/main/java/kaptainwutax/seedcracker/cracker/ISeedData.java +++ /dev/null @@ -1,9 +0,0 @@ -package kaptainwutax.seedcracker.cracker; - -import kaptainwutax.seedcracker.util.Rand; - -public interface ISeedData { - - boolean test(long seed, Rand rand); - -} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java b/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java index ba1c7d9..b19cbd5 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java @@ -1,11 +1,16 @@ package kaptainwutax.seedcracker.cracker; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.SeedData; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; +import kaptainwutax.seedcracker.util.Rand; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; -public class PillarData { +public class PillarData extends SeedData { private List heights; @@ -13,25 +18,20 @@ public class PillarData { this.heights = heights; } - public List getPillarSeeds() { - List result = new ArrayList<>(); - - for(int pillarSeed = 0; pillarSeed < (1 << 16); pillarSeed++) { - List h = this.getPillarHeights(pillarSeed); - if(h.equals(this.heights)) result.add(pillarSeed); - } - - return result; + @Override + public boolean test(long seed, Rand rand) { + List h = this.getPillarHeights((int)seed); + return h.equals(this.heights); } - public List getPillarHeights(int spikeSeed) { + public List getPillarHeights(int pillarSeed) { List indices = new ArrayList<>(); for(int i = 0; i < 10; i++) { indices.add(i); } - Collections.shuffle(indices, new Random(spikeSeed)); + Collections.shuffle(indices, new Random(pillarSeed)); List heights = new ArrayList<>(); @@ -42,4 +42,14 @@ public class PillarData { return heights; } + @Override + public double getBits() { + return 16; + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.PILLARS); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/SlimeChunkData.java b/src/main/java/kaptainwutax/seedcracker/cracker/SlimeChunkData.java index 54506fb..fd468a4 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/SlimeChunkData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/SlimeChunkData.java @@ -1,13 +1,18 @@ package kaptainwutax.seedcracker.cracker; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.SeedData; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; import kaptainwutax.seedcracker.util.Rand; import kaptainwutax.seedcracker.util.Seeds; import net.minecraft.util.math.ChunkPos; -public class SlimeChunkData implements ISeedData { +public class SlimeChunkData extends SeedData { - protected ChunkPos chunkPos; - protected boolean isSlimeChunk; + protected static final double BITS = Math.log(10) / Math.log(2); + + protected final ChunkPos chunkPos; + protected final boolean isSlimeChunk; public SlimeChunkData(ChunkPos chunkPos, boolean isSlimeChunk) { this.chunkPos = chunkPos; @@ -20,4 +25,14 @@ public class SlimeChunkData implements ISeedData { return (rand.nextInt(10) == 0) == this.isSlimeChunk; } + @Override + public double getBits() { + return BITS; + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java b/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java deleted file mode 100644 index 1868881..0000000 --- a/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java +++ /dev/null @@ -1,100 +0,0 @@ -package kaptainwutax.seedcracker.cracker; - -import kaptainwutax.seedcracker.cracker.population.DecoratorData; -import kaptainwutax.seedcracker.cracker.structure.StructureData; -import kaptainwutax.seedcracker.util.Log; -import kaptainwutax.seedcracker.util.Rand; -import kaptainwutax.seedcracker.util.math.LCG; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; - -public class TimeMachine { - - private LCG inverseLCG = Rand.JAVA_LCG.combine(-2); - public int THREAD_COUNT = 4; - public ExecutorService SERVICE = Executors.newFixedThreadPool(THREAD_COUNT); - - private boolean isRunning = false; - - public TimeMachine() { - - } - - public List bruteforceRegion(int pillarSeed, int region, long size, List structureDataList, List decoratorDataList) { - List result = new ArrayList<>(); - Rand rand = new Rand(0L); - - long start = region * size; - long end = start + size; - - for(long i = start; i < end; i++) { - long structureSeed = this.timeMachine(i, pillarSeed); - boolean goodSeed = true; - - for(StructureData structureData: structureDataList) { - if(!goodSeed)break; - if(!structureData.test(structureSeed, rand))goodSeed = false; - } - - for(DecoratorData decoratorData : decoratorDataList) { - if(!goodSeed)break; - if(!decoratorData.test(structureSeed, rand))goodSeed = false; - } - - if(goodSeed) { - result.add(structureSeed); - } - } - - return result; - } - - public Set buildStructureSeeds(int pillarSeed, List structureDataList, List decoratorDataList, Set structureSeeds) { - if(this.isRunning) { - throw new IllegalStateException("Time Machine is already running"); - } - - this.isRunning = true; - long size = (long)Math.ceil((double)(1L << 32) / THREAD_COUNT); - AtomicInteger progress = new AtomicInteger(); - - for(int i = 0; i < THREAD_COUNT; i++) { - int finalI = i; - - SERVICE.submit(() -> { - structureSeeds.addAll(this.bruteforceRegion(pillarSeed, finalI, size, structureDataList, decoratorDataList)); - Log.warn("Completed thread " + finalI + "!"); - progress.getAndIncrement(); - }); - } - - while(progress.get() < THREAD_COUNT) { - try {Thread.sleep(20);} - catch(InterruptedException e) {e.printStackTrace();} - } - - this.isRunning = false; - return structureSeeds; - } - - public long timeMachine(long partialWorldSeed, int pillarSeed) { - long currentSeed = 0L; - currentSeed |= (partialWorldSeed & 0xFFFF0000L) << 16; - currentSeed |= (long)pillarSeed << 16; - currentSeed |= partialWorldSeed & 0xFFFFL; - - currentSeed = this.inverseLCG.nextSeed(currentSeed); - currentSeed ^= Rand.JAVA_LCG.multiplier; - return currentSeed; - } - - public void stop() { - this.isRunning = false; - } - -} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/DecoratorData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/DecoratorData.java index 4f9cb88..ed4f45e 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/DecoratorData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/DecoratorData.java @@ -1,32 +1,26 @@ package kaptainwutax.seedcracker.cracker.population; -import kaptainwutax.seedcracker.cracker.DecoratorCache; -import kaptainwutax.seedcracker.cracker.ISeedData; +import kaptainwutax.seedcracker.cracker.storage.SeedData; import kaptainwutax.seedcracker.util.Rand; +import kaptainwutax.seedcracker.util.Seeds; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.Biome; -import net.minecraft.world.gen.decorator.Decorator; -public abstract class DecoratorData implements ISeedData { +public abstract class DecoratorData extends SeedData { private final ChunkPos chunkPos; - private final Decorator decorator; + private final int salt; private final Biome biome; - public DecoratorData(ChunkPos chunkPos, Decorator decorator, Biome biome) { + public DecoratorData(ChunkPos chunkPos, int salt, Biome biome) { this.chunkPos = chunkPos; - this.decorator = decorator; + this.salt = salt; this.biome = biome; } @Override public final boolean test(long seed, Rand rand) { - long decoratorSeed = this.getPopulationSeed(seed, this.chunkPos.x << 4, this.chunkPos.z << 4); - int salt = DecoratorCache.get().getSalt(this.biome, this.decorator, true); - - if(salt == DecoratorCache.INVALID) { - return false; - } + long decoratorSeed = Seeds.setPopulationSeed(null, seed, this.chunkPos.x << 4, this.chunkPos.z << 4); decoratorSeed += salt; decoratorSeed ^= Rand.JAVA_LCG.multiplier; @@ -35,13 +29,6 @@ public abstract class DecoratorData implements ISeedData { return this.testDecorator(rand); } - public long getPopulationSeed(long structureSeed, int x, int z) { - Rand rand = new Rand(structureSeed, true); - long a = rand.nextLong() | 1L; - long b = rand.nextLong() | 1L; - return (long)x * a + (long)z * b ^ structureSeed; - } - public abstract boolean testDecorator(Rand rand); @Override @@ -50,10 +37,15 @@ public abstract class DecoratorData implements ISeedData { if(obj instanceof DecoratorData) { DecoratorData decoratorData = ((DecoratorData)obj); - return decoratorData.chunkPos.equals(this.chunkPos) && decoratorData.decorator == this.decorator; + return decoratorData.chunkPos.equals(this.chunkPos) && decoratorData.salt == this.salt; } return false; } + @Override + public int hashCode() { + return this.chunkPos.hashCode() * 31 + this.salt; + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/DesertWellData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/DesertWellData.java index b979c21..cf1911e 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/DesertWellData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/DesertWellData.java @@ -1,17 +1,20 @@ package kaptainwutax.seedcracker.cracker.population; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; import kaptainwutax.seedcracker.util.Rand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.Biome; -import net.minecraft.world.gen.decorator.Decorator; public class DesertWellData extends DecoratorData { + public static final int SALT = 30010; + private static final double BITS = Math.log(1000 * 16 * 16) / Math.log(2); private BlockPos pos; public DesertWellData(ChunkPos chunkPos, Biome biome, BlockPos pos) { - super(chunkPos, Decorator.CHANCE_HEIGHTMAP, biome); + super(chunkPos, SALT, biome); this.pos = new BlockPos(pos.getX() & 15, pos.getY(), pos.getZ() & 15); } @@ -23,4 +26,14 @@ public class DesertWellData extends DecoratorData { return true; } + @Override + public double getBits() { + return BITS; + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java index 621fcc3..f64a1e5 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java @@ -1,18 +1,22 @@ package kaptainwutax.seedcracker.cracker.population; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; import kaptainwutax.seedcracker.util.Rand; import kaptainwutax.seedcracker.util.math.LCG; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.Biome; -import net.minecraft.world.gen.decorator.Decorator; import java.util.List; public class DungeonData extends DecoratorData { - public static LCG REVERSE_SKIP = Rand.JAVA_LCG.combine(-1); - public static LCG Y_START_SKIP = Rand.JAVA_LCG.combine(2); + private static final double BITS = Math.log(256 * 16 * 16 * 0.125D) / Math.log(2); + public static final int SALT = 20003; + + private static LCG REVERSE_SKIP = Rand.JAVA_LCG.combine(-1); + private static LCG Y_START_SKIP = Rand.JAVA_LCG.combine(2); public static LCG Y_SKIP = Rand.JAVA_LCG.combine(5); public static final Integer COBBLESTONE_CALL = 0; @@ -22,7 +26,7 @@ public class DungeonData extends DecoratorData { private final List> floorCallsList; public DungeonData(ChunkPos chunkPos, Biome biome, List starts, List> floorCallsList) { - super(chunkPos, Decorator.DUNGEONS, biome); + super(chunkPos, SALT, biome); this.starts = starts; this.floorCallsList = floorCallsList; } @@ -50,4 +54,14 @@ public class DungeonData extends DecoratorData { return false; } + @Override + public double getBits() { + return BITS; + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java index 947594e..2cc1290 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java @@ -1,18 +1,22 @@ package kaptainwutax.seedcracker.cracker.population; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; import kaptainwutax.seedcracker.util.Rand; import kaptainwutax.seedcracker.util.math.LCG; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.Biome; -import net.minecraft.world.gen.decorator.Decorator; import java.util.List; import java.util.stream.Collectors; public class EmeraldOreData extends DecoratorData { - public static final LCG[] SKIP = { + private static final double BITS = Math.log(28 * 16 * 16 * 0.5D) / Math.log(2); + public static final int SALT = 40014; + + private static final LCG[] SKIP = { Rand.JAVA_LCG.combine(0), Rand.JAVA_LCG.combine(1), Rand.JAVA_LCG.combine(2), @@ -22,7 +26,7 @@ public class EmeraldOreData extends DecoratorData { private List starts; public EmeraldOreData(ChunkPos chunkPos, Biome biome, List ores) { - super(chunkPos, Decorator.EMERALD_ORE, biome); + super(chunkPos, SALT, biome); this.starts = ores.stream().map(pos -> new BlockPos(pos.getX() & 15, pos.getY(), pos.getZ() & 15) @@ -51,4 +55,14 @@ public class EmeraldOreData extends DecoratorData { return false; } + @Override + public double getBits() { + return BITS; + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java index ef9d24e..d21b623 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java @@ -1,19 +1,23 @@ package kaptainwutax.seedcracker.cracker.population; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; import kaptainwutax.seedcracker.util.Rand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.Biome; -import net.minecraft.world.gen.decorator.Decorator; public class EndGatewayData extends DecoratorData { + private static final double BITS = Math.log(700 * 16 * 16 * 7) / Math.log(2); + private static final int SALT = 30000; + private int xOffset; private int zOffset; private int height; public EndGatewayData(ChunkPos chunkPos, Biome biome, BlockPos pos, int height) { - super(chunkPos, Decorator.END_GATEWAY, biome); + super(chunkPos, SALT, biome); this.xOffset = pos.getX() & 15; this.zOffset = pos.getZ() & 15; this.height = height; @@ -29,4 +33,14 @@ public class EndGatewayData extends DecoratorData { return true; } + @Override + public double getBits() { + return BITS; + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/storage/DataStorage.java b/src/main/java/kaptainwutax/seedcracker/cracker/storage/DataStorage.java new file mode 100644 index 0000000..fcb586b --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/storage/DataStorage.java @@ -0,0 +1,123 @@ +package kaptainwutax.seedcracker.cracker.storage; + +import io.netty.util.internal.ConcurrentSet; +import kaptainwutax.seedcracker.cracker.BiomeData; +import kaptainwutax.seedcracker.cracker.PillarData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.util.Log; + +import java.util.Comparator; +import java.util.Set; +import java.util.function.Consumer; + +public class DataStorage { + + public static Comparator SEED_DATA_COMPARATOR = (s1, s2) -> { + boolean isStructure1 = s1 instanceof StructureData; + boolean isStructure2 = s2 instanceof StructureData; + + if(isStructure1 != isStructure2) { + return isStructure2 ? 1: -1; + } + + if(s1.equals(s2)) { + return 0; + } + + double diff = s2.getBits() - s1.getBits(); + return diff == 0.0D ? 1 : (int)Math.signum(diff); + }; + + protected TimeMachine timeMachine = new TimeMachine(this); + protected Set> scheduledData = new ConcurrentSet<>(); + + protected PillarData pillarData = null; + protected ScheduledSet baseSeedData = new ScheduledSet<>(SEED_DATA_COMPARATOR); + protected ScheduledSet biomeSeedData = new ScheduledSet<>(null); + protected HashedSeedData hashedSeedData = null; + + public void tick() { + if(!this.timeMachine.isRunning) { + this.baseSeedData.dump(); + this.biomeSeedData.dump(); + + this.scheduledData.removeIf(c -> { + c.accept(this); + return true; + }); + } + } + + public synchronized boolean addPillarData(PillarData pillarData) { + boolean isAdded = this.pillarData == null; + + if(isAdded && pillarData != null) { + this.pillarData = pillarData; + this.schedule(pillarData::onDataAdded); + } + + return isAdded; + } + + public synchronized boolean addBaseData(SeedData seedData) { + if(this.baseSeedData.contains(seedData)) { + return false; + } + + this.baseSeedData.scheduleAdd(seedData); + this.schedule(seedData::onDataAdded); + return true; + } + + public synchronized boolean addBiomeData(BiomeData biomeData) { + if(this.biomeSeedData.contains(biomeData)) { + return false; + } + + this.biomeSeedData.scheduleAdd(biomeData); + this.schedule(biomeData::onDataAdded); + return true; + } + + public synchronized boolean addHashedSeedData(HashedSeedData hashedSeedData) { + if(this.hashedSeedData == null || this.hashedSeedData.getHashedSeed() != hashedSeedData.getHashedSeed()) { + Log.warn("Fetched hashed world seed [" + hashedSeedData.getHashedSeed() + "]."); + this.hashedSeedData = hashedSeedData; + this.schedule(hashedSeedData::onDataAdded); + return true; + } + + return false; + } + + public void schedule(Consumer consumer) { + this.scheduledData.add(consumer); + } + + public TimeMachine getTimeMachine() { + return this.timeMachine; + } + + public double getBaseBits() { + double bits = 0.0D; + + for(SeedData baseSeedDatum: this.baseSeedData) { + bits += baseSeedDatum.getBits(); + } + + return bits; + } + + public void clear() { + System.out.println("Clearing data storage."); + this.scheduledData = new ConcurrentSet<>(); + + this.pillarData = null; + this.baseSeedData = new ScheduledSet<>(SEED_DATA_COMPARATOR); + this.biomeSeedData = new ScheduledSet<>(null); + this.hashedSeedData = null; + this.timeMachine.terminate = true; + this.timeMachine = new TimeMachine(this); + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/storage/HashedSeedData.java b/src/main/java/kaptainwutax/seedcracker/cracker/storage/HashedSeedData.java new file mode 100644 index 0000000..e33275c --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/storage/HashedSeedData.java @@ -0,0 +1,33 @@ +package kaptainwutax.seedcracker.cracker.storage; + +import kaptainwutax.seedcracker.util.Rand; +import net.minecraft.world.level.LevelProperties; + +public class HashedSeedData extends SeedData { + + private final long hashedSeed; + + public HashedSeedData(long hashedSeed) { + this.hashedSeed = hashedSeed; + } + + @Override + public boolean test(long seed, Rand rand) { + return LevelProperties.sha256Hash(seed) == this.hashedSeed; + } + + public long getHashedSeed() { + return this.hashedSeed; + } + + @Override + public double getBits() { + return 64; + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.BIOMES); + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/storage/ISeedStorage.java b/src/main/java/kaptainwutax/seedcracker/cracker/storage/ISeedStorage.java new file mode 100644 index 0000000..aaf4ef0 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/storage/ISeedStorage.java @@ -0,0 +1,7 @@ +package kaptainwutax.seedcracker.cracker.storage; + +public interface ISeedStorage { + + void onDataAdded(DataStorage dataStorage); + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/storage/ScheduledSet.java b/src/main/java/kaptainwutax/seedcracker/cracker/storage/ScheduledSet.java new file mode 100644 index 0000000..f2d02a3 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/storage/ScheduledSet.java @@ -0,0 +1,44 @@ +package kaptainwutax.seedcracker.cracker.storage; + +import java.util.*; + +public class ScheduledSet implements Iterable { + + protected final Set baseSet; + protected final Set scheduledSet; + + public ScheduledSet(Comparator comparator) { + if(comparator != null) { + this.baseSet = new TreeSet<>(comparator); + } else { + this.baseSet = new HashSet<>(); + } + + this.scheduledSet = new HashSet<>(); + } + + public synchronized void scheduleAdd(T e) { + this.scheduledSet.add(e); + } + + public synchronized void dump() { + synchronized(this.baseSet) { + this.baseSet.addAll(this.scheduledSet); + this.scheduledSet.clear(); + } + } + + public synchronized boolean contains(T e) { + return this.baseSet.contains(e) || this.scheduledSet.contains(e); + } + + @Override + public synchronized Iterator iterator() { + return this.baseSet.iterator(); + } + + public synchronized int size() { + return this.baseSet.size(); + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/storage/SeedData.java b/src/main/java/kaptainwutax/seedcracker/cracker/storage/SeedData.java new file mode 100644 index 0000000..d708e38 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/storage/SeedData.java @@ -0,0 +1,11 @@ +package kaptainwutax.seedcracker.cracker.storage; + +import kaptainwutax.seedcracker.util.Rand; + +public abstract class SeedData implements ISeedStorage { + + public abstract boolean test(long seed, Rand rand); + + public abstract double getBits(); + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/storage/TimeMachine.java b/src/main/java/kaptainwutax/seedcracker/cracker/storage/TimeMachine.java new file mode 100644 index 0000000..ddb615c --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/storage/TimeMachine.java @@ -0,0 +1,215 @@ +package kaptainwutax.seedcracker.cracker.storage; + +import kaptainwutax.seedcracker.cracker.BiomeData; +import kaptainwutax.seedcracker.cracker.FakeBiomeSource; +import kaptainwutax.seedcracker.util.Log; +import kaptainwutax.seedcracker.util.Rand; +import kaptainwutax.seedcracker.util.math.LCG; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class TimeMachine { + + public static ExecutorService SERVICE = Executors.newFixedThreadPool(1); + + private LCG inverseLCG = Rand.JAVA_LCG.combine(-2); + protected DataStorage dataStorage; + + public boolean isRunning = false; + public boolean terminate = false; + + protected List pillarSeeds = null; + protected List structureSeeds = null; + protected List worldSeeds = null; + + public TimeMachine(DataStorage dataStorage) { + this.dataStorage = dataStorage; + } + + public void poke(Phase phase) { + this.isRunning = true; + final Phase[] finalPhase = {phase}; + + SERVICE.submit(() -> { + while(finalPhase[0] != null && !this.terminate) { + if(finalPhase[0] == Phase.PILLARS) { + if(!this.pokePillars())break; + } else if(finalPhase[0] == Phase.STRUCTURES) { + if(!this.pokeStructures())break; + } else if(finalPhase[0] == Phase.BIOMES) { + if(!this.pokeBiomes())break; + } + + finalPhase[0] = finalPhase[0].nextPhase(); + } + }); + + this.isRunning = false; + } + + protected boolean pokePillars() { + if(this.pillarSeeds != null || this.dataStorage.pillarData == null)return false; + this.pillarSeeds = new ArrayList<>(); + + Log.debug("===================================="); + Log.warn("Looking for pillar seeds..."); + + for(int pillarSeed = 0; pillarSeed < 1 << 16 && !this.terminate; pillarSeed++) { + if(this.dataStorage.pillarData.test(pillarSeed, null)) { + Log.warn("Found pillar seed [" + pillarSeed + "]."); + this.pillarSeeds.add(pillarSeed); + } + } + + if(!this.pillarSeeds.isEmpty()) { + Log.warn("Finished searching for pillar seeds."); + } else { + Log.error("Finished search with no results."); + } + + return true; + } + + protected boolean pokeStructures() { + if(this.pillarSeeds == null || this.structureSeeds != null || this.dataStorage.getBaseBits() < 54.0D)return false; + this.structureSeeds = new ArrayList<>(); + + Rand rand = new Rand(0L, false); + Log.debug("===================================="); + Log.warn("Looking for structure seeds..."); + + for(int pillarSeed: this.pillarSeeds) { + for(long partialWorldSeed = 0; partialWorldSeed < 1L << 32; partialWorldSeed++) { + if((partialWorldSeed & ((1 << 29) - 1)) == 0) { + Log.debug("Progress: " + ((100.0D * (double)partialWorldSeed) / (double)(1L << 32)) + "%"); + } + + long seed = this.timeMachine(partialWorldSeed, pillarSeed); + boolean matches = true; + + for(SeedData baseSeedDatum: this.dataStorage.baseSeedData) { + if(!baseSeedDatum.test(seed, rand)) { + matches = false; + break; + } + } + + if(matches) { + this.structureSeeds.add(seed); + Log.warn("Found structure seed [" + seed + "]."); + } + + if(this.terminate) { + return false; + } + } + } + + if(!this.structureSeeds.isEmpty()) { + Log.warn("Finished searching for structure seeds."); + } else { + Log.error("Finished search with no results."); + } + + return true; + } + + protected boolean pokeBiomes() { + if(this.structureSeeds == null || this.worldSeeds != null)return false; + if(this.dataStorage.hashedSeedData == null && this.dataStorage.biomeSeedData.size() < 5)return false; + + this.worldSeeds = new ArrayList<>(); + Log.debug("===================================="); + Log.warn("Looking for world seeds..."); + + if(this.dataStorage.hashedSeedData != null) { + for(long structureSeed: this.structureSeeds) { + for(long upperBits = 0; upperBits < 1 << 16; upperBits++) { + long worldSeed = (upperBits << 48) | structureSeed; + + if(!this.dataStorage.hashedSeedData.test(worldSeed, null)) { + continue; + } else { + this.worldSeeds.add(worldSeed); + Log.warn("Found world seed [" + worldSeed + "]"); + } + + if(this.terminate) { + return false; + } + } + } + + if(!this.worldSeeds.isEmpty()) { + Log.warn("Finished searching for world seeds."); + return true; + } else { + Log.error("Finished search with no results, reverting back to biomes."); + } + } + + Log.warn("Looking for world seeds..."); + + for(long structureSeed: this.structureSeeds) { + for(long upperBits = 0; upperBits < 1 << 16; upperBits++) { + long worldSeed = (upperBits << 48) | structureSeed; + + FakeBiomeSource source = new FakeBiomeSource(worldSeed); + boolean matches = true; + + for(BiomeData biomeSeedDatum: this.dataStorage.biomeSeedData) { + if(!biomeSeedDatum.test(source)) { + matches = false; + break; + } + } + + if(matches) { + this.worldSeeds.add(worldSeed); + Log.warn("Found world seed [" + worldSeed + "]."); + } + + if(this.terminate) { + return false; + } + } + } + + if(!this.worldSeeds.isEmpty()) { + Log.warn("Finished searching for world seeds."); + } else { + Log.error("Finished search with no results."); + } + + return true; + } + + public long timeMachine(long partialWorldSeed, int pillarSeed) { + long currentSeed = 0L; + currentSeed |= (partialWorldSeed & 0xFFFF0000L) << 16; + currentSeed |= (long)pillarSeed << 16; + currentSeed |= partialWorldSeed & 0xFFFFL; + + currentSeed = this.inverseLCG.nextSeed(currentSeed); + currentSeed ^= Rand.JAVA_LCG.multiplier; + return currentSeed; + } + + public enum Phase { + BIOMES(null), STRUCTURES(BIOMES), PILLARS(STRUCTURES); + + private final Phase nextPhase; + + Phase(Phase nextPhase) { + this.nextPhase = nextPhase; + } + + public Phase nextPhase() { + return this.nextPhase; + } + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureData.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureData.java index 4627e0b..1cf564d 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureData.java @@ -1,12 +1,14 @@ package kaptainwutax.seedcracker.cracker.structure; -import kaptainwutax.seedcracker.cracker.ISeedData; +import kaptainwutax.seedcracker.cracker.storage.DataStorage; +import kaptainwutax.seedcracker.cracker.storage.SeedData; +import kaptainwutax.seedcracker.cracker.storage.TimeMachine; import kaptainwutax.seedcracker.cracker.structure.type.FeatureType; -import kaptainwutax.seedcracker.util.Seeds; import kaptainwutax.seedcracker.util.Rand; +import kaptainwutax.seedcracker.util.Seeds; import net.minecraft.util.math.ChunkPos; -public class StructureData implements ISeedData { +public class StructureData extends SeedData { public int chunkX; public int chunkZ; @@ -29,16 +31,31 @@ public class StructureData implements ISeedData { return this.featureType.test(rand, this, structureSeed); } + @Override + public double getBits() { + return this.featureType.getBits(); + } + + @Override + public void onDataAdded(DataStorage dataStorage) { + dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); + } + @Override public boolean equals(Object obj) { if(obj == this)return true; if(obj instanceof StructureData) { StructureData structureData = ((StructureData)obj); - return structureData.regionX == this.regionX && structureData.regionZ == this.regionZ && structureData.featureType == this.featureType; + return structureData.featureType == this.featureType && structureData.regionX == this.regionX && structureData.regionZ == this.regionZ; } return false; } + @Override + public int hashCode() { + return this.regionX * 961 + this.regionZ * 31 + this.featureType.salt; + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureFeatures.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureFeatures.java index c7f58ab..48cab73 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureFeatures.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureFeatures.java @@ -41,6 +41,8 @@ public class StructureFeatures { public static final FeatureType BURIED_TREASURE = new RarityType(10387320, 1, 0.01F); public static final FeatureType NETHER_FORTRESS = new FeatureType(-1, 1) { + protected final double bits = Math.log(3 * 8 * 8) / Math.log(2); + @Override public boolean test(Rand rand, StructureData data, long structureSeed) { Seeds.setWeakSeed(rand, structureSeed, data.chunkX, data.chunkZ); @@ -49,14 +51,26 @@ public class StructureFeatures { && data.chunkX == ((data.chunkX >> 4) << 4) + 4 + rand.nextInt(8) && data.chunkZ == ((data.chunkZ >> 4) << 4) + 4 + rand.nextInt(8); } + + @Override + public double getBits() { + return this.bits; + } }; public static final FeatureType MINESHAFT = new FeatureType(-1, 1) { + protected final double bits = Math.log(1.0D / 0.004D) / Math.log(2); + @Override public boolean test(Rand rand, StructureData data, long structureSeed) { Seeds.setStructureStartSeed(rand, structureSeed, data.chunkX, data.chunkZ); return rand.nextDouble() < 0.004D; } + + @Override + public double getBits() { + return this.bits; + } }; } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/AbstractTempleType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/AbstractTempleType.java index 76b842f..fe89f2c 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/AbstractTempleType.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/AbstractTempleType.java @@ -6,10 +6,12 @@ import kaptainwutax.seedcracker.util.Rand; public class AbstractTempleType extends FeatureType { protected final int offset; + protected final double bits; public AbstractTempleType(int salt, int distance, int offset) { super(salt, distance); this.offset = offset; + this.bits = Math.log(this.offset * this.offset) / Math.log(2); } @Override @@ -17,4 +19,9 @@ public class AbstractTempleType extends FeatureType { return rand.nextInt(this.offset) == data.offsetX && rand.nextInt(this.offset) == data.offsetZ; } + @Override + public double getBits() { + return this.bits; + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/FeatureType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/FeatureType.java index 1f0057a..a7166fc 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/FeatureType.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/FeatureType.java @@ -40,4 +40,6 @@ public abstract class FeatureType { public abstract boolean test(Rand rand, T data, long structureSeed); + public abstract double getBits(); + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/RarityType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/RarityType.java index bcf4db0..0749124 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/RarityType.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/RarityType.java @@ -5,11 +5,13 @@ import kaptainwutax.seedcracker.util.Rand; public class RarityType extends FeatureType { - private float rarity; + private final float rarity; + private final double bits; public RarityType(int salt, int distance, float rarity) { super(salt, distance); this.rarity = rarity; + this.bits = Math.log(1.0D / this.rarity) / Math.log(2); } @Override @@ -17,4 +19,9 @@ public class RarityType extends FeatureType { return rand.nextFloat() < this.rarity; } + @Override + public double getBits() { + return this.bits; + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/TriangularType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/TriangularType.java index b7467d5..affb07d 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/TriangularType.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/TriangularType.java @@ -7,10 +7,12 @@ import kaptainwutax.seedcracker.util.Rand; public class TriangularType extends FeatureType { protected final int peak; + protected final double bits; public TriangularType(int salt, int distance, int peak) { super(salt, distance); this.peak = peak; + this.bits = Math.log(this.peak * this.peak) / Math.log(2); } @Override @@ -19,4 +21,12 @@ public class TriangularType extends FeatureType { && (rand.nextInt(this.peak) + rand.nextInt(this.peak)) / 2 == data.offsetZ; } + /* + * For this type specifically, the bits approximation is bad since the distribution is special. + */ + @Override + public double getBits() { + return this.bits; + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java index e2a691a..db6b015 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java @@ -35,7 +35,7 @@ public class BiomeFinder extends Finder { continue; } - if(SeedCracker.get().onBiomeData(new BiomeData(blockPos, biome))) { + if(SeedCracker.get().getDataStorage().addBiomeData(new BiomeData(blockPos, biome))) { blockPos = this.world.getTopPosition(Heightmap.Type.WORLD_SURFACE, blockPos).down(); result.add(blockPos); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java b/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java index bdb31cb..28995f0 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java @@ -27,17 +27,20 @@ public class FinderQueue { } public void onChunkData(World world, ChunkPos chunkPos) { - this.finderConfig.getActiveFinderTypes().forEach(type -> { + this.finderConfig.getActiveFinderTypes().forEach(type -> { SERVICE.submit(() -> { - List finders = type.finderBuilder.build(world, chunkPos); + try { + List finders = type.finderBuilder.build(world, chunkPos); - finders.forEach(finder -> { - if(finder.isValidDimension(world.dimension.getType())) { - this.finderConfig.addFinder(type, finder); - finder.findInChunk(); - this.finderConfig.addFinder(type, finder); - } - }); + finders.forEach(finder -> { + if(finder.isValidDimension(world.dimension.getType())) { + finder.findInChunk(); + this.finderConfig.addFinder(type, finder); + } + }); + } catch(Exception e) { + e.printStackTrace(); + } }); }); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/population/DesertWellFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/population/DesertWellFinder.java index a3159b9..2dc324f 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/DesertWellFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/DesertWellFinder.java @@ -48,9 +48,10 @@ public class DesertWellFinder extends PieceFinder { List result = super.findInChunk(); result.forEach(pos -> { - this.renderers.add(new Cuboid(pos, SIZE, new Vector4f(0.5f, 0.5f, 1.0f, 1.0f))); - this.renderers.add(new Cube(pos.add(2, 1, 2), new Vector4f(0.5f, 0.5f, 1.0f, 1.0f))); - SeedCracker.get().onDecoratorData(new DesertWellData(this.chunkPos, biome, pos.add(2, 1, 2))); + if(SeedCracker.get().getDataStorage().addBaseData(new DesertWellData(this.chunkPos, biome, pos.add(2, 1, 2)))) { + this.renderers.add(new Cuboid(pos, SIZE, new Vector4f(0.5f, 0.5f, 1.0f, 1.0f))); + this.renderers.add(new Cube(pos.add(2, 1, 2), new Vector4f(0.5f, 0.5f, 1.0f, 1.0f))); + } }); return result; diff --git a/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java index 8416705..bdfab38 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java @@ -72,7 +72,7 @@ public class DungeonFinder extends BlockFinder { .map(pos -> this.getFloorCalls(this.getDungeonSize(pos), pos)).collect(Collectors.toList()); result.forEach(pos -> { - if(SeedCracker.get().onDecoratorData(new DungeonData(this.chunkPos, biome, starts, floorCallsList))) { + if(SeedCracker.get().getDataStorage().addBaseData(new DungeonData(this.chunkPos, biome, starts, floorCallsList))) { this.renderers.add(new Cube(pos, new Vector4f(1.0f, 0.0f, 0.0f, 1.0f))); Vec3i size = this.getDungeonSize(pos); this.renderers.add(new Cuboid(pos.subtract(size), pos.add(size).add(1, -1, 1), new Vector4f(1.0f, 0.0f, 0.0f, 1.0f))); diff --git a/src/main/java/kaptainwutax/seedcracker/finder/population/EndGatewayFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/population/EndGatewayFinder.java index 497806f..b0290dc 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/EndGatewayFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/EndGatewayFinder.java @@ -1,7 +1,6 @@ package kaptainwutax.seedcracker.finder.population; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.DecoratorCache; import kaptainwutax.seedcracker.cracker.population.EndGatewayData; import kaptainwutax.seedcracker.finder.BlockFinder; import kaptainwutax.seedcracker.finder.Finder; @@ -14,7 +13,6 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.dimension.DimensionType; -import net.minecraft.world.gen.decorator.Decorator; import java.util.ArrayList; import java.util.List; @@ -35,10 +33,6 @@ public class EndGatewayFinder extends BlockFinder { //If no end gateway is supposed to populate in this chunk, return. Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(8, 0, 8)); - if(DecoratorCache.get().getSalt(biome, Decorator.END_GATEWAY, false) == DecoratorCache.INVALID) { - return new ArrayList<>(); - } - List result = super.findInChunk(); List newResult = new ArrayList<>(); @@ -48,7 +42,7 @@ public class EndGatewayFinder extends BlockFinder { if(height >= 3 && height <= 9) { newResult.add(pos); - if(SeedCracker.get().onDecoratorData(new EndGatewayData(this.chunkPos, biome, pos, height))) { + if(SeedCracker.get().getDataStorage().addBaseData(new EndGatewayData(this.chunkPos, biome, pos, height))) { this.renderers.add(new Cuboid(pos.add(-1, -2, -1), pos.add(2, 3, 2), new Vector4f(0.4f, 0.4f, 0.82f, 1.0f))); } } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/population/EndPillarsFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/population/EndPillarsFinder.java index 9fb5dc6..3bf6b0b 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/EndPillarsFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/EndPillarsFinder.java @@ -26,7 +26,7 @@ public class EndPillarsFinder extends Finder { public EndPillarsFinder(World world, ChunkPos chunkPos) { super(world, chunkPos); - this.alreadyFound = SeedCracker.get().onPillarData(null); + this.alreadyFound = !SeedCracker.get().getDataStorage().addPillarData(null); if(this.alreadyFound)return; for(int i = 0; i < this.bedrockMarkers.length; i++) { @@ -48,7 +48,7 @@ public class EndPillarsFinder extends Finder { if(result.size() == this.bedrockMarkers.length) { PillarData pillarData = new PillarData(result.stream().map(Vec3i::getY).collect(Collectors.toList())); - if(SeedCracker.get().onPillarData(pillarData)){ + if(SeedCracker.get().getDataStorage().addPillarData(pillarData)) { result.forEach(pos -> this.renderers.add(new Cube(pos, new Vector4f(0.5f, 0.0f, 0.5f, 1.0f)))); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/population/ore/EmeraldOreFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/population/ore/EmeraldOreFinder.java index 2a60f87..53cd968 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/ore/EmeraldOreFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/ore/EmeraldOreFinder.java @@ -1,7 +1,6 @@ package kaptainwutax.seedcracker.finder.population.ore; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.DecoratorCache; import kaptainwutax.seedcracker.cracker.population.EmeraldOreData; import kaptainwutax.seedcracker.finder.BlockFinder; import kaptainwutax.seedcracker.finder.Finder; @@ -13,7 +12,6 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.dimension.DimensionType; -import net.minecraft.world.gen.decorator.Decorator; import java.util.ArrayList; import java.util.List; @@ -35,13 +33,9 @@ public class EmeraldOreFinder extends BlockFinder { public List findInChunk() { Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(8, 0, 8)); - if(DecoratorCache.get().getSalt(biome, Decorator.EMERALD_ORE, false) == DecoratorCache.INVALID) { - return new ArrayList<>(); - } - List result = super.findInChunk(); - if(!result.isEmpty() && SeedCracker.get().onDecoratorData(new EmeraldOreData(this.chunkPos, biome, result))) { + if(!result.isEmpty() && SeedCracker.get().getDataStorage().addBaseData(new EmeraldOreData(this.chunkPos, biome, result))) { //TODO: support more ores. this.renderers.add(new Cube(result.get(0), new Vector4f(0.0f, 1.0f, 0.0f, 1.0f))); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/BuriedTreasureFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/BuriedTreasureFinder.java index 8969a26..64ac6d9 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/BuriedTreasureFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/BuriedTreasureFinder.java @@ -72,7 +72,7 @@ public class BuriedTreasureFinder extends BlockFinder { }); result.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.BURIED_TREASURE))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.BURIED_TREASURE))) { this.renderers.add(new Cube(pos, new Vector4f(1.0f, 1.0f, 0.0f, 1.0f))); } }); diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/DesertTempleFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/DesertTempleFinder.java index 36bdc0e..fcb922e 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/DesertTempleFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/DesertTempleFinder.java @@ -36,7 +36,7 @@ public class DesertTempleFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if( SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.DESERT_PYRAMID))) { + if( SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.DESERT_PYRAMID))) { this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f))); } }); diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/EndCityFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/EndCityFinder.java index 487146f..57d9c03 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/EndCityFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/EndCityFinder.java @@ -86,7 +86,7 @@ public class EndCityFinder extends Finder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.END_CITY))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.END_CITY))) { this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.6f, 0.0f, 0.6f, 1.0f))); this.renderers.add(new Cube(pos, new Vector4f(0.6f, 0.0f, 0.6f, 1.0f))); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/IglooFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/IglooFinder.java index 4fa937d..c4b29ca 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/IglooFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/IglooFinder.java @@ -45,7 +45,7 @@ public class IglooFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.IGLOO))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.IGLOO))) { this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.0f, 1.0f, 1.0f, 1.0f))); this.renderers.add(new Cube(pos, new Vector4f(0.0f, 1.0f, 1.0f, 1.0f))); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/JungleTempleFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/JungleTempleFinder.java index 96be497..d43e985 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/JungleTempleFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/JungleTempleFinder.java @@ -36,7 +36,7 @@ public class JungleTempleFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.JUNGLE_TEMPLE))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.JUNGLE_TEMPLE))) { this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f))); } }); diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/MansionFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/MansionFinder.java index efef387..fad809d 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/MansionFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/MansionFinder.java @@ -62,7 +62,7 @@ public class MansionFinder extends Finder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.WOODLAND_MANSION))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.WOODLAND_MANSION))) { this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.4f, 0.26f, 0.13f, 1.0f))); this.renderers.add(new Cube(this.chunkPos.getCenterBlockPos().add(0, pos.getY(), 0), new Vector4f(0.4f, 0.26f, 0.13f, 1.0f))); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java index 7484456..cd8c537 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java @@ -58,7 +58,7 @@ public class OceanMonumentFinder extends Finder { positions.forEach(pos -> { ChunkPos monumentStart = new ChunkPos(this.chunkPos.x + 1, this.chunkPos.z + 1); - if(SeedCracker.get().onStructureData(new StructureData(monumentStart, StructureFeatures.OCEAN_MONUMENT))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(monumentStart, StructureFeatures.OCEAN_MONUMENT))) { this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.0f, 0.0f, 1.0f, 1.0f))); this.renderers.add(new Cube(monumentStart.getCenterBlockPos().add(0, pos.getY(), 0), new Vector4f(0.0f, 0.0f, 1.0f, 1.0f))); } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java index c1f3a4f..7829972 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java @@ -175,7 +175,7 @@ public class ShipwreckFinder extends BlockFinder { mutablePos.setOffset(-4, -chestY, -15); if((mutablePos.getX() & 0xf) == 0 && (mutablePos.getZ() & 0xf) == 0) { - if(SeedCracker.get().onStructureData(new StructureData(new ChunkPos(mutablePos), StructureFeatures.SHIPWRECK))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(new ChunkPos(mutablePos), StructureFeatures.SHIPWRECK))) { this.renderers.add(new Cuboid(box, new Vector4f(1.0f, 0.0f, 1.0f, 1.0f))); this.renderers.add(new Cube(new ChunkPos(mutablePos).getCenterBlockPos().offset(Direction.UP, mutablePos.getY()), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f))); return true; diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java index 84bbe23..bbc6a87 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java @@ -37,7 +37,7 @@ public class SwampHutFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.SWAMP_HUT))) { + if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.SWAMP_HUT))) { this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f))); } }); diff --git a/src/main/java/kaptainwutax/seedcracker/magic/PopulationReversal.java b/src/main/java/kaptainwutax/seedcracker/magic/PopulationReversal.java index 771bed0..f558b94 100644 --- a/src/main/java/kaptainwutax/seedcracker/magic/PopulationReversal.java +++ b/src/main/java/kaptainwutax/seedcracker/magic/PopulationReversal.java @@ -14,7 +14,7 @@ public class PopulationReversal { private static final LCG SKIP_4 = Rand.JAVA_LCG.combine(4); public static ArrayList getWorldSeeds(long populationSeed, int x, int z) { - populationSeed = populationSeed ^ Rand.JAVA_LCG.multiplier; + populationSeed ^= Rand.JAVA_LCG.multiplier; ArrayList worldSeeds = new ArrayList<>(); if (x == 0 && z == 0) { @@ -105,7 +105,7 @@ public class PopulationReversal { seed = r.nextLong() & ((1L << 48)-1); x = r.nextInt(16) - 8; z = r.nextInt(16) - 8; - seeds = getWorldSeeds(Seeds.setPopulationSeed(null, seed,x,z), x, z); + seeds = getWorldSeeds(Seeds.setPopulationSeed(null, seed, x, z) ^ Rand.JAVA_LCG.multiplier, x, z); if (!seeds.contains(seed)) { System.out.println(seed); diff --git a/src/main/java/kaptainwutax/seedcracker/magic/RandomSeed.java b/src/main/java/kaptainwutax/seedcracker/magic/RandomSeed.java index 242da76..6968f46 100644 --- a/src/main/java/kaptainwutax/seedcracker/magic/RandomSeed.java +++ b/src/main/java/kaptainwutax/seedcracker/magic/RandomSeed.java @@ -20,5 +20,4 @@ public class RandomSeed { return new Rand(seed, false).nextLong() == worldSeed; } - } diff --git a/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java index 792ed5e..ce54609 100644 --- a/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java @@ -4,8 +4,8 @@ import com.mojang.authlib.GameProfile; import com.mojang.brigadier.CommandDispatcher; import kaptainwutax.seedcracker.SeedCracker; import kaptainwutax.seedcracker.command.ClientCommands; +import kaptainwutax.seedcracker.cracker.storage.HashedSeedData; import kaptainwutax.seedcracker.finder.FinderQueue; -import kaptainwutax.seedcracker.util.Log; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.network.ClientPlayNetworkHandler; @@ -50,8 +50,7 @@ public abstract class ClientPlayNetworkHandlerMixin { @Inject(method = "onPlayerRespawn", at = @At("HEAD")) public void onPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) { - SeedCracker.get().hashedWorldSeed = packet.method_22425(); - Log.warn("Fetched hashed world seed [" + SeedCracker.get().hashedWorldSeed + "]."); + SeedCracker.get().getDataStorage().addHashedSeedData(new HashedSeedData(packet.method_22425())); } } diff --git a/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayerEntityMixin.java b/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayerEntityMixin.java index caca170..da34d8c 100644 --- a/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayerEntityMixin.java @@ -1,6 +1,7 @@ package kaptainwutax.seedcracker.mixin; import com.mojang.brigadier.StringReader; +import kaptainwutax.seedcracker.SeedCracker; import kaptainwutax.seedcracker.command.ClientCommands; import net.minecraft.client.network.ClientPlayerEntity; import org.spongepowered.asm.mixin.Mixin; @@ -13,6 +14,11 @@ import java.util.regex.Pattern; @Mixin(ClientPlayerEntity.class) public abstract class ClientPlayerEntityMixin { + @Inject(method = "tick", at = @At("HEAD")) + private void tick(CallbackInfo ci) { + SeedCracker.get().getDataStorage().tick(); + } + @Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true) private void onSendChatMessage(String message, CallbackInfo ci) { if(message.startsWith("/")) { diff --git a/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java b/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java index 5d772a1..e9f83e4 100644 --- a/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java +++ b/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java @@ -16,7 +16,7 @@ public abstract class ClientWorldMixin { @Inject(method = "disconnect", at = @At("HEAD")) private void disconnect(CallbackInfo ci) { - SeedCracker.get().clear(); + SeedCracker.get().getDataStorage().clear(); FinderQueue.get().clear(); }