Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
|
||||
@@ -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<Long> worldSeeds = null;
|
||||
public List<Long> structureSeeds = null;
|
||||
public Set<Long> structureSeeds = null;
|
||||
public List<Integer> pillarSeeds = null;
|
||||
|
||||
private TimeMachine timeMachine = new TimeMachine();
|
||||
private List<StructureData> structureCache = new ArrayList<>();
|
||||
private List<PopulationData> populationCache = new ArrayList<>();
|
||||
private List<DecoratorData> decoratorCache = new ArrayList<>();
|
||||
private List<BiomeData> 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<ChunkPos> initialize(long worldSeed) {
|
||||
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
|
||||
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[0];
|
||||
|
||||
List<ChunkPos> startPositions = new ArrayList<>();
|
||||
List<Biome> 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<Biome> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,7 +39,7 @@ public class DecoratorCache {
|
||||
}
|
||||
|
||||
private void initializeBiomeStep(Biome biome, GenerationStep.Feature genStep) {
|
||||
List<ConfiguredFeature<?>> features = biome.getFeaturesForStep(genStep);
|
||||
List<ConfiguredFeature<?, ?>> features = biome.getFeaturesForStep(genStep);
|
||||
|
||||
for(int i = 0; i < features.size(); i++) {
|
||||
FeatureConfig config = features.get(i).config;
|
||||
|
||||
@@ -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<Biome> 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.<Biome>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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,39 +7,39 @@ import java.util.Random;
|
||||
|
||||
public class PillarData {
|
||||
|
||||
private List<Integer> heights;
|
||||
private List<Integer> heights;
|
||||
|
||||
public PillarData(List<Integer> heights) {
|
||||
this.heights = heights;
|
||||
}
|
||||
public PillarData(List<Integer> heights) {
|
||||
this.heights = heights;
|
||||
}
|
||||
|
||||
public List<Integer> getPillarSeeds() {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
public List<Integer> getPillarSeeds() {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
||||
for(int pillarSeed = 0; pillarSeed < (1 << 16); pillarSeed++) {
|
||||
List<Integer> h = this.getPillarHeights(pillarSeed);
|
||||
if(h.equals(heights))result.add(pillarSeed);
|
||||
}
|
||||
for(int pillarSeed = 0; pillarSeed < (1 << 16); pillarSeed++) {
|
||||
List<Integer> h = this.getPillarHeights(pillarSeed);
|
||||
if(h.equals(this.heights)) result.add(pillarSeed);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Integer> getPillarHeights(int spikeSeed) {
|
||||
List<Integer> indices = new ArrayList<>();
|
||||
public List<Integer> getPillarHeights(int spikeSeed) {
|
||||
List<Integer> 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<Integer> heights = new ArrayList<>();
|
||||
List<Integer> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<PopulationData> populationDataList, List<Long> structureSeeds) {
|
||||
ChunkRandom chunkRandom = new ChunkRandom();
|
||||
public List<Long> bruteforceRegion(int pillarSeed, int region, long size, List<StructureData> structureDataList, List<DecoratorData> decoratorDataList) {
|
||||
List<Long> 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<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<DecoratorData> decoratorDataList, Set<Long> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Biome, Long> 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<ConfiguredFeature<?>> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<StructureData> featureType;
|
||||
|
||||
public StructureData(ChunkPos chunkPos, FeatureType<StructureData> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<StructureData> DESERT_PYRAMID = new AbstractTempleType(14357617, 32, 24);
|
||||
|
||||
public static final FeatureType<StructureData> IGLOO = new AbstractTempleType(14357618, 32, 24);
|
||||
|
||||
public static final FeatureType<StructureData> JUNGLE_TEMPLE = new AbstractTempleType(14357619, 32, 24);
|
||||
|
||||
public static final FeatureType<StructureData> SWAMP_HUT = new AbstractTempleType(14357620, 32, 24);
|
||||
|
||||
public static final FeatureType<StructureData> OCEAN_RUIN = new AbstractTempleType(14357621, 16, 8);
|
||||
|
||||
public static final FeatureType<StructureData> SHIPWRECK = new AbstractTempleType(165745295, 16, 8);
|
||||
|
||||
public static final FeatureType<StructureData> 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<StructureData> VILLAGE = new AbstractTempleType(10387312, 32, 24);
|
||||
|
||||
public static final FeatureType<StructureData> END_CITY = new TriangularType(10387313, 20, 9);
|
||||
|
||||
public static final FeatureType<StructureData> OCEAN_MONUMENT = new TriangularType(10387313, 32, 27);
|
||||
|
||||
public static final FeatureType<StructureData> WOODLAND_MANSION = new TriangularType(10387319, 80, 60);
|
||||
|
||||
public static final FeatureType<StructureData> BURIED_TREASURE = new RarityType(10387320, 1, 0.01F);
|
||||
|
||||
public static final FeatureType<StructureData> NETHER_FORTRESS = new FeatureType<StructureData>(-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<StructureData> MINESHAFT = new FeatureType<StructureData>(-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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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<StructureData> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<T extends StructureData> {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -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<StructureData> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<StructureData> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Integer> 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<Long> dungeonSeeds = this.getDungeonSeeds(dungeonSize, floorCalls);
|
||||
List<Long> 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<Long> getDungeonSeeds(Vec3i dungeonSize, List<Integer> floorCalls) {
|
||||
List<Long> floorSeeds = new ArrayList<>();
|
||||
|
||||
//TODO: Lattice magic to find floorSeeds from floorCalls.
|
||||
|
||||
List<Long> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import java.util.List;
|
||||
public class EmeraldOreFinder extends BlockFinder {
|
||||
|
||||
protected static List<BlockPos> 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<BlockPos> 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)));
|
||||
});
|
||||
|
||||
@@ -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<BlockPos> 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<BlockPos> 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)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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<BlockPos> 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<BlockPos> findInChunk() {
|
||||
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(9, 0, 9));
|
||||
|
||||
if(!biome.hasStructureFeature(Feature.WOODLAND_MANSION)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Map<PieceFinder, List<BlockPos>> result = this.findInChunkPieces();
|
||||
List<BlockPos> 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
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.util.Map;
|
||||
public class PieceFinder extends Finder {
|
||||
|
||||
protected Map<BlockPos, BlockState> structure = new LinkedHashMap<>();
|
||||
private MutableIntBoundingBox boundingBox;
|
||||
private BlockBox boundingBox;
|
||||
protected List<BlockPos> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<BlockPos> 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<BlockPos> findInChunk() {
|
||||
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(9, 0, 9));
|
||||
|
||||
if(!biome.hasStructureFeature(Feature.SHIPWRECK)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<BlockPos> 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<Finder> create(World world, ChunkPos chunkPos) {
|
||||
List<Finder> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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<ServerCommandSource>)(Object)this.commandDispatcher);
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerRespawn", at = @At("HEAD"))
|
||||
public void onPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) {
|
||||
SeedCracker.get().hashedWorldSeed = packet.method_22425();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Biome> ci) {
|
||||
ci.setReturnValue(Biomes.THE_VOID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,4 +18,9 @@ public class Cube extends Cuboid {
|
||||
super(pos, new Vec3i(1, 1, 1), color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getPos() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String, List<Runnable>> typeRunnableMap = new HashMap<>();
|
||||
private boolean trackRender = false;
|
||||
private Map<String, List<Consumer<MatrixStack>>> 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<MatrixStack> runnable) {
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(runnable);
|
||||
|
||||
@@ -21,11 +24,11 @@ public class RenderQueue {
|
||||
this.typeRunnableMap.put(type, new ArrayList<>());
|
||||
}
|
||||
|
||||
List<Runnable> runnableList = this.typeRunnableMap.get(type);
|
||||
List<Consumer<MatrixStack>> runnableList = this.typeRunnableMap.get(type);
|
||||
runnableList.add(runnable);
|
||||
}
|
||||
|
||||
public void remove(String type, Runnable runnable) {
|
||||
public void remove(String type, Consumer<MatrixStack> runnable) {
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(runnable);
|
||||
|
||||
@@ -33,17 +36,17 @@ public class RenderQueue {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Runnable> runnableList = this.typeRunnableMap.get(type);
|
||||
List<Consumer<MatrixStack>> 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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!",
|
||||
|
||||
Reference in New Issue
Block a user