15 Commits

Author SHA1 Message Date
Hykilpikonna c8875b2d75 [O] Optimize user report and usability for 1.14.4 2020-02-21 11:36:57 -05:00
Hykilpikonna 56d8d47289 Revert "Revert "Whatever""
This reverts commit 6c0760ae01.
2020-02-20 10:47:38 -05:00
Hykilpikonna 6c0760ae01 Revert "Whatever"
This reverts commit 4e28f711ed.
2020-02-20 10:42:38 -05:00
Hykilpikonna 8db7d96727 Revert "Merge remote-tracking branch 'origin/master'"
This reverts commit 3f57818c35, reversing
changes made to 4e28f711ed.
2020-02-20 10:42:03 -05:00
Neil 3f57818c35 Merge remote-tracking branch 'origin/master' 2020-02-18 16:25:41 +01:00
Neil 4e28f711ed Whatever 2020-02-18 16:24:52 +01:00
Unknown 0abeaeabdb improved structure data logic 2019-12-31 19:47:06 -05:00
Unknown be62ba5c00 optimized structure seed code 2019-12-30 15:43:41 -05:00
Unknown 5ed8e517e4 optimized buried treasure finder 2019-12-29 16:47:44 -05:00
Unknown 4a0c86c36a Merge remote-tracking branch 'origin/master' 2019-12-29 15:53:22 -05:00
Unknown 5cfa74ac19 code cleanup 2019-12-29 15:53:15 -05:00
KESSLER Erwan a5da8b83e8 linked log to in-game chat 2019-12-26 23:41:02 +01:00
KaptainWutax 79e7b00210 Update README.md 2019-12-24 10:26:51 -05:00
KaptainWutax cb85a794d1 Merge pull request #3 from Nekzuris/master
Improve README.md
2019-12-24 10:26:01 -05:00
Demange Louis 4a8f4c7a4d Improve README.md 2019-12-24 16:14:57 +01:00
32 changed files with 346 additions and 570 deletions
+3 -3
View File
@@ -3,12 +3,12 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/use
minecraft_version=1.15
yarn_mappings=1.15+build.2
minecraft_version=1.14.4
yarn_mappings=1.14.4+build.15
loader_version=0.7.2+build.174
# Mod Properties
mod_version = 0.0.2-alpha
mod_version = 1.0.0
maven_group = kaptainwutax
archives_base_name = seedcracker
@@ -1,44 +1,96 @@
package kaptainwutax.seedcracker;
import io.netty.util.internal.ConcurrentSet;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import kaptainwutax.seedcracker.cracker.*;
import kaptainwutax.seedcracker.cracker.population.DecoratorData;
import kaptainwutax.seedcracker.cracker.population.PopulationData;
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.BlockBox;
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 java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Random;
public class SeedCracker implements ModInitializer {
private static final SeedCracker INSTANCE = new SeedCracker();
public List<Long> worldSeeds = null;
public Set<Long> structureSeeds = null;
public List<Long> structureSeeds = null;
public List<Integer> pillarSeeds = null;
private TimeMachine timeMachine = new TimeMachine();
private List<StructureData> structureCache = new ArrayList<>();
private List<DecoratorData> decoratorCache = new ArrayList<>();
private List<PopulationData> populationCache = new ArrayList<>();
private List<BiomeData> biomeCache = new ArrayList<>();
@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, BlockBox.empty(), 0, worldSeed);
StrongholdFeature.Start start = new StrongholdFeature.Start(Feature.STRONGHOLD, pos.x, pos.z, Biomes.PLAINS, MutableIntBoundingBox.empty(), 0, worldSeed);
}
public static SeedCracker get() {
@@ -51,7 +103,7 @@ public class SeedCracker implements ModInitializer {
this.pillarSeeds = null;
this.structureCache.clear();
this.biomeCache.clear();
this.decoratorCache.clear();
this.populationCache.clear();
}
public synchronized boolean onPillarData(PillarData pillarData) {
@@ -61,7 +113,7 @@ public class SeedCracker implements ModInitializer {
this.pillarSeeds = pillarData.getPillarSeeds();
if(this.pillarSeeds.size() > 0) {
Log.warn("Finished search with " + this.pillarSeeds + (this.pillarSeeds.size() == 1 ? " seed." : " seeds."));
Log.warn("Finished search with " + this.pillarSeeds);
} else {
Log.error("Finished search with no seeds.");
}
@@ -79,25 +131,28 @@ public class SeedCracker implements ModInitializer {
if(structureData != null && !this.structureCache.contains(structureData)) {
this.structureCache.add(structureData);
added = true;
Log.warn("Structure added: " + structureData);
System.out.println(new Gson().toJson(structureCache));
}
if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() + this.decoratorCache.size() >= 5) {
this.structureSeeds = new ConcurrentSet<>();
if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() + this.populationCache.size() >= 6) {
this.structureSeeds = new ArrayList<>();
Log.warn("Looking for structure seeds with " + this.structureCache.size() + " structure features.");
Log.warn("Looking for structure seeds with " + this.decoratorCache.size() + " decorator features.");
Log.warn("Looking for structure seeds with " + this.populationCache.size() + " population features.");
this.pillarSeeds.forEach(pillarSeed -> {
timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.decoratorCache, this.structureSeeds);
timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.populationCache, this.structureSeeds);
});
if(this.structureSeeds.size() > 0) {
Log.warn("Finished search with " + this.structureSeeds + (this.structureSeeds.size() == 1 ? " seed." : " seeds."));
Log.warn("Finished search with " + this.structureSeeds);
} else {
Log.error("Finished search with no seeds.");
}
this.structureCache.clear();
this.onDecoratorData(null);
//this.structureCache.clear();
//this.onPopulationData(null);
this.onBiomeData(null);
} else if(this.structureSeeds != null && structureData != null) {
this.structureSeeds.removeIf(structureSeed -> {
@@ -112,11 +167,11 @@ public class SeedCracker implements ModInitializer {
return added;
}
public synchronized boolean onDecoratorData(DecoratorData decoratorData) {
public synchronized boolean onPopulationData(PopulationData populationData) {
boolean added = false;
if(decoratorData != null && !this.decoratorCache.contains(decoratorData)) {
this.decoratorCache.add(decoratorData);
if(populationData != null && !this.populationCache.contains(populationData)) {
this.populationCache.add(populationData);
added = true;
}
@@ -130,21 +185,28 @@ public class SeedCracker implements ModInitializer {
if(biomeData != null && !this.biomeCache.contains(biomeData)) {
this.biomeCache.add(biomeData);
added = true;
Log.warn("Biome added: " + biomeData);
System.out.println(new Gson().toJson(biomeCache));
}
if(this.worldSeeds == null && this.structureSeeds != null && this.biomeCache.size() >= 5) {
this.worldSeeds = new ArrayList<>();
Log.warn("Looking for world seeds with " + this.biomeCache.size() + " biomes.");
this.structureSeeds.forEach(structureSeed -> {
for(long j = 0; j < (1L << 16); j++) {
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 j = 0; j < (1L << 16); j++) {
long worldSeed = (j << 48) | structureSeed;
boolean goodSeed = true;
FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed);
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1];
for(BiomeData data : this.biomeCache) {
if (!data.test(fakeBiomeSource)) {
if (!data.test(worldSeed, sampler)) {
goodSeed = false;
break;
}
@@ -154,7 +216,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."));
@@ -163,14 +225,16 @@ public class SeedCracker implements ModInitializer {
}
} else if(this.worldSeeds != null && biomeData != null) {
this.worldSeeds.removeIf(worldSeed -> {
FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed);
return !biomeData.test(fakeBiomeSource);
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1];
return !biomeData.test(worldSeed, sampler);
});
} else if(this.worldSeeds != null) {
this.worldSeeds.removeIf(worldSeed -> {
for(BiomeData data: this.biomeCache) {
FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed);
if(!data.test(fakeBiomeSource))return true;
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1];
if(!biomeData.test(worldSeed, sampler))return true;
}
return false;
@@ -228,7 +292,6 @@ public class SeedCracker implements ModInitializer {
writer.close();*/
}
/*
private static List<ChunkPos> initialize(long worldSeed) {
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[0];
@@ -265,10 +328,8 @@ public class SeedCracker implements ModInitializer {
}
return startPositions;
}./
}
//CHECK NEW 1.15 SAMPLER
/*
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;
@@ -293,6 +354,6 @@ public class SeedCracker implements ModInitializer {
}
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.source.VoronoiBiomeAccessType;
import net.minecraft.world.biome.layer.BiomeLayerSampler;
public class BiomeData {
@@ -25,20 +25,8 @@ public class BiomeData {
this(x, z, Registry.BIOME.get(biomeId));
}
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;
public boolean test(long worldSeed, BiomeLayerSampler sampler) {
return sampler.sample(this.x, this.z) == 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;
@@ -1,49 +0,0 @@
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);
}
}
@@ -9,11 +9,11 @@ public class StructureData {
private int regionZ;
private int offsetX;
private int offsetZ;
private FeatureType featureType;
private Feature feature;
public StructureData(ChunkPos chunkPos, FeatureType featureType) {
this.featureType = featureType;
this.featureType.build(this, chunkPos);
public StructureData(ChunkPos chunkPos, Feature feature) {
this.feature = feature;
this.feature.build(this, chunkPos);
}
public int getRegionX() {
@@ -33,15 +33,15 @@ public class StructureData {
}
public int getSalt() {
return this.featureType.salt;
return this.feature.salt;
}
public FeatureType getFeatureType() {
return this.featureType;
public Feature getFeature() {
return this.feature;
}
public boolean test(ChunkRandom rand) {
return this.featureType.test(rand, this.offsetX, this.offsetZ);
return this.feature.test(rand, this.offsetX, this.offsetZ);
}
@Override
@@ -50,17 +50,17 @@ public class StructureData {
if(obj instanceof StructureData) {
StructureData structureData = ((StructureData)obj);
return structureData.regionX == this.regionX && structureData.regionZ == this.regionZ && structureData.featureType == this.featureType;
return structureData.regionX == this.regionX && structureData.regionZ == this.regionZ && structureData.feature == this.feature;
}
return false;
}
public abstract static class FeatureType {
public abstract static class Feature {
public final int salt;
public final int distance;
public FeatureType(int salt, int distance) {
public Feature(int salt, int distance) {
this.salt = salt;
this.distance = distance;
}
@@ -89,56 +89,56 @@ public class StructureData {
public abstract boolean test(ChunkRandom rand, int x, int z);
}
public static final FeatureType DESERT_PYRAMID = new FeatureType(14357617, 32) {
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 FeatureType IGLOO = new FeatureType(14357618, 32) {
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 FeatureType JUNGLE_TEMPLE = new FeatureType(14357619, 32) {
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 FeatureType SWAMP_HUT = new FeatureType(14357620, 32) {
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 FeatureType OCEAN_RUIN = new FeatureType(14357621, 16) {
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 FeatureType SHIPWRECK = new FeatureType(165745295, 16) {
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 FeatureType PILLAGER_OUTPOST = new FeatureType(165745296, 32) {
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 FeatureType END_CITY = new FeatureType(10387313, 20) {
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
@@ -146,7 +146,7 @@ public class StructureData {
}
};
public static final FeatureType OCEAN_MONUMENT = new FeatureType(10387313, 32) {
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
@@ -154,14 +154,14 @@ public class StructureData {
}
};
public static final FeatureType BURIED_TREASURE = new FeatureType(10387320, 1) {
public static final Feature BURIED_TREASURE = new Feature(10387320, 1) {
@Override
public boolean test(ChunkRandom rand, int x, int z) {
return rand.nextFloat() < 0.01f;
return rand.nextFloat() < 0.1f;
}
};
public static final FeatureType WOODLAND_MANSION = new FeatureType(10387319, 80) {
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
@@ -1,38 +1,30 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.cracker.population.DecoratorData;
import kaptainwutax.seedcracker.SeedCracker;
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> bruteforceRegion(int pillarSeed, int region, long size, List<StructureData> structureDataList, List<DecoratorData> decoratorDataList) {
List<Long> result = new ArrayList<>();
public List<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<PopulationData> populationDataList, List<Long> structureSeeds) {
ChunkRandom chunkRandom = new ChunkRandom();
long start = region * size;
long end = start + size;
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;
@@ -43,44 +35,16 @@ public class TimeMachine {
if(!structureData.test(chunkRandom))goodSeed = false;
}
for(DecoratorData decoratorData : decoratorDataList) {
for(PopulationData populationData: populationDataList) {
if(!goodSeed)break;
if(!decoratorData.test(structureSeed))goodSeed = false;
if(!populationData.test(structureSeed))goodSeed = false;
}
if(goodSeed) {
result.add(structureSeed);
structureSeeds.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;
}
@@ -95,8 +59,4 @@ public class TimeMachine {
return currentSeed;
}
public void stop() {
this.isRunning = false;
}
}
@@ -1,56 +0,0 @@
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 DecoratorData {
public class DungeonData extends PopulationData {
public static LCG REVERSE_SKIP = Rand.JAVA_LCG.combine(-1);
public static LCG Y_START_SKIP = Rand.JAVA_LCG.combine(2);
@@ -28,26 +28,33 @@ public class DungeonData extends DecoratorData {
}
@Override
public boolean testDecorator(Rand rand) {
public boolean testDecorator(long decoratorSeed) {
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++) {
int x = rand.nextInt(16);
int z = rand.nextInt(16);
int y = rand.nextInt(256);
currentSeed = i == 0 ? Y_START_SKIP.nextSeed(currentSeed) : Y_SKIP.nextSeed(currentSeed);
if(y == start.getY() && x == start.getX() && z == start.getZ()) {
return true;
if(currentSeed >> 40 == start.getY()) {
valid = true;
break;
}
rand.nextInt(2);
rand.nextInt(2);
}
return false;
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;
}
}
@@ -10,7 +10,7 @@ import net.minecraft.world.gen.decorator.Decorator;
import java.util.List;
import java.util.stream.Collectors;
public class EmeraldOreData extends DecoratorData {
public class EmeraldOreData extends PopulationData {
public static final LCG[] SKIP = {
Rand.JAVA_LCG.combine(0),
@@ -30,18 +30,19 @@ public class EmeraldOreData extends DecoratorData {
}
@Override
public boolean testDecorator(Rand rand) {
public boolean testDecorator(long decoratorSeed) {
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 z = rand.nextInt(16);
int y = rand.nextInt(28) + 4;
int z = rand.nextInt(16);
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 DecoratorData {
public class EndGatewayData extends PopulationData {
private int xOffset;
private int zOffset;
@@ -20,7 +20,9 @@ public class EndGatewayData extends DecoratorData {
}
@Override
public boolean testDecorator(Rand rand) {
public boolean testDecorator(long decoratorSeed) {
Rand rand = new Rand(decoratorSeed, false);
if(rand.nextInt(700) != 0)return false;
if(rand.nextInt(16) != this.xOffset)return false;
if(rand.nextInt(16) != this.zOffset)return false;
@@ -0,0 +1,104 @@
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;
}
}
}
@@ -9,7 +9,6 @@ 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;
@@ -30,11 +29,6 @@ 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.getStateManager().getStates());
this.targetBlockStates.addAll(block.getStateFactory().getStates());
}
public BlockFinder(World world, ChunkPos chunkPos, BlockState... blockStates) {
@@ -3,6 +3,7 @@ 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);
@@ -24,8 +24,9 @@ public abstract class Finder {
static {
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
for(int y = 0; y < 256; y++) {
for(int y = 0; y < 256; y++) {
for(int z = 0; z < 16; z++) {
BlockPos pos = new BlockPos(x, y, z);
if(y < 16)SUB_CHUNK_POSITIONS.add(pos);
CHUNK_POSITIONS.add(pos);
@@ -75,7 +75,6 @@ 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,8 +1,6 @@
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;
@@ -42,12 +40,9 @@ public class FinderQueue {
});
}
public void renderFinders(MatrixStack matrixStack) {
public void renderFinders() {
if(this.renderType == RenderType.OFF)return;
RenderSystem.pushMatrix();
RenderSystem.multMatrix(matrixStack.peek().getModel());
GlStateManager.disableTexture();
//Makes it render through blocks.
@@ -61,7 +56,11 @@ public class FinderQueue {
}
});
RenderSystem.popMatrix();
GlStateManager.enableTexture();
if(this.renderType == RenderType.XRAY) {
GlStateManager.enableDepthTest();
}
}
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().onDecoratorData(new DungeonData(this.chunkPos, biome, starts, floorCallsList))) {
if(SeedCracker.get().onPopulationData(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().onDecoratorData(new EndGatewayData(this.chunkPos, biome, pos, height))) {
if(SeedCracker.get().onPopulationData(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,8 +21,6 @@ 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;
});
@@ -41,7 +39,7 @@ public class EmeraldOreFinder extends BlockFinder {
List<BlockPos> result = super.findInChunk();
if(!result.isEmpty() && SeedCracker.get().onDecoratorData(new EmeraldOreData(this.chunkPos, biome, result))) {
if(!result.isEmpty() && SeedCracker.get().onPopulationData(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)));
});
@@ -13,9 +13,7 @@ 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;
@@ -25,6 +23,7 @@ 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;
@@ -36,28 +35,27 @@ public class MansionFinder extends Finder {
public MansionFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos);
for(Direction direction: Direction.values()) {
PieceFinder finder = new PieceFinder(world, chunkPos, direction, this.size);
Direction.Type.HORIZONTAL.forEach(direction -> {
PieceFinder finder = new PieceFinder(world, chunkPos, direction, 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 -> {
@@ -82,26 +80,12 @@ 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();
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);
//TODO: Finish this.
}
@Override
@@ -18,7 +18,7 @@ import java.util.Map;
public class PieceFinder extends Finder {
protected Map<BlockPos, BlockState> structure = new LinkedHashMap<>();
private BlockBox boundingBox;
private MutableIntBoundingBox 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 BlockBox(
this.boundingBox = new MutableIntBoundingBox(
0, 0, 0,
size.getX() - 1, size.getY() - 1, size.getZ() - 1
);
} else {
this.boundingBox = new BlockBox(
this.boundingBox = new MutableIntBoundingBox(
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 + 120;
int y = this.rotation.ordinal() * 10 + this.mirror.ordinal() * 20 + 100;
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(entry.getValue() != null && !state.getBlock().equals(entry.getValue().getBlock())) {
if(!state.getBlock().equals(entry.getValue().getBlock())) {
found = false;
break;
}
@@ -200,6 +200,10 @@ 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),
@@ -207,11 +211,6 @@ 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);
}
@@ -220,7 +219,6 @@ public class PieceFinder extends Finder {
state = state.rotate(this.rotation);
}
this.structure.put(pos, state);
}
}
@@ -1,210 +0,0 @@
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
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), StructureData.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,15 +1,14 @@
package kaptainwutax.seedcracker.mixin;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.finder.FinderQueue;
import kaptainwutax.seedcracker.SeedCracker;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.concurrent.Executors;
@Mixin(ClientWorld.class)
public abstract class ClientWorldMixin {
@@ -18,11 +17,8 @@ public abstract class ClientWorldMixin {
private void disconnect(CallbackInfo ci) {
SeedCracker.get().clear();
FinderQueue.get().clear();
}
@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);
FinderQueue.SERVICE.shutdown();
FinderQueue.SERVICE = Executors.newFixedThreadPool(5);
}
}
@@ -2,7 +2,6 @@ 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;
@@ -11,14 +10,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
public abstract class GameRendererMixin {
@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("HEAD"))
private void renderCenterStart(float delta, long time, CallbackInfo ci) {
RenderQueue.get().setTrackRender(true);
}
@Inject(method = "renderWorld", at = @At("TAIL"))
private void renderWorldFinish(float delta, long time, MatrixStack matrixStack, CallbackInfo ci) {
RenderQueue.get().setTrackRender(null);
@Inject(method = "renderCenter", at = @At("TAIL"))
private void renderCenterFinish(float delta, long time, CallbackInfo ci) {
RenderQueue.get().setTrackRender(false);
}
}
@@ -1,7 +1,6 @@
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;
@@ -25,10 +24,6 @@ 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;
@@ -33,7 +33,7 @@ public class Line extends Renderer {
Vec3d camPos = this.mc.gameRenderer.getCamera().getPos();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
BufferBuilder buffer = tessellator.getBufferBuilder();
//This is how thick the line is.
GlStateManager.lineWidth(2.0f);
@@ -48,16 +48,18 @@ public class Line extends Renderer {
}
protected void putVertex(BufferBuilder buffer, Vec3d camPos, Vec3d pos) {
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();
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();
}
}
}
@@ -1,22 +1,19 @@
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<Consumer<MatrixStack>>> typeRunnableMap = new HashMap<>();
private MatrixStack matrixStack = null;
private Map<String, List<Runnable>> typeRunnableMap = new HashMap<>();
private boolean trackRender = false;
public static RenderQueue get() {
return INSTANCE;
}
public void add(String type, Consumer<MatrixStack> runnable) {
public void add(String type, Runnable runnable) {
Objects.requireNonNull(type);
Objects.requireNonNull(runnable);
@@ -24,11 +21,11 @@ public class RenderQueue {
this.typeRunnableMap.put(type, new ArrayList<>());
}
List<Consumer<MatrixStack>> runnableList = this.typeRunnableMap.get(type);
List<Runnable> runnableList = this.typeRunnableMap.get(type);
runnableList.add(runnable);
}
public void remove(String type, Consumer<MatrixStack> runnable) {
public void remove(String type, Runnable runnable) {
Objects.requireNonNull(type);
Objects.requireNonNull(runnable);
@@ -36,17 +33,17 @@ public class RenderQueue {
return;
}
List<Consumer<MatrixStack>> runnableList = this.typeRunnableMap.get(type);
List<Runnable> runnableList = this.typeRunnableMap.get(type);
runnableList.remove(runnable);
}
public void setTrackRender(MatrixStack matrixStack) {
this.matrixStack = matrixStack;
public void setTrackRender(boolean flag) {
this.trackRender = flag;
}
public void onRender(String type) {
if(this.matrixStack == null || !this.typeRunnableMap.containsKey(type))return;
this.typeRunnableMap.get(type).forEach(r -> r.accept(this.matrixStack));
if(!this.trackRender || !this.typeRunnableMap.containsKey(type))return;
this.typeRunnableMap.get(type).forEach(Runnable::run);
}
}
@@ -1,10 +1,14 @@
package kaptainwutax.seedcracker.util;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.TextFormat;
import net.minecraft.client.util.TextComponentUtil;
import net.minecraft.text.Texts;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.text.LiteralText;
import static net.minecraft.util.Formatting.RED;
import static net.minecraft.util.Formatting.YELLOW;
public class Log {
public static void debug(String message) {
@@ -19,7 +23,7 @@ public class Log {
PlayerEntity player = getPlayer();
if(player != null) {
player.addChatMessage(new LiteralText(TextFormat.YELLOW + message), false);
player.addChatMessage(new LiteralText(YELLOW + message), false);
}
}
@@ -27,7 +31,7 @@ public class Log {
PlayerEntity player = getPlayer();
if(player != null) {
player.addChatMessage(new LiteralText(TextFormat.RED + message), false);
player.addChatMessage(new LiteralText(RED + message), false);
}
}
@@ -11,11 +11,12 @@ public class PosIterator {
Set<BlockPos> result = new HashSet<>();
for(int x = start.getX(); x <= end.getX(); x++) {
for(int z = start.getZ(); z <= end.getZ(); z++) {
for(int y = start.getY(); y <= end.getY(); y++) {
result.add(new BlockPos(x, y, z));
for(int y = start.getY(); y <= end.getY(); y++) {
for(int z = start.getZ(); z <= end.getZ(); z++) {
result.add(new BlockPos(x, y, z));
}
}
}
}
return result;
+1 -1
View File
@@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"id": "seedcracker",
"version": "0.0.2",
"version": "0.0.1",
"name": "Seed Cracker",
"description": "This is an example description! Tell everyone what your mod is about!",