diff --git a/README.md b/README.md index d3e5898..f35e44c 100644 --- a/README.md +++ b/README.md @@ -1 +1,33 @@ -SeedCracker +# SeedCracker + +## Installation + +Download and install the [fabric mod loader](https://fabricmc.net/use/). + +Then download the lastest [release](https://github.com/KaptainWutax/SeedCracker/releases) of SeedCracker and put the `.jar` file in the `%appdata%/.minecraft/mods/` folder. + +## Usage + +Launch minercaft with the fabric loader profile. + +Explore the world you want to crack the seed and find at least 5 structures or decorators (like Monument, Temple, Mansion, Treasure, Dungeon...), in the background while you explore the world, SeedCracker will collect biomes coordinates. + +Then go on the main End island to load the pillars and the seed cracking process should start and take arround one minute. + +## Usefull command + +renderer option: `/seed render outlines (ON/OFF/XRAY)` + +seed finder option: `/seed finder category (BIOMES/ORES/OTHERS/STRUCTURES) (ON/OFF)` + +## Video Tutorial + +https://youtu.be/1ChmLi9og8Q + +## Contributors + +[KaptainWutax](https://github.com/KaptainWutax) - the mod + +[neil](https://www.youtube.com/channel/UCbM3acUrR8Ku6pjgRUNPnbQ/featured) - video tutorial + +[Nekzuris](https://github.com/Nekzuris) - readme diff --git a/gradle.properties b/gradle.properties index 107467d..fed7f06 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,12 +3,12 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://fabricmc.net/use - minecraft_version=1.14.4 - yarn_mappings=1.14.4+build.15 + minecraft_version=1.15 + yarn_mappings=1.15+build.2 loader_version=0.7.2+build.174 # Mod Properties - mod_version = 1.0.0 + mod_version = 0.0.2-alpha maven_group = kaptainwutax archives_base_name = seedcracker diff --git a/src/main/java/kaptainwutax/seedcracker/SeedCracker.java b/src/main/java/kaptainwutax/seedcracker/SeedCracker.java index 7d7037f..0805c1c 100644 --- a/src/main/java/kaptainwutax/seedcracker/SeedCracker.java +++ b/src/main/java/kaptainwutax/seedcracker/SeedCracker.java @@ -1,95 +1,39 @@ package kaptainwutax.seedcracker; -import com.google.common.collect.Lists; +import io.netty.util.internal.ConcurrentSet; import kaptainwutax.seedcracker.cracker.*; -import kaptainwutax.seedcracker.cracker.population.PopulationData; +import kaptainwutax.seedcracker.cracker.population.DecoratorData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; 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.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.MutableIntBoundingBox; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.Biomes; -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.gen.feature.Feature; -import net.minecraft.world.gen.feature.StrongholdFeature; -import net.minecraft.world.level.LevelGeneratorType; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import net.minecraft.world.level.LevelProperties; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import java.util.Random; +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 List structureSeeds = null; + public Set structureSeeds = null; public List pillarSeeds = null; private TimeMachine timeMachine = new TimeMachine(); private List structureCache = new ArrayList<>(); - private List populationCache = new ArrayList<>(); + private List decoratorCache = new ArrayList<>(); private List biomeCache = new ArrayList<>(); - @Override + @Override public void onInitialize() { RenderQueue.get().add("hand", FinderQueue.get()::renderFinders); DecoratorCache.get().initialize(); - /* - System.out.println("FETCHING SEEDS============"); - long structureSeed = 29131954246896L; - ChunkPos chunkPos = new ChunkPos(117, 23); - - for(long j = 0; j < (1L << 16); j++) { - long worldSeed = (j << 48) | structureSeed; - - if(initialize(worldSeed).contains(chunkPos)) { - System.out.println(worldSeed); - this.checkWorldSeed(worldSeed, chunkPos); - } - } - System.out.println("FETCHING SEEDS============"); - */ - - /* - System.out.println(9348141881871L ^ Rand.JAVA_LCG.multiplier); - DungeonData data = new DungeonData(new ChunkPos(18, 8), Biomes.JUNGLE, new ArrayList<>(), new ArrayList<>()); - data.test(-2418316773073950375L); - - try { - BufferedWriter writer = new BufferedWriter(new FileWriter("kaktoos14.txt")); - - for(int i = 0; i < (1 << 16); i++) { - long worldSeed = 9368770777595L | ((long)i << 48); - - BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT, - BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1]; - - if(sampler.sample(8, 8) == Biomes.DESERT) { - writer.write(worldSeed + "\n"); - } - } - - writer.flush(); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - }*/ - } - - private void checkWorldSeed(long worldSeed, ChunkPos pos) { - StrongholdFeature.Start start = new StrongholdFeature.Start(Feature.STRONGHOLD, pos.x, pos.z, Biomes.PLAINS, MutableIntBoundingBox.empty(), 0, worldSeed); } public static SeedCracker get() { @@ -97,12 +41,13 @@ public class SeedCracker implements ModInitializer { } public void clear() { + this.hashedWorldSeed = -1; this.worldSeeds = null; this.structureSeeds = null; this.pillarSeeds = null; this.structureCache.clear(); this.biomeCache.clear(); - this.populationCache.clear(); + this.decoratorCache.clear(); } public synchronized boolean onPillarData(PillarData pillarData) { @@ -138,7 +83,7 @@ public class SeedCracker implements ModInitializer { Log.warn("Looking for structure seeds with " + this.populationCache.size() + " population features."); this.pillarSeeds.forEach(pillarSeed -> { - timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.populationCache, this.structureSeeds); + timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.decoratorCache, this.structureSeeds); }); if(this.structureSeeds.size() > 0) { @@ -148,13 +93,12 @@ public class SeedCracker implements ModInitializer { } this.structureCache.clear(); - this.onPopulationData(null); + this.onDecoratorData(null); 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); + Rand rand = new Rand(0L); + return !structureData.test(structureSeed, rand); }); this.onBiomeData(null); @@ -163,11 +107,11 @@ public class SeedCracker implements ModInitializer { return added; } - public synchronized boolean onPopulationData(PopulationData populationData) { + public synchronized boolean onDecoratorData(DecoratorData decoratorData) { boolean added = false; - if(populationData != null && !this.populationCache.contains(populationData)) { - this.populationCache.add(populationData); + if(decoratorData != null && !this.decoratorCache.contains(decoratorData)) { + this.decoratorCache.add(decoratorData); added = true; } @@ -190,16 +134,33 @@ public class SeedCracker implements ModInitializer { for(int i = 0; i < this.structureSeeds.size(); i++) { Log.warn("Progress " + (i * 100.0f) / this.structureSeeds.size() + "%..."); - long structureSeed = this.structureSeeds.get(i); + for(long structureSeed: this.structureSeeds) { + for(long j = 0; j < (1L << 16); j++) { + long worldSeed = (j << 48) | structureSeed; + long hash = LevelProperties.sha256Hash(worldSeed); - for (long j = 0; j < (1L << 16); j++) { + 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; - BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT, - BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1]; + + FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed); for(BiomeData data : this.biomeCache) { - if (!data.test(worldSeed, sampler)) { + if(!data.test(fakeBiomeSource)) { goodSeed = false; break; } @@ -209,7 +170,7 @@ public class SeedCracker implements ModInitializer { this.worldSeeds.add(worldSeed); } } - } + }); if(this.worldSeeds.size() > 0) { Log.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds.")); @@ -218,16 +179,14 @@ public class SeedCracker implements ModInitializer { } } else if(this.worldSeeds != null && biomeData != null) { this.worldSeeds.removeIf(worldSeed -> { - BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT, - BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1]; - return !biomeData.test(worldSeed, sampler); + FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed); + return !biomeData.test(fakeBiomeSource); }); } else if(this.worldSeeds != null) { this.worldSeeds.removeIf(worldSeed -> { for(BiomeData data: this.biomeCache) { - BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT, - BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1]; - if(!biomeData.test(worldSeed, sampler))return true; + FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed); + if(!data.test(fakeBiomeSource))return true; } return false; @@ -237,116 +196,4 @@ public class SeedCracker implements ModInitializer { return added; } - public static void main(String[] args) throws Exception { - for(int i = 0; i < 10000; i++) { - Rand rand = new Rand(i, false); - if(rand.nextInt(700) == 0)System.out.println(i); - } - - /*Random rand = new Random(1234L); - - IntStream.range(0, 8).mapToObj((int_1x) -> { - int int_2 = rand.nextInt(16); - int int_3 = rand.nextInt(256); - int int_4 = rand.nextInt(16); - System.out.println("Created " + int_2 + ", " + int_3 + ", " + int_4); - return new BlockPos(int_2, int_3, int_4); - }).forEach(pos -> { - System.out.println("Populating " + pos); - });*/ - - /* - System.out.println(validSeed(65867021031296932L)); - - BufferedReader reader = new BufferedReader(new FileReader("run/seeds.txt")); - BufferedWriter writer = new BufferedWriter(new FileWriter("run/kaktoos14.txt")); - - while(reader.ready()) { - long seed = Long.parseLong(reader.readLine().split(Pattern.quote(" "))[0]); - seed ^= Rand.JAVA_LCG.multiplier; - seed -= 60007; - - writer.write(seed + "===========================================\n"); - - for(int i = 0; i < (1 << 16); i++) { - long worldSeed = seed | ((long)i << 48); - - BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT, - BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1]; - - if(sampler.sample(8, 8) == Biomes.DESERT) { - writer.write(worldSeed + "\n"); - } - } - - writer.flush(); - } - - writer.close();*/ - } - - private static List initialize(long worldSeed) { - BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT, - BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[0]; - - List startPositions = new ArrayList<>(); - List validBiomes = Lists.newArrayList(); - Iterator biomeIterator = Registry.BIOME.iterator(); - - while(biomeIterator.hasNext()) { - Biome biome = (Biome)biomeIterator.next(); - if(biome != null && biome.hasStructureFeature(Feature.STRONGHOLD)) { - validBiomes.add(biome); - } - } - - Random rand = new Random(worldSeed); - double randomRadian = rand.nextDouble() * Math.PI * 2.0D; - - //Actually 128, but we don't care about all of them. - for(int i = 0; i < 3; ++i) { - double double_2 = 128.0D + (rand.nextDouble() - 0.5D) * 80.0D; - int x = (int)Math.round(Math.cos(randomRadian) * double_2); - int z = (int)Math.round(Math.sin(randomRadian) * double_2); - - BlockPos locatedPos = locateBiome(sampler, (x << 4) + 8, (z << 4) + 8, 112, validBiomes, rand); - - if(locatedPos != null) { - x = locatedPos.getX() >> 4; - z = locatedPos.getZ() >> 4; - } - - startPositions.add(new ChunkPos(x, z)); - randomRadian += (Math.PI * 2.0D) / 3.0d; - } - - return startPositions; - } - - public static BlockPos locateBiome(BiomeLayerSampler sampler, int x, int z, int size, List validBiomes, Random rand) { - int int_4 = x - size >> 2; - int int_5 = z - size >> 2; - int int_6 = x + size >> 2; - int int_7 = z + size >> 2; - int int_8 = int_6 - int_4 + 1; - int int_9 = int_7 - int_5 + 1; - Biome[] biomeSample = sampler.sample(int_4, int_5, int_8, int_9); - BlockPos pos = null; - int int_10 = 0; - - for(int i = 0; i < int_8 * int_9; ++i) { - int int_12 = int_4 + i % int_8 << 2; - int int_13 = int_5 + i / int_8 << 2; - if (validBiomes.contains(biomeSample[i])) { - if(pos == null || rand.nextInt(int_10 + 1) == 0) { - pos = new BlockPos(int_12, 0, int_13); - } - - ++int_10; - } - } - - return pos; - } - } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java b/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java index 268f66a..97231fd 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/BiomeData.java @@ -3,7 +3,7 @@ package kaptainwutax.seedcracker.cracker; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.layer.BiomeLayerSampler; +import net.minecraft.world.biome.source.VoronoiBiomeAccessType; public class BiomeData { @@ -25,8 +25,20 @@ public class BiomeData { this(x, z, Registry.BIOME.get(biomeId)); } - public boolean test(long worldSeed, BiomeLayerSampler sampler) { - return sampler.sample(this.x, this.z) == this.biome; + public boolean test(FakeBiomeSource source) { + return VoronoiBiomeAccessType.INSTANCE.getBiome(source.getHashedSeed(), this.x,0, this.z, source) == this.biome; + } + + public int getX() { + return this.x; + } + + public int getZ() { + return this.z; + } + + public Biome getBiome() { + return this.biome; } @Override diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/DecoratorCache.java b/src/main/java/kaptainwutax/seedcracker/cracker/DecoratorCache.java index dc05b5e..261bfec 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/DecoratorCache.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/DecoratorCache.java @@ -39,7 +39,7 @@ public class DecoratorCache { } private void initializeBiomeStep(Biome biome, GenerationStep.Feature genStep) { - List> features = biome.getFeaturesForStep(genStep); + List> features = biome.getFeaturesForStep(genStep); for(int i = 0; i < features.size(); i++) { FeatureConfig config = features.get(i).config; diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/FakeBiomeSource.java b/src/main/java/kaptainwutax/seedcracker/cracker/FakeBiomeSource.java new file mode 100644 index 0000000..cf7968c --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/FakeBiomeSource.java @@ -0,0 +1,49 @@ +package kaptainwutax.seedcracker.cracker; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biomes; +import net.minecraft.world.biome.layer.BiomeLayers; +import net.minecraft.world.biome.source.BiomeLayerSampler; +import net.minecraft.world.biome.source.BiomeSource; +import net.minecraft.world.gen.chunk.OverworldChunkGeneratorConfig; +import net.minecraft.world.level.LevelGeneratorType; +import net.minecraft.world.level.LevelProperties; + +import java.util.Set; + +public class FakeBiomeSource extends BiomeSource { + + public static final OverworldChunkGeneratorConfig CHUNK_GEN_CONFIG = new OverworldChunkGeneratorConfig(); + + private static final Set BIOMES; + private final BiomeLayerSampler biomeSampler; + + private long seed; + private long hashedSeed; + + public FakeBiomeSource(long worldSeed) { + super(BIOMES); + this.seed = worldSeed; + this.hashedSeed = LevelProperties.sha256Hash(worldSeed); + this.biomeSampler = BiomeLayers.build(this.seed, LevelGeneratorType.DEFAULT, CHUNK_GEN_CONFIG); + } + + @Override + public Biome getBiomeForNoiseGen(int biomeX, int biomeY, int biomeZ) { + return this.biomeSampler.sample(biomeX, biomeZ); + } + + public long getSeed() { + return this.seed; + } + + public long getHashedSeed() { + return this.hashedSeed; + } + + 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); + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java b/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java index acba647..ba1c7d9 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/PillarData.java @@ -7,39 +7,39 @@ import java.util.Random; public class PillarData { - private List heights; + private List heights; - public PillarData(List heights) { - this.heights = heights; - } + public PillarData(List heights) { + this.heights = heights; + } - public List getPillarSeeds() { - List result = new ArrayList<>(); + 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); - } + for(int pillarSeed = 0; pillarSeed < (1 << 16); pillarSeed++) { + List h = this.getPillarHeights(pillarSeed); + if(h.equals(this.heights)) result.add(pillarSeed); + } - return result; - } + return result; + } - public List getPillarHeights(int spikeSeed) { - List indices = new ArrayList<>(); + public List getPillarHeights(int spikeSeed) { + List indices = new ArrayList<>(); - for (int i = 0; i < 10; i++) { - indices.add(i); - } + for(int i = 0; i < 10; i++) { + indices.add(i); + } - Collections.shuffle(indices, new Random(spikeSeed)); + Collections.shuffle(indices, new Random(spikeSeed)); - List heights = new ArrayList<>(); + List heights = new ArrayList<>(); - for (Integer index: indices) { - heights.add(76 + index * 3); - } + for(Integer index : indices) { + heights.add(76 + index * 3); + } - return heights; - } + return heights; + } } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/StructureData.java b/src/main/java/kaptainwutax/seedcracker/cracker/StructureData.java deleted file mode 100644 index 6338445..0000000 --- a/src/main/java/kaptainwutax/seedcracker/cracker/StructureData.java +++ /dev/null @@ -1,172 +0,0 @@ -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.build(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 Feature getFeature() { - return this.feature; - } - - public boolean test(ChunkRandom rand) { - return this.feature.test(rand, this.offsetX, this.offsetZ); - } - - @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.feature == this.feature; - } - - return false; - } - - public abstract static class Feature { - public final int salt; - public final int distance; - - public Feature(int salt, int distance) { - this.salt = salt; - this.distance = distance; - } - - public void build(StructureData data, ChunkPos chunkPos) { - int chunkX = chunkPos.x; - int chunkZ = chunkPos.z; - - chunkX = chunkX < 0 ? chunkX - this.distance + 1 : chunkX; - chunkZ = chunkZ < 0 ? chunkZ - this.distance + 1 : chunkZ; - - //Pick out in which region the chunk is. - int regionX = (chunkX / this.distance); - int regionZ = (chunkZ / this.distance); - - data.regionX = regionX; - data.regionZ = regionZ; - - regionX *= this.distance; - regionZ *= this.distance; - - data.offsetX = chunkPos.x - regionX; - data.offsetZ = chunkPos.z - regionZ; - } - - 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) { - return rand.nextInt(24) == x && rand.nextInt(24) == z; - } - }; - - public static final Feature IGLOO = new Feature(14357618, 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 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 OCEAN_RUIN = new Feature(14357621, 16) { - @Override - public boolean test(ChunkRandom rand, int x, int z) { - return rand.nextInt(8) == x && rand.nextInt(8) == z; - } - }; - - public static final Feature SHIPWRECK = new Feature(165745295, 16) { - @Override - public boolean test(ChunkRandom rand, int x, int z) { - return rand.nextInt(8) == x && rand.nextInt(8) == z; - } - }; - - public static final Feature PILLAGER_OUTPOST = new Feature(165745296, 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; - } - }; - - public static final Feature BURIED_TREASURE = new Feature(10387320, 1) { - @Override - public boolean test(ChunkRandom rand, int x, int z) { - return rand.nextFloat() < 0.1f; - } - }; - - public static final Feature WOODLAND_MANSION = new Feature(10387319, 80) { - @Override - public boolean test(ChunkRandom rand, int x, int z) { - return (rand.nextInt(60) + rand.nextInt(60)) / 2 == x - && (rand.nextInt(60) + rand.nextInt(60)) / 2 == z; - } - }; - -} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java b/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java index d7d2d1c..14beb04 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/TimeMachine.java @@ -5,46 +5,82 @@ import kaptainwutax.seedcracker.cracker.population.PopulationData; import kaptainwutax.seedcracker.util.Log; import kaptainwutax.seedcracker.util.Rand; import kaptainwutax.seedcracker.util.math.LCG; -import net.minecraft.world.gen.ChunkRandom; +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 buildStructureSeeds(int pillarSeed, List structureDataList, List populationDataList, List structureSeeds) { - ChunkRandom chunkRandom = new ChunkRandom(); + public List bruteforceRegion(int pillarSeed, int region, long size, List structureDataList, List decoratorDataList) { + List result = new ArrayList<>(); + Rand rand = new Rand(0L); for(long i = 0; i < (1L << 32); i++) { if((i & ((1L << 28) - 1)) == 0) { Log.warn("Progress " + (i * 100.0f) / (1L << 32) + "%..."); } + for(long i = start; i < end; i++) { long structureSeed = this.timeMachine(i, pillarSeed); boolean goodSeed = true; for(StructureData structureData: structureDataList) { if(!goodSeed)break; - chunkRandom.setStructureSeed(structureSeed, structureData.getRegionX(), - structureData.getRegionZ(), structureData.getSalt()); - if(!structureData.test(chunkRandom))goodSeed = false; + if(!structureData.test(structureSeed, rand))goodSeed = false; } - for(PopulationData populationData: populationDataList) { + for(DecoratorData decoratorData : decoratorDataList) { if(!goodSeed)break; - if(!populationData.test(structureSeed))goodSeed = false; + if(!decoratorData.test(structureSeed))goodSeed = false; } if(goodSeed) { - structureSeeds.add(structureSeed); + 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; } @@ -59,4 +95,8 @@ public class TimeMachine { 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 new file mode 100644 index 0000000..55c73e9 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/DecoratorData.java @@ -0,0 +1,56 @@ +package kaptainwutax.seedcracker.cracker.population; + +import kaptainwutax.seedcracker.cracker.DecoratorCache; +import kaptainwutax.seedcracker.util.Rand; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.decorator.Decorator; + +public abstract class DecoratorData { + + private final ChunkPos chunkPos; + private final Decorator decorator; + private final Biome biome; + + public DecoratorData(ChunkPos chunkPos, Decorator decorator, Biome biome) { + this.chunkPos = chunkPos; + this.decorator = decorator; + this.biome = biome; + } + + public final boolean test(long structureSeed) { + long decoratorSeed = this.getPopulationSeed(structureSeed, this.chunkPos.x << 4, this.chunkPos.z << 4); + int salt = DecoratorCache.get().getSalt(this.biome, this.decorator, true); + + if(salt == DecoratorCache.INVALID) { + return false; + } + + decoratorSeed += salt; + decoratorSeed ^= Rand.JAVA_LCG.multiplier; + decoratorSeed &= Rand.JAVA_LCG.modulo - 1; + return this.testDecorator(new Rand(decoratorSeed, false)); + } + + 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 + public boolean equals(Object obj) { + if(obj == this)return true; + + if(obj instanceof DecoratorData) { + DecoratorData decoratorData = ((DecoratorData)obj); + return decoratorData.chunkPos.equals(this.chunkPos) && decoratorData.decorator == this.decorator; + } + + return false; + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java index 6aad60b..621fcc3 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/DungeonData.java @@ -9,7 +9,7 @@ import net.minecraft.world.gen.decorator.Decorator; import java.util.List; -public class DungeonData extends PopulationData { +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); @@ -28,33 +28,26 @@ public class DungeonData extends PopulationData { } @Override - public boolean testDecorator(long decoratorSeed) { + public boolean testDecorator(Rand rand) { if(this.starts.isEmpty())return true; //TODO: This currently only supports 1 dungeon per chunk. BlockPos start = this.starts.get(0); - long currentSeed = decoratorSeed; - boolean valid = false; - for(int i = 0; i < 8; i++) { - currentSeed = i == 0 ? Y_START_SKIP.nextSeed(currentSeed) : Y_SKIP.nextSeed(currentSeed); + int x = rand.nextInt(16); + int z = rand.nextInt(16); + int y = rand.nextInt(256); - if(currentSeed >> 40 == start.getY()) { - valid = true; - break; + if(y == start.getY() && x == start.getX() && z == start.getZ()) { + return true; } + + rand.nextInt(2); + rand.nextInt(2); } - if(!valid)return false; - - int x = (int)(REVERSE_SKIP.nextSeed(currentSeed) >> 44); - if(x != start.getX())return false; - - int z = (int)(Rand.JAVA_LCG.nextSeed(currentSeed) >> 44); - if(z != start.getZ())return false; - - return true; + return false; } } diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java index 68236f5..947594e 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/EmeraldOreData.java @@ -10,7 +10,7 @@ import net.minecraft.world.gen.decorator.Decorator; import java.util.List; import java.util.stream.Collectors; -public class EmeraldOreData extends PopulationData { +public class EmeraldOreData extends DecoratorData { public static final LCG[] SKIP = { Rand.JAVA_LCG.combine(0), @@ -30,19 +30,18 @@ public class EmeraldOreData extends PopulationData { } @Override - public boolean testDecorator(long decoratorSeed) { + public boolean testDecorator(Rand rand) { if(this.starts.isEmpty())return true; //TODO: This currently only supports 1 emerald per chunk. BlockPos start = this.starts.get(0); - Rand rand = new Rand(decoratorSeed, false); int b = rand.nextInt(6); for(int i = 0; i < b + 3; i++) { int x = rand.nextInt(16); - int y = rand.nextInt(28) + 4; int z = rand.nextInt(16); + int y = rand.nextInt(28) + 4; if(y == start.getY() && x == start.getX() && z == start.getZ()) { return true; diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java index 896bbe7..ef9d24e 100644 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java +++ b/src/main/java/kaptainwutax/seedcracker/cracker/population/EndGatewayData.java @@ -6,7 +6,7 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.Biome; import net.minecraft.world.gen.decorator.Decorator; -public class EndGatewayData extends PopulationData { +public class EndGatewayData extends DecoratorData { private int xOffset; private int zOffset; @@ -20,9 +20,7 @@ public class EndGatewayData extends PopulationData { } @Override - public boolean testDecorator(long decoratorSeed) { - Rand rand = new Rand(decoratorSeed, false); - + public boolean testDecorator(Rand rand) { if(rand.nextInt(700) != 0)return false; if(rand.nextInt(16) != this.xOffset)return false; if(rand.nextInt(16) != this.zOffset)return false; diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/population/PopulationData.java b/src/main/java/kaptainwutax/seedcracker/cracker/population/PopulationData.java deleted file mode 100644 index 55b3a01..0000000 --- a/src/main/java/kaptainwutax/seedcracker/cracker/population/PopulationData.java +++ /dev/null @@ -1,104 +0,0 @@ -package kaptainwutax.seedcracker.cracker.population; - -import kaptainwutax.seedcracker.cracker.DecoratorCache; -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.ChunkRandom; -import net.minecraft.world.gen.GenerationStep; -import net.minecraft.world.gen.decorator.ConfiguredDecorator; -import net.minecraft.world.gen.decorator.Decorator; -import net.minecraft.world.gen.feature.ConfiguredFeature; -import net.minecraft.world.gen.feature.DecoratedFeatureConfig; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public abstract class PopulationData { - - private final ChunkPos chunkPos; - private final Decorator decorator; - private final Biome biome; - - public PopulationData(ChunkPos chunkPos, Decorator decorator, Biome biome) { - this.chunkPos = chunkPos; - this.decorator = decorator; - this.biome = biome; - } - - public final boolean test(long structureSeed) { - long decoratorSeed = this.getPopulationSeed(structureSeed, this.chunkPos.x << 4, this.chunkPos.z << 4); - int salt = DecoratorCache.get().getSalt(this.biome, this.decorator, true); - - if(salt == DecoratorCache.INVALID) { - return false; - } - - decoratorSeed += salt; - decoratorSeed ^= Rand.JAVA_LCG.multiplier; - decoratorSeed &= Rand.JAVA_LCG.modulo - 1; - return this.testDecorator(decoratorSeed); - } - - 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(long decoratorSeed); - - @Override - public boolean equals(Object obj) { - if(obj == this)return true; - - if(obj instanceof PopulationData) { - PopulationData populationData = ((PopulationData)obj); - return populationData.chunkPos.equals(this.chunkPos) && populationData.decorator == this.decorator; - } - - return false; - } - - - public abstract static class Feature { - private Map CACHE = new HashMap<>(); - - private GenerationStep.Feature genStep; - private Decorator decorator; - - public Feature(GenerationStep.Feature genStep, Decorator decorator) { - this.genStep = genStep; - this.decorator = decorator; - } - - public ChunkRandom buildRand(long worldSeed, Biome biome, ChunkPos chunkPos) { - if(CACHE.containsKey(biome)) { - return new ChunkRandom(CACHE.get(biome)); - } - - List> features = biome.getFeaturesForStep(this.genStep); - - for(int i = 0; i < features.size(); i++) { - ConfiguredFeature feature = features.get(i); - if(!(feature.config instanceof DecoratedFeatureConfig))continue; - ConfiguredDecorator currentDecorator = ((DecoratedFeatureConfig)feature.config).decorator; - - if(currentDecorator.decorator == this.decorator) { - BlockPos pos = new BlockPos(chunkPos.getStartX(), 0, chunkPos.getStartZ()); - ChunkRandom chunkRandom = new ChunkRandom(); - long populationSeed = chunkRandom.setSeed(worldSeed, pos.getX(), pos.getZ()); - long seed = chunkRandom.setFeatureSeed(populationSeed, i, this.genStep.ordinal()); - CACHE.put(biome, seed ^ Rand.JAVA_LCG.multiplier); - return chunkRandom; - } - } - - return null; - } - } - -} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureData.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureData.java new file mode 100644 index 0000000..219a96e --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureData.java @@ -0,0 +1,42 @@ +package kaptainwutax.seedcracker.cracker.structure; + +import kaptainwutax.seedcracker.cracker.structure.type.FeatureType; +import kaptainwutax.seedcracker.util.Seeds; +import kaptainwutax.seedcracker.util.Rand; +import net.minecraft.util.math.ChunkPos; + +public class StructureData { + + public int chunkX; + public int chunkZ; + public int regionX; + public int regionZ; + public int offsetX; + public int offsetZ; + private final int salt; + private FeatureType featureType; + + public StructureData(ChunkPos chunkPos, FeatureType featureType) { + this.featureType = featureType; + this.salt = this.featureType.salt; + this.featureType.build(this, chunkPos); + } + + public boolean test(long structureSeed, Rand rand) { + Seeds.setRegionSeed(rand, structureSeed, this.regionX, this.regionZ, this.salt); + return this.featureType.test(rand, this, structureSeed); + } + + @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 false; + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureFeatures.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureFeatures.java new file mode 100644 index 0000000..c7f58ab --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/StructureFeatures.java @@ -0,0 +1,62 @@ +package kaptainwutax.seedcracker.cracker.structure; + +import kaptainwutax.seedcracker.cracker.structure.type.AbstractTempleType; +import kaptainwutax.seedcracker.cracker.structure.type.FeatureType; +import kaptainwutax.seedcracker.cracker.structure.type.RarityType; +import kaptainwutax.seedcracker.cracker.structure.type.TriangularType; +import kaptainwutax.seedcracker.util.Rand; +import kaptainwutax.seedcracker.util.Seeds; + +public class StructureFeatures { + + public static final FeatureType DESERT_PYRAMID = new AbstractTempleType(14357617, 32, 24); + + public static final FeatureType IGLOO = new AbstractTempleType(14357618, 32, 24); + + public static final FeatureType JUNGLE_TEMPLE = new AbstractTempleType(14357619, 32, 24); + + public static final FeatureType SWAMP_HUT = new AbstractTempleType(14357620, 32, 24); + + public static final FeatureType OCEAN_RUIN = new AbstractTempleType(14357621, 16, 8); + + public static final FeatureType SHIPWRECK = new AbstractTempleType(165745295, 16, 8); + + public static final FeatureType PILLAGER_OUTPOST = new AbstractTempleType(165745296, 32, 24) { + @Override + public boolean test(Rand rand, StructureData data, long structureSeed) { + if(!super.test(rand, data, structureSeed))return false; + Seeds.setWeakSeed(rand, structureSeed, data.chunkX, data.chunkZ); + return rand.nextInt(5) == 0; + } + }; + + public static final FeatureType VILLAGE = new AbstractTempleType(10387312, 32, 24); + + public static final FeatureType END_CITY = new TriangularType(10387313, 20, 9); + + public static final FeatureType OCEAN_MONUMENT = new TriangularType(10387313, 32, 27); + + public static final FeatureType WOODLAND_MANSION = new TriangularType(10387319, 80, 60); + + public static final FeatureType BURIED_TREASURE = new RarityType(10387320, 1, 0.01F); + + public static final FeatureType NETHER_FORTRESS = new FeatureType(-1, 1) { + @Override + public boolean test(Rand rand, StructureData data, long structureSeed) { + Seeds.setWeakSeed(rand, structureSeed, data.chunkX, data.chunkZ); + + return rand.nextInt(3) == 0 + && data.chunkX == ((data.chunkX >> 4) << 4) + 4 + rand.nextInt(8) + && data.chunkZ == ((data.chunkZ >> 4) << 4) + 4 + rand.nextInt(8); + } + }; + + public static final FeatureType MINESHAFT = new FeatureType(-1, 1) { + @Override + public boolean test(Rand rand, StructureData data, long structureSeed) { + Seeds.setStructureStartSeed(rand, structureSeed, data.chunkX, data.chunkZ); + return rand.nextDouble() < 0.004D; + } + }; + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/AbstractTempleType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/AbstractTempleType.java new file mode 100644 index 0000000..76b842f --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/AbstractTempleType.java @@ -0,0 +1,20 @@ +package kaptainwutax.seedcracker.cracker.structure.type; + +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.util.Rand; + +public class AbstractTempleType extends FeatureType { + + protected final int offset; + + public AbstractTempleType(int salt, int distance, int offset) { + super(salt, distance); + this.offset = offset; + } + + @Override + public boolean test(Rand rand, StructureData data, long structureSeed) { + return rand.nextInt(this.offset) == data.offsetX && rand.nextInt(this.offset) == data.offsetZ; + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/FeatureType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/FeatureType.java new file mode 100644 index 0000000..1f0057a --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/FeatureType.java @@ -0,0 +1,43 @@ +package kaptainwutax.seedcracker.cracker.structure.type; + +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.util.Rand; +import net.minecraft.util.math.ChunkPos; + +public abstract class FeatureType { + + public final int salt; + public final int distance; + + public FeatureType(int salt, int distance) { + this.salt = salt; + this.distance = distance; + } + + public void build(T data, ChunkPos chunkPos) { + int chunkX = chunkPos.x; + int chunkZ = chunkPos.z; + + data.chunkX = chunkX; + data.chunkZ = chunkZ; + + chunkX = chunkX < 0 ? chunkX - this.distance + 1 : chunkX; + chunkZ = chunkZ < 0 ? chunkZ - this.distance + 1 : chunkZ; + + //Pick out in which region the chunk is. + int regionX = (chunkX / this.distance); + int regionZ = (chunkZ / this.distance); + + data.regionX = regionX; + data.regionZ = regionZ; + + regionX *= this.distance; + regionZ *= this.distance; + + data.offsetX = chunkPos.x - regionX; + data.offsetZ = chunkPos.z - regionZ; + } + + public abstract boolean test(Rand rand, T data, long structureSeed); + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/RarityType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/RarityType.java new file mode 100644 index 0000000..bcf4db0 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/RarityType.java @@ -0,0 +1,20 @@ +package kaptainwutax.seedcracker.cracker.structure.type; + +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.util.Rand; + +public class RarityType extends FeatureType { + + private float rarity; + + public RarityType(int salt, int distance, float rarity) { + super(salt, distance); + this.rarity = rarity; + } + + @Override + public boolean test(Rand rand, StructureData data, long structureSeed) { + return rand.nextFloat() < this.rarity; + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/TriangularType.java b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/TriangularType.java new file mode 100644 index 0000000..b7467d5 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/cracker/structure/type/TriangularType.java @@ -0,0 +1,22 @@ +package kaptainwutax.seedcracker.cracker.structure.type; + + +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.util.Rand; + +public class TriangularType extends FeatureType { + + protected final int peak; + + public TriangularType(int salt, int distance, int peak) { + super(salt, distance); + this.peak = peak; + } + + @Override + public boolean test(Rand rand, StructureData data, long structureSeed) { + return (rand.nextInt(this.peak) + rand.nextInt(this.peak)) / 2 == data.offsetX + && (rand.nextInt(this.peak) + rand.nextInt(this.peak)) / 2 == data.offsetZ; + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/feature/decoration/DecorationFeature.java b/src/main/java/kaptainwutax/seedcracker/feature/decoration/DecorationFeature.java deleted file mode 100644 index 811406e..0000000 --- a/src/main/java/kaptainwutax/seedcracker/feature/decoration/DecorationFeature.java +++ /dev/null @@ -1,23 +0,0 @@ -package kaptainwutax.seedcracker.feature.decoration; - -import net.minecraft.block.Block; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public abstract class DecorationFeature { - - protected World world; - protected BlockPos pos; - - public DecorationFeature(World world, BlockPos pos) { - this.world = world; - this.pos = pos; - } - - public abstract void reverseSeed(); - - public Block getBlockAt(BlockPos pos) { - return this.world.getBlockState(pos).getBlock(); - } - -} diff --git a/src/main/java/kaptainwutax/seedcracker/feature/decoration/DungeonFeature.java b/src/main/java/kaptainwutax/seedcracker/feature/decoration/DungeonFeature.java deleted file mode 100644 index 6b33bf6..0000000 --- a/src/main/java/kaptainwutax/seedcracker/feature/decoration/DungeonFeature.java +++ /dev/null @@ -1,91 +0,0 @@ -package kaptainwutax.seedcracker.feature.decoration; - -import kaptainwutax.seedcracker.util.Rand; -import net.minecraft.block.Block; -import net.minecraft.block.Blocks; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3i; -import net.minecraft.world.World; - -import java.util.ArrayList; -import java.util.List; - -public class DungeonFeature extends DecorationFeature { - - private static int MOSSY_COBBLESTONE_CALL = 0; - private static int COBBLESTONE_CALL = 1; - - public DungeonFeature(World world, BlockPos pos) { - super(world, pos); - } - - @Override - public void reverseSeed() { - BlockPos decoratorPos = this.getLocalPos(this.pos); - Vec3i dungeonSize = this.getDungeonSize(this.pos); - - List floorCalls = new ArrayList<>(); - - for(int xo = -dungeonSize.getX(); xo <= dungeonSize.getX(); xo++) { - for(int zo = -dungeonSize.getZ(); zo <= dungeonSize.getZ(); zo++) { - Block block = this.world.getBlockState(this.pos.add(xo, -1, zo)).getBlock(); - - if(block == Blocks.MOSSY_COBBLESTONE) { - floorCalls.add(MOSSY_COBBLESTONE_CALL); - } else if(block == Blocks.COBBLESTONE) { - floorCalls.add(COBBLESTONE_CALL); - } - } - } - - List dungeonSeeds = this.getDungeonSeeds(dungeonSize, floorCalls); - List decoratorSeeds = new ArrayList<>(); - - for(long dungeonSeed: dungeonSeeds) { - long decoratorSeed = Rand.JAVA_LCG.combine(-3).nextSeed(dungeonSeed); - Rand rand = new Rand(decoratorSeed, false); - if(rand.nextInt(16) != decoratorPos.getX())continue; - if(rand.nextInt(256) != decoratorPos.getY())continue; - if(rand.nextInt(16) != decoratorPos.getZ())continue; - decoratorSeeds.add(decoratorSeed); - } - - decoratorSeeds.forEach(System.out::println); - } - - public BlockPos getLocalPos(BlockPos pos) { - return new BlockPos(pos.getX() & 15, pos.getY(), pos.getZ() & 15); - } - - public Vec3i getDungeonSize(BlockPos spawnerPos) { - for(int xo = 4; xo >= 3; xo--) { - for(int zo = 4; zo >= 3; zo--) { - Block block = this.getBlockAt(spawnerPos.add(xo, -1, zo)); - if(block != Blocks.MOSSY_COBBLESTONE)continue; - if(block != Blocks.COBBLESTONE)continue; - return new Vec3i(xo, 0, zo); - } - } - - return Vec3i.ZERO; - } - - public List getDungeonSeeds(Vec3i dungeonSize, List floorCalls) { - List floorSeeds = new ArrayList<>(); - - //TODO: Lattice magic to find floorSeeds from floorCalls. - - List dungeonSeeds = new ArrayList<>(); - - for(long floorSeed: floorSeeds) { - long dungeonSeed = Rand.JAVA_LCG.combine(-2).nextSeed(floorSeed); - Rand rand = new Rand(dungeonSeed, false); - if(rand.nextInt(2) + 3 != dungeonSize.getX())continue; - if(rand.nextInt(2) + 3 != dungeonSize.getZ())continue; - dungeonSeeds.add(dungeonSeed); - } - - return dungeonSeeds; - } - -} diff --git a/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java index 34eace5..d92abe1 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/BiomeFinder.java @@ -9,6 +9,7 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.world.Heightmap; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biomes; import net.minecraft.world.dimension.DimensionType; import java.util.ArrayList; @@ -29,6 +30,11 @@ public class BiomeFinder extends Finder { BlockPos blockPos = this.chunkPos.getCenterBlockPos().add(x, 0, z); Biome biome = this.world.getBiome(blockPos); + //TODO: Fix this multi-threading issue. + if(biome == Biomes.THE_VOID) { + continue; + } + if(SeedCracker.get().onBiomeData(new BiomeData(blockPos.getX(), blockPos.getZ(), biome))) { blockPos = this.world.getTopPosition(Heightmap.Type.WORLD_SURFACE, blockPos).down(); result.add(blockPos); diff --git a/src/main/java/kaptainwutax/seedcracker/finder/BlockFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/BlockFinder.java index 280e459..4d5f351 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/BlockFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/BlockFinder.java @@ -17,7 +17,7 @@ public abstract class BlockFinder extends Finder { public BlockFinder(World world, ChunkPos chunkPos, Block block) { super(world, chunkPos); - this.targetBlockStates.addAll(block.getStateFactory().getStates()); + this.targetBlockStates.addAll(block.getStateManager().getStates()); } public BlockFinder(World world, ChunkPos chunkPos, BlockState... blockStates) { diff --git a/src/main/java/kaptainwutax/seedcracker/finder/DefaultFinderConfig.java b/src/main/java/kaptainwutax/seedcracker/finder/DefaultFinderConfig.java index 5ea5391..865411a 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/DefaultFinderConfig.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/DefaultFinderConfig.java @@ -3,7 +3,6 @@ package kaptainwutax.seedcracker.finder; public class DefaultFinderConfig extends FinderConfig { public DefaultFinderConfig() { - super(); this.typeStates.put(Type.DIAMOND_ORE, false); this.typeStates.put(Type.INFESTED_STONE_ORE, false); this.typeStates.put(Type.IGLOO, false); diff --git a/src/main/java/kaptainwutax/seedcracker/finder/Finder.java b/src/main/java/kaptainwutax/seedcracker/finder/Finder.java index 09e9946..8b2cbd3 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/Finder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/Finder.java @@ -55,16 +55,17 @@ public abstract class Finder { DimensionType playerDim = mc.player.world.dimension.getType(); if(finderDim != playerDim)return false; - Vec3d playerPos = mc.player.getPos(); - - double distance = playerPos.squaredDistanceTo( - this.chunkPos.x * 16, - playerPos.y, - this.chunkPos.z * 16 - ); int renderDistance = mc.options.viewDistance * 16 + 16; - return distance <= renderDistance * renderDistance + 32; + Vec3d playerPos = mc.player.getPos(); + + for(Renderer renderer: this.renderers) { + BlockPos pos = renderer.getPos(); + double distance = playerPos.squaredDistanceTo(pos.getX(), playerPos.y, pos.getZ()); + if(distance <= renderDistance * renderDistance + 32)return true; + } + + return false; } public void render() { diff --git a/src/main/java/kaptainwutax/seedcracker/finder/FinderConfig.java b/src/main/java/kaptainwutax/seedcracker/finder/FinderConfig.java index c00650c..d69a16a 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/FinderConfig.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/FinderConfig.java @@ -75,6 +75,7 @@ public class FinderConfig { MONUMENT(OceanMonumentFinder::create, Category.STRUCTURES), SWAMP_HUT(SwampHutFinder::create, Category.STRUCTURES), MANSION(MansionFinder::create, Category.STRUCTURES), + SHIPWRECK(ShipwreckFinder::create, Category.STRUCTURES), END_PILLARS(EndPillarsFinder::create, Category.OTHERS), END_GATEWAY(EndGatewayFinder::create, Category.OTHERS), diff --git a/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java b/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java index 882332a..bdb31cb 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/FinderQueue.java @@ -1,6 +1,8 @@ package kaptainwutax.seedcracker.finder; import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.World; @@ -40,9 +42,12 @@ public class FinderQueue { }); } - public void renderFinders() { + public void renderFinders(MatrixStack matrixStack) { if(this.renderType == RenderType.OFF)return; + RenderSystem.pushMatrix(); + RenderSystem.multMatrix(matrixStack.peek().getModel()); + GlStateManager.disableTexture(); //Makes it render through blocks. @@ -56,11 +61,7 @@ public class FinderQueue { } }); - GlStateManager.enableTexture(); - - if(this.renderType == RenderType.XRAY) { - GlStateManager.enableDepthTest(); - } + RenderSystem.popMatrix(); } public void clear() { diff --git a/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java index 12b0c9b..3287d91 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/DungeonFinder.java @@ -69,7 +69,7 @@ public class DungeonFinder extends BlockFinder { .map(pos -> this.getFloorCalls(this.getDungeonSize(pos), pos)).collect(Collectors.toList()); result.forEach(pos -> { - if(SeedCracker.get().onPopulationData(new DungeonData(this.chunkPos, biome, starts, floorCallsList))) { + if(SeedCracker.get().onDecoratorData(new DungeonData(this.chunkPos, biome, starts, floorCallsList))) { this.renderers.add(new Cube(pos, 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 53dfafc..497806f 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/EndGatewayFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/EndGatewayFinder.java @@ -48,7 +48,7 @@ public class EndGatewayFinder extends BlockFinder { if(height >= 3 && height <= 9) { newResult.add(pos); - if(SeedCracker.get().onPopulationData(new EndGatewayData(this.chunkPos, biome, pos, height))) { + if(SeedCracker.get().onDecoratorData(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/ore/EmeraldOreFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/population/ore/EmeraldOreFinder.java index 16eb421..bc876bf 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/population/ore/EmeraldOreFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/population/ore/EmeraldOreFinder.java @@ -21,6 +21,8 @@ import java.util.List; public class EmeraldOreFinder extends BlockFinder { protected static List SEARCH_POSITIONS = Finder.buildSearchPositions(Finder.CHUNK_POSITIONS, pos -> { + if(pos.getY() < 4)return true; + if(pos.getY() > 28 + 4)return true; return false; }); @@ -39,7 +41,7 @@ public class EmeraldOreFinder extends BlockFinder { List result = super.findInChunk(); - if(!result.isEmpty() && SeedCracker.get().onPopulationData(new EmeraldOreData(this.chunkPos, biome, result))) { + if(!result.isEmpty() && SeedCracker.get().onDecoratorData(new EmeraldOreData(this.chunkPos, biome, result))) { result.forEach(pos -> { this.renderers.add(new Cube(pos, 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 270a9d4..8969a26 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/BuriedTreasureFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/BuriedTreasureFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.BlockFinder; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cube; @@ -26,7 +27,7 @@ public class BuriedTreasureFinder extends BlockFinder { int localX = pos.getX() & 15; int localZ = pos.getZ() & 15; if(localX != 9 || localZ != 9)return true; - + if(pos.getY() > 90)return true; return false; }); @@ -55,28 +56,23 @@ public class BuriedTreasureFinder extends BlockFinder { @Override public List findInChunk() { - //Gets all the positions with a chest in the chunk. + Biome biome = world.getBiome(this.chunkPos.getCenterBlockPos().add(9, 0, 9)); + if(!biome.hasStructureFeature(Feature.BURIED_TREASURE))return new ArrayList<>(); + List result = super.findInChunk(); result.removeIf(pos -> { - //Chest can't be waterlogged! BlockState chest = world.getBlockState(pos); if(chest.get(ChestBlock.WATERLOGGED))return true; - //Only so many blocks can hold a treasure chest. BlockState chestHolder = world.getBlockState(pos.down()); if(!CHEST_HOLDERS.contains(chestHolder))return true; - //Check if the biome contains the buried treasure feature. - Biome biome = world.getBiome(pos); - if(!biome.hasStructureFeature(Feature.BURIED_TREASURE))return true; - - //Damn that chest be lucky! return false; }); result.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.BURIED_TREASURE))) { + if(SeedCracker.get().onStructureData(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 31283d7..36bdc0e 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/DesertTempleFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/DesertTempleFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cuboid; import net.minecraft.block.BlockState; @@ -35,7 +36,7 @@ public class DesertTempleFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if( SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.DESERT_PYRAMID))) { + if( SeedCracker.get().onStructureData(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 04702d4..487146f 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/EndCityFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/EndCityFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cube; import kaptainwutax.seedcracker.render.Cuboid; @@ -85,7 +86,7 @@ public class EndCityFinder extends Finder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.END_CITY))) { + if(SeedCracker.get().onStructureData(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 3ee0986..4fa937d 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/IglooFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/IglooFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cube; import kaptainwutax.seedcracker.render.Cuboid; @@ -44,7 +45,7 @@ public class IglooFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.IGLOO))) { + if(SeedCracker.get().onStructureData(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 19d2be6..96be497 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/JungleTempleFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/JungleTempleFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cuboid; import net.minecraft.block.*; @@ -35,7 +36,7 @@ public class JungleTempleFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.JUNGLE_TEMPLE))) { + if(SeedCracker.get().onStructureData(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 e51b59f..efef387 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/MansionFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/MansionFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cube; import kaptainwutax.seedcracker.render.Cuboid; @@ -13,7 +14,9 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.feature.Feature; import java.util.ArrayList; import java.util.HashMap; @@ -23,7 +26,6 @@ import java.util.Map; public class MansionFinder extends Finder { protected static List SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { - if(pos.getY() != 64)return true; if((pos.getX() & 15) != 0)return true; if((pos.getZ() & 15) != 0)return true; return false; @@ -35,31 +37,32 @@ public class MansionFinder extends Finder { public MansionFinder(World world, ChunkPos chunkPos) { super(world, chunkPos); - Direction.Type.HORIZONTAL.forEach(direction -> { - PieceFinder finder = new PieceFinder(world, chunkPos, direction, size); + for(Direction direction: Direction.values()) { + PieceFinder finder = new PieceFinder(world, chunkPos, direction, this.size); finder.searchPositions = SEARCH_POSITIONS; buildStructure(finder); this.finders.add(finder); - }); + } } @Override public List findInChunk() { + Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(9, 0, 9)); + + if(!biome.hasStructureFeature(Feature.WOODLAND_MANSION)) { + return new ArrayList<>(); + } + Map> result = this.findInChunkPieces(); List combinedResult = new ArrayList<>(); result.forEach((pieceFinder, positions) -> { - positions.removeIf(pos -> { - //Figure this out, it's not a trivial task. - return false; - }); - combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.WOODLAND_MANSION))) { + if(SeedCracker.get().onStructureData(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))); } @@ -80,12 +83,26 @@ public class MansionFinder extends Finder { } public void buildStructure(PieceFinder finder) { + BlockState air = Blocks.AIR.getDefaultState(); BlockState cobblestone = Blocks.COBBLESTONE.getDefaultState(); BlockState birchPlanks = Blocks.BIRCH_PLANKS.getDefaultState(); BlockState redCarpet = Blocks.RED_CARPET.getDefaultState(); BlockState whiteCarpet = Blocks.WHITE_CARPET.getDefaultState(); - //TODO: Finish this. + finder.fillWithOutline(0, 0, 0, 15, 0, 15, birchPlanks, birchPlanks, false); + finder.fillWithOutline(0, 0, 8, 6, 0, 12, null, null, false); + finder.fillWithOutline(0, 0, 12, 9, 0, 15, null, null, false); + finder.fillWithOutline(15, 0, 0, 15, 0, 15, cobblestone, cobblestone, false); + finder.addBlock(Blocks.DARK_OAK_LOG.getDefaultState(), 15, 0, 15); + finder.addBlock(Blocks.DARK_OAK_LOG.getDefaultState(), 15, 0, 7); + finder.addBlock(Blocks.DARK_OAK_LOG.getDefaultState(), 14, 0, 7); + + finder.fillWithOutline(9, 1, 0, 9, 1, 8, whiteCarpet, whiteCarpet, false); + finder.addBlock(whiteCarpet, 8,1, 8); + finder.fillWithOutline(13, 1, 0, 13, 1, 8, whiteCarpet, whiteCarpet, false); + finder.addBlock(whiteCarpet, 14,1, 8); + + finder.fillWithOutline(10, 1, 0, 12, 1, 15, redCarpet, redCarpet, false); } @Override diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java index f4f3cb0..7484456 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/OceanMonumentFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cube; import kaptainwutax.seedcracker.render.Cuboid; @@ -57,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, StructureData.OCEAN_MONUMENT))) { + if(SeedCracker.get().onStructureData(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/PieceFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/PieceFinder.java index 02a57af..b6df258 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/PieceFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/PieceFinder.java @@ -18,7 +18,7 @@ import java.util.Map; public class PieceFinder extends Finder { protected Map structure = new LinkedHashMap<>(); - private MutableIntBoundingBox boundingBox; + private BlockBox boundingBox; protected List searchPositions = new ArrayList<>(); protected Direction facing; @@ -40,12 +40,12 @@ public class PieceFinder extends Finder { this.depth = size.getZ(); if(this.facing.getAxis() == Direction.Axis.Z) { - this.boundingBox = new MutableIntBoundingBox( + this.boundingBox = new BlockBox( 0, 0, 0, size.getX() - 1, size.getY() - 1, size.getZ() - 1 ); } else { - this.boundingBox = new MutableIntBoundingBox( + this.boundingBox = new BlockBox( 0, 0, 0, size.getZ() - 1, size.getY() - 1, size.getX() - 1 ); @@ -71,7 +71,7 @@ public class PieceFinder extends Finder { //FOR DEBUGGING PIECES. if(this.debug) { MinecraftClient.getInstance().execute(() -> { - int y = this.rotation.ordinal() * 10 + this.mirror.ordinal() * 20 + 100; + int y = this.rotation.ordinal() * 10 + this.mirror.ordinal() * 20 + 120; if (this.chunkPos.x % 2 == 0 && this.chunkPos.z % 2 == 0) { this.structure.forEach((pos, state) -> { @@ -89,7 +89,7 @@ public class PieceFinder extends Finder { BlockState state = this.world.getBlockState(pos); //Blockstate may change when it gets placed in the world, that's why it's using the block here. - if(!state.getBlock().equals(entry.getValue().getBlock())) { + if(entry.getValue() != null && !state.getBlock().equals(entry.getValue().getBlock())) { found = false; break; } @@ -200,10 +200,6 @@ public class PieceFinder extends Finder { } protected void addBlock(BlockState state, int x, int y, int z) { - if(state == null) { - return; - } - BlockPos pos = new BlockPos( this.applyXTransform(x, z), this.applyYTransform(y), @@ -211,6 +207,11 @@ public class PieceFinder extends Finder { ); if(this.boundingBox.contains(pos)) { + if(state == null) { + this.structure.remove(pos); + return; + } + if (this.mirror != BlockMirror.NONE) { state = state.mirror(this.mirror); } @@ -219,6 +220,7 @@ public class PieceFinder extends Finder { state = state.rotate(this.rotation); } + this.structure.put(pos, state); } } diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java new file mode 100644 index 0000000..9dbc88f --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/ShipwreckFinder.java @@ -0,0 +1,211 @@ +package kaptainwutax.seedcracker.finder.structure; + +import kaptainwutax.seedcracker.SeedCracker; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; +import kaptainwutax.seedcracker.finder.BlockFinder; +import kaptainwutax.seedcracker.finder.Finder; +import kaptainwutax.seedcracker.render.Cube; +import kaptainwutax.seedcracker.render.Cuboid; +import net.minecraft.block.*; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.ChestBlockEntity; +import net.minecraft.block.enums.ChestType; +import net.minecraft.client.util.math.Vector4f; +import net.minecraft.util.math.BlockBox; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.feature.Feature; + +import java.util.ArrayList; +import java.util.List; + +public class ShipwreckFinder extends BlockFinder { + + protected static List SEARCH_POSITIONS = Finder.buildSearchPositions(Finder.CHUNK_POSITIONS, pos -> { + return false; + }); + + public ShipwreckFinder(World world, ChunkPos chunkPos) { + super(world, chunkPos, Blocks.CHEST); + this.searchPositions = SEARCH_POSITIONS; + } + + @Override + public List findInChunk() { + Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(9, 0, 9)); + + if(!biome.hasStructureFeature(Feature.SHIPWRECK)) { + return new ArrayList<>(); + } + + List result = super.findInChunk(); + + result.removeIf(pos -> { + BlockState state = this.world.getBlockState(pos); + if(state.get(ChestBlock.CHEST_TYPE) != ChestType.SINGLE)return true; + + BlockEntity blockEntity = this.world.getBlockEntity(pos); + if(!(blockEntity instanceof ChestBlockEntity))return true; + + return !this.onChestFound(pos); + }); + + return result; + } + + /** + * Source: https://github.com/skyrising/casual-mod/blob/master/src/main/java/de/skyrising/casual/ShipwreckFinder.java + * */ + private boolean onChestFound(BlockPos pos) { + BlockPos.Mutable mutablePos = new BlockPos.Mutable(pos); + Direction chestFacing = world.getBlockState(pos).get(ChestBlock.FACING); + + int[] stairs = new int[4]; + int totalStairs = 0; + int[] trapdoors = new int[4]; + int totalTrapdoors = 0; + for(int y = -1; y <= 2; y++) { + for(int x = -1; x <= 1; x++) { + for(int z = -1; z <= 1; z++) { + if (x == 0 && y == 0 && z == 0)continue; + mutablePos.set(pos.getX() + x, pos.getY() + y, pos.getZ() + z); + BlockState neighborState = world.getBlockState(mutablePos); + Block neighborBlock = neighborState.getBlock(); + if(neighborBlock == Blocks.VOID_AIR)return false; + + if(neighborBlock instanceof StairsBlock) { + stairs[y + 1]++; + totalStairs++; + } else if(neighborBlock instanceof TrapdoorBlock) { + trapdoors[y + 1]++; + totalTrapdoors++; + } + } + } + } + //System.out.printf("%s: chest facing %s\n", pos, chestFacing); + int chestX = 4; + int chestY = 2; + int chestZ = 0; + int length = 16; + int height = 9; + Direction direction = chestFacing; + + if(trapdoors[3] > 4) { // with_mast[_degraded] + chestZ = 9; + height = 21; + length = 28; + } else if(totalTrapdoors == 0 && stairs[3] == 3) { // upsidedown_backhalf[_degraded] + if(stairs[0] == 0) { + chestX = 2; + chestZ = 12; + direction = chestFacing.getOpposite(); + } else { // redundant + chestX = 3; + chestY = 5; + chestZ = 5; + direction = chestFacing.rotateYClockwise(); + } + } else if(totalTrapdoors == 0) { // rightsideup that have backhalf + if(stairs[0] == 4) { + if(totalStairs > 4) { + chestX = 6; + chestY = 4; + chestZ = 12; + direction = chestFacing.getOpposite(); + } else { // sideways backhalf + chestX = 6; + chestY = 3; + chestZ = 8; + length = 17; + direction = chestFacing.getOpposite(); + } + } else if(stairs[0] == 3 && totalStairs > 5) { + chestX = 5; + chestZ = 6; + direction = chestFacing.rotateYCounterclockwise(); + } + + mutablePos.set(pos); + mutablePos.setOffset(0, -chestY, 0); + mutablePos.setOffset(direction.rotateYClockwise(), chestX - 4); + mutablePos.setOffset(direction, -chestZ - 1); + + if(this.world.getBlockState(mutablePos).getMaterial() == Material.WOOD) { + if(length == 17) { // sideways + chestZ += 11; + length += 11; + } else { + chestZ += 12; + length += 12; + } + mutablePos.setOffset(0, 10, 0); + + if(this.world.getBlockState(mutablePos).getBlock() instanceof LogBlock) { + height = 21; + } + } + } else if(totalTrapdoors == 2 && trapdoors[3] == 2 && stairs[3] == 3) { // rightsideup_fronthalf[_degraded] + chestZ = 8; + length = 24; + } + + if(chestZ != 0) { + mutablePos.set(pos); + mutablePos.setOffset(direction, 15 - chestZ); + mutablePos.setOffset(direction.rotateYClockwise(), chestX - 4); + BlockPos.Mutable pos2 = new BlockPos.Mutable(mutablePos); + pos2.setOffset(0, -chestY, 0); + pos2.setOffset(direction, -15); + pos2.setOffset(direction.rotateYClockwise(), 4); + BlockPos.Mutable pos3 = new BlockPos.Mutable(pos2); + pos3.setOffset(direction, length - 1); + pos3.setOffset(direction.rotateYClockwise(), -8); + pos3.setOffset(0, height - 1, 0); + + BlockBox box = new BlockBox( + Math.min(pos2.getX(), pos3.getX()), pos2.getY(), Math.min(pos2.getZ(), pos3.getZ()), + Math.max(pos2.getX(), pos3.getX()), pos3.getY(), Math.max(pos2.getZ(), pos3.getZ())); + + 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))) { + 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; + } + } + } + + return false; + } + + @Override + public boolean isValidDimension(DimensionType dimension) { + return dimension == DimensionType.OVERWORLD; + } + + public static List create(World world, ChunkPos chunkPos) { + List finders = new ArrayList<>(); + finders.add(new ShipwreckFinder(world, chunkPos)); + + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); + + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z))); + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1))); + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1))); + + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); + finders.add(new ShipwreckFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z + 1))); + return finders; + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java index 2f03449..84bbe23 100644 --- a/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java +++ b/src/main/java/kaptainwutax/seedcracker/finder/structure/SwampHutFinder.java @@ -1,7 +1,8 @@ package kaptainwutax.seedcracker.finder.structure; import kaptainwutax.seedcracker.SeedCracker; -import kaptainwutax.seedcracker.cracker.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureData; +import kaptainwutax.seedcracker.cracker.structure.StructureFeatures; import kaptainwutax.seedcracker.finder.Finder; import kaptainwutax.seedcracker.render.Cuboid; import net.minecraft.block.BlockState; @@ -36,7 +37,7 @@ public class SwampHutFinder extends AbstractTempleFinder { combinedResult.addAll(positions); positions.forEach(pos -> { - if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.SWAMP_HUT))) { + if(SeedCracker.get().onStructureData(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/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java index fc75998..f88eca7 100644 --- a/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/kaptainwutax/seedcracker/mixin/ClientPlayNetworkHandlerMixin.java @@ -2,6 +2,7 @@ package kaptainwutax.seedcracker.mixin; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.CommandDispatcher; +import kaptainwutax.seedcracker.SeedCracker; import kaptainwutax.seedcracker.command.ClientCommands; import kaptainwutax.seedcracker.finder.FinderQueue; import net.minecraft.client.MinecraftClient; @@ -9,6 +10,7 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.packet.ChunkDataS2CPacket; import net.minecraft.client.network.packet.CommandTreeS2CPacket; +import net.minecraft.client.network.packet.PlayerRespawnS2CPacket; import net.minecraft.client.world.ClientWorld; import net.minecraft.network.ClientConnection; import net.minecraft.server.command.CommandSource; @@ -44,4 +46,9 @@ public abstract class ClientPlayNetworkHandlerMixin { ClientCommands.registerCommands((CommandDispatcher)(Object)this.commandDispatcher); } + @Inject(method = "onPlayerRespawn", at = @At("HEAD")) + public void onPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) { + SeedCracker.get().hashedWorldSeed = packet.method_22425(); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java b/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java index 60e4157..ab6ee10 100644 --- a/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java +++ b/src/main/java/kaptainwutax/seedcracker/mixin/ClientWorldMixin.java @@ -1,14 +1,15 @@ package kaptainwutax.seedcracker.mixin; -import kaptainwutax.seedcracker.finder.FinderQueue; import kaptainwutax.seedcracker.SeedCracker; +import kaptainwutax.seedcracker.finder.FinderQueue; import net.minecraft.client.world.ClientWorld; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biomes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.concurrent.Executors; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ClientWorld.class) public abstract class ClientWorldMixin { @@ -17,8 +18,11 @@ public abstract class ClientWorldMixin { private void disconnect(CallbackInfo ci) { SeedCracker.get().clear(); FinderQueue.get().clear(); - FinderQueue.SERVICE.shutdown(); - FinderQueue.SERVICE = Executors.newFixedThreadPool(5); + } + + @Inject(method = "getGeneratorStoredBiome", at = @At("HEAD"), cancellable = true) + private void getGeneratorStoredBiome(int x, int y, int z, CallbackInfoReturnable ci) { + ci.setReturnValue(Biomes.THE_VOID); } } diff --git a/src/main/java/kaptainwutax/seedcracker/mixin/GameRendererMixin.java b/src/main/java/kaptainwutax/seedcracker/mixin/GameRendererMixin.java index 2345295..b79d43b 100644 --- a/src/main/java/kaptainwutax/seedcracker/mixin/GameRendererMixin.java +++ b/src/main/java/kaptainwutax/seedcracker/mixin/GameRendererMixin.java @@ -2,6 +2,7 @@ package kaptainwutax.seedcracker.mixin; import kaptainwutax.seedcracker.render.RenderQueue; import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -10,14 +11,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GameRenderer.class) public abstract class GameRendererMixin { - @Inject(method = "renderCenter", at = @At("HEAD")) - private void renderCenterStart(float delta, long time, CallbackInfo ci) { - RenderQueue.get().setTrackRender(true); + @Inject(method = "renderWorld", at = @At("HEAD")) + private void renderWorldStart(float delta, long time, MatrixStack matrixStack, CallbackInfo ci) { + RenderQueue.get().setTrackRender(matrixStack); } - @Inject(method = "renderCenter", at = @At("TAIL")) - private void renderCenterFinish(float delta, long time, CallbackInfo ci) { - RenderQueue.get().setTrackRender(false); + @Inject(method = "renderWorld", at = @At("TAIL")) + private void renderWorldFinish(float delta, long time, MatrixStack matrixStack, CallbackInfo ci) { + RenderQueue.get().setTrackRender(null); } } diff --git a/src/main/java/kaptainwutax/seedcracker/render/Cube.java b/src/main/java/kaptainwutax/seedcracker/render/Cube.java index 5c734a2..a446139 100644 --- a/src/main/java/kaptainwutax/seedcracker/render/Cube.java +++ b/src/main/java/kaptainwutax/seedcracker/render/Cube.java @@ -18,4 +18,9 @@ public class Cube extends Cuboid { super(pos, new Vec3i(1, 1, 1), color); } + @Override + public BlockPos getPos() { + return this.start; + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/render/Cuboid.java b/src/main/java/kaptainwutax/seedcracker/render/Cuboid.java index d0e7ffb..201efff 100644 --- a/src/main/java/kaptainwutax/seedcracker/render/Cuboid.java +++ b/src/main/java/kaptainwutax/seedcracker/render/Cuboid.java @@ -1,6 +1,7 @@ package kaptainwutax.seedcracker.render; import net.minecraft.client.util.math.Vector4f; +import net.minecraft.util.math.BlockBox; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3i; @@ -24,6 +25,10 @@ public class Cuboid extends Renderer { this(start, new Vec3i(end.getX() - start.getX(), end.getY() - start.getY(), end.getZ() - start.getZ()), color); } + public Cuboid(BlockBox box, Vector4f color) { + this(new BlockPos(box.minX, box.minY, box.minZ), new BlockPos(box.maxX, box.maxY, box.maxZ), color); + } + public Cuboid(BlockPos start, Vec3i size, Vector4f color) { this.start = start; this.size = size; @@ -52,4 +57,9 @@ public class Cuboid extends Renderer { } } + @Override + public BlockPos getPos() { + return this.start.add(this.size.getX() / 2, this.size.getY() / 2, this.size.getZ() / 2); + } + } diff --git a/src/main/java/kaptainwutax/seedcracker/render/Line.java b/src/main/java/kaptainwutax/seedcracker/render/Line.java index 2113892..43daa6c 100644 --- a/src/main/java/kaptainwutax/seedcracker/render/Line.java +++ b/src/main/java/kaptainwutax/seedcracker/render/Line.java @@ -5,6 +5,7 @@ import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.util.math.Vector4f; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; public class Line extends Renderer { @@ -33,7 +34,7 @@ public class Line extends Renderer { Vec3d camPos = this.mc.gameRenderer.getCamera().getPos(); Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBufferBuilder(); + BufferBuilder buffer = tessellator.getBuffer(); //This is how thick the line is. GlStateManager.lineWidth(2.0f); @@ -48,18 +49,24 @@ public class Line extends Renderer { } protected void putVertex(BufferBuilder buffer, Vec3d camPos, Vec3d pos) { - for(int i = 0; i < 2; i++) { - buffer.vertex( - pos.getX() - camPos.x, - pos.getY() - camPos.y, - pos.getZ() - camPos.z - ).color( - this.color.getX(), - this.color.getY(), - this.color.getZ(), - this.color.getW() - ).next(); - } + buffer.vertex( + pos.getX() - camPos.x, + pos.getY() - camPos.y, + pos.getZ() - camPos.z + ).color( + this.color.getX(), + this.color.getY(), + this.color.getZ(), + this.color.getW() + ).next(); + } + + @Override + public BlockPos getPos() { + double x = (this.end.getX() - this.start.getX()) / 2 + this.start.getX(); + double y = (this.end.getY() - this.start.getY()) / 2 + this.start.getY(); + double z = (this.end.getZ() - this.start.getZ()) / 2 + this.start.getZ(); + return new BlockPos(x, y, z); } } diff --git a/src/main/java/kaptainwutax/seedcracker/render/RenderQueue.java b/src/main/java/kaptainwutax/seedcracker/render/RenderQueue.java index 0029650..e993726 100644 --- a/src/main/java/kaptainwutax/seedcracker/render/RenderQueue.java +++ b/src/main/java/kaptainwutax/seedcracker/render/RenderQueue.java @@ -1,19 +1,22 @@ package kaptainwutax.seedcracker.render; +import net.minecraft.client.util.math.MatrixStack; + import java.util.*; +import java.util.function.Consumer; public class RenderQueue { private final static RenderQueue INSTANCE = new RenderQueue(); - private Map> typeRunnableMap = new HashMap<>(); - private boolean trackRender = false; + private Map>> typeRunnableMap = new HashMap<>(); + private MatrixStack matrixStack = null; public static RenderQueue get() { return INSTANCE; } - public void add(String type, Runnable runnable) { + public void add(String type, Consumer runnable) { Objects.requireNonNull(type); Objects.requireNonNull(runnable); @@ -21,11 +24,11 @@ public class RenderQueue { this.typeRunnableMap.put(type, new ArrayList<>()); } - List runnableList = this.typeRunnableMap.get(type); + List> runnableList = this.typeRunnableMap.get(type); runnableList.add(runnable); } - public void remove(String type, Runnable runnable) { + public void remove(String type, Consumer runnable) { Objects.requireNonNull(type); Objects.requireNonNull(runnable); @@ -33,17 +36,17 @@ public class RenderQueue { return; } - List runnableList = this.typeRunnableMap.get(type); + List> runnableList = this.typeRunnableMap.get(type); runnableList.remove(runnable); } - public void setTrackRender(boolean flag) { - this.trackRender = flag; + public void setTrackRender(MatrixStack matrixStack) { + this.matrixStack = matrixStack; } public void onRender(String type) { - if(!this.trackRender || !this.typeRunnableMap.containsKey(type))return; - this.typeRunnableMap.get(type).forEach(Runnable::run); + if(this.matrixStack == null || !this.typeRunnableMap.containsKey(type))return; + this.typeRunnableMap.get(type).forEach(r -> r.accept(this.matrixStack)); } } diff --git a/src/main/java/kaptainwutax/seedcracker/render/Renderer.java b/src/main/java/kaptainwutax/seedcracker/render/Renderer.java index 88485bd..d1c97af 100644 --- a/src/main/java/kaptainwutax/seedcracker/render/Renderer.java +++ b/src/main/java/kaptainwutax/seedcracker/render/Renderer.java @@ -10,6 +10,8 @@ public abstract class Renderer { public abstract void render(); + public abstract BlockPos getPos(); + protected Vec3d toVec3d(BlockPos pos) { return new Vec3d(pos.getX(), pos.getY(), pos.getZ()); } diff --git a/src/main/java/kaptainwutax/seedcracker/util/Rand.java b/src/main/java/kaptainwutax/seedcracker/util/Rand.java index e045f46..003c66b 100644 --- a/src/main/java/kaptainwutax/seedcracker/util/Rand.java +++ b/src/main/java/kaptainwutax/seedcracker/util/Rand.java @@ -2,6 +2,8 @@ package kaptainwutax.seedcracker.util; import kaptainwutax.seedcracker.util.math.LCG; +import java.util.Random; + public class Rand implements Cloneable { public static final LCG JAVA_LCG = new LCG(0x5DEECE66DL, 0xBL, 1L << 48); @@ -69,6 +71,10 @@ public class Rand implements Cloneable { return (((long)this.next(27) << 27) + this.next(27)) / (double)(1L << 54); } + public Random toRandom() { + return new Random(this.seed ^ JAVA_LCG.multiplier); + } + @Override public boolean equals(Object obj) { if(obj == this)return true; diff --git a/src/main/java/kaptainwutax/seedcracker/util/Seeds.java b/src/main/java/kaptainwutax/seedcracker/util/Seeds.java new file mode 100644 index 0000000..2939f23 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/util/Seeds.java @@ -0,0 +1,29 @@ +package kaptainwutax.seedcracker.util; + +public class Seeds { + + public static long setRegionSeed(Rand rand, long worldSeed, int regionX, int regionZ, int salt) { + long seed = (long)regionX * 341873128712L + (long)regionZ * 132897987541L + worldSeed + (long)salt; + rand.setSeed(seed, true); + return seed; + } + + public static long setStructureStartSeed(Rand rand, long worldSeed, int chunkX, int chunkZ) { + rand.setSeed(worldSeed, true); + long a = rand.nextLong(); + long b = rand.nextLong(); + long seed = (long)chunkX * a ^ (long)chunkZ * b ^ worldSeed; + rand.setSeed(seed, true); + return seed; + } + + public static long setWeakSeed(Rand rand, long worldSeed, int chunkX, int chunkZ) { + int sX = chunkX >> 4; + int sZ = chunkZ >> 4; + long seed = (long)(sX ^ sZ << 4) ^ worldSeed; + rand.setSeed(seed, true); + rand.nextInt(); + return seed; + } + +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 2c48cd5..d992d04 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "seedcracker", - "version": "0.0.1", + "version": "0.0.2", "name": "Seed Cracker", "description": "This is an example description! Tell everyone what your mod is about!",