16 Commits

Author SHA1 Message Date
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
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
Unknown f9d2e3d01b bump to 0.0.2 2019-12-15 14:27:53 -05:00
Unknown f9f3c88cfd updated decorator data to use rand instead of seed 2019-12-15 09:54:03 -05:00
Unknown 235fff9426 fixed render OFF disabling hand rendering 2019-12-15 09:53:41 -05:00
Unknown 7a49baa19c removed redundant super 2019-12-14 16:45:28 -05:00
Unknown 10bb559a1e updated mansion finder 2019-12-14 16:45:19 -05:00
Unknown b86892c10a removed water-logging check for shipwrecks 2019-12-14 16:45:03 -05:00
Unknown 525d67f0f1 added shipwreck finder 2019-12-14 14:45:43 -05:00
Unknown 118e056c06 optimized search range of emerald ore 2019-12-14 14:45:26 -05:00
41 changed files with 661 additions and 557 deletions
+33 -1
View File
@@ -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
+1 -1
View File
@@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx1G
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
@@ -3,16 +3,13 @@ package kaptainwutax.seedcracker;
import io.netty.util.internal.ConcurrentSet;
import kaptainwutax.seedcracker.cracker.*;
import kaptainwutax.seedcracker.cracker.population.DecoratorData;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.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.ChunkPos;
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.LevelProperties;
import java.util.ArrayList;
import java.util.List;
@@ -22,6 +19,8 @@ public class SeedCracker implements ModInitializer {
private static final SeedCracker INSTANCE = new SeedCracker();
public long hashedWorldSeed = -1;
public List<Long> worldSeeds = null;
public Set<Long> structureSeeds = null;
public List<Integer> pillarSeeds = null;
@@ -31,21 +30,18 @@ public class SeedCracker implements ModInitializer {
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();
}
private void checkWorldSeed(long worldSeed, ChunkPos pos) {
StrongholdFeature.Start start = new StrongholdFeature.Start(Feature.STRONGHOLD, pos.x, pos.z, BlockBox.empty(), 0, worldSeed);
}
public static SeedCracker get() {
return INSTANCE;
}
public void clear() {
this.hashedWorldSeed = -1;
this.worldSeeds = null;
this.structureSeeds = null;
this.pillarSeeds = null;
@@ -101,9 +97,8 @@ public class SeedCracker implements ModInitializer {
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);
@@ -134,6 +129,27 @@ public class SeedCracker implements ModInitializer {
if(this.worldSeeds == null && this.structureSeeds != null && this.biomeCache.size() >= 5) {
this.worldSeeds = new ArrayList<>();
if(this.hashedWorldSeed != -1) {
Log.warn("SHA2 seed was found.");
Log.warn("Looking for world seeds with hash [" + this.hashedWorldSeed + "].");
for(long structureSeed: this.structureSeeds) {
for(long j = 0; j < (1L << 16); j++) {
long worldSeed = (j << 48) | structureSeed;
long hash = LevelProperties.sha256Hash(worldSeed);
if(hash == this.hashedWorldSeed) {
this.worldSeeds.add(worldSeed);
Log.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds."));
return added;
}
}
}
Log.error("Finished search with no seeds, reverting to biomes.");
}
Log.warn("Looking for world seeds with " + this.biomeCache.size() + " biomes.");
this.structureSeeds.forEach(structureSeed -> {
@@ -144,7 +160,7 @@ public class SeedCracker implements ModInitializer {
FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed);
for(BiomeData data : this.biomeCache) {
if (!data.test(fakeBiomeSource)) {
if(!data.test(fakeBiomeSource)) {
goodSeed = false;
break;
}
@@ -180,119 +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;
}./
//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;
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;
}*/
}
@@ -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 FeatureType featureType;
public StructureData(ChunkPos chunkPos, FeatureType featureType) {
this.featureType = featureType;
this.featureType.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.featureType.salt;
}
public FeatureType getFeatureType() {
return this.featureType;
}
public boolean test(ChunkRandom rand) {
return this.featureType.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.featureType == this.featureType;
}
return false;
}
public abstract static class FeatureType {
public final int salt;
public final int distance;
public FeatureType(int salt, int distance) {
this.salt = salt;
this.distance = distance;
}
public void build(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 FeatureType DESERT_PYRAMID = new FeatureType(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) {
@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) {
@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) {
@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) {
@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) {
@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) {
@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) {
@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 FeatureType OCEAN_MONUMENT = new FeatureType(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 FeatureType BURIED_TREASURE = new FeatureType(10387320, 1) {
@Override
public boolean test(ChunkRandom rand, int x, int z) {
return rand.nextFloat() < 0.01f;
}
};
public static final FeatureType WOODLAND_MANSION = new FeatureType(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;
}
};
}
@@ -1,10 +1,10 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.cracker.population.DecoratorData;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.util.Log;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
import net.minecraft.world.gen.ChunkRandom;
import java.util.ArrayList;
import java.util.List;
@@ -27,7 +27,7 @@ public class TimeMachine {
public List<Long> bruteforceRegion(int pillarSeed, int region, long size, List<StructureData> structureDataList, List<DecoratorData> decoratorDataList) {
List<Long> result = new ArrayList<>();
ChunkRandom chunkRandom = new ChunkRandom();
Rand rand = new Rand(0L);
long start = region * size;
long end = start + size;
@@ -38,9 +38,7 @@ public class TimeMachine {
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(DecoratorData decoratorData : decoratorDataList) {
@@ -2,19 +2,9 @@ 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 DecoratorData {
@@ -39,7 +29,7 @@ public abstract class DecoratorData {
decoratorSeed += salt;
decoratorSeed ^= Rand.JAVA_LCG.multiplier;
decoratorSeed &= Rand.JAVA_LCG.modulo - 1;
return this.testDecorator(decoratorSeed);
return this.testDecorator(new Rand(decoratorSeed, false));
}
public long getPopulationSeed(long structureSeed, int x, int z) {
@@ -49,7 +39,7 @@ public abstract class DecoratorData {
return (long)x * a + (long)z * b ^ structureSeed;
}
public abstract boolean testDecorator(long decoratorSeed);
public abstract boolean testDecorator(Rand rand);
@Override
public boolean equals(Object obj) {
@@ -63,42 +53,4 @@ public abstract class DecoratorData {
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;
}
}
}
@@ -28,9 +28,8 @@ public class DungeonData extends DecoratorData {
}
@Override
public boolean testDecorator(long decoratorSeed) {
public boolean testDecorator(Rand rand) {
if(this.starts.isEmpty())return true;
Rand rand = new Rand(decoratorSeed, false);
//TODO: This currently only supports 1 dungeon per chunk.
BlockPos start = this.starts.get(0);
@@ -30,13 +30,12 @@ public class EmeraldOreData extends DecoratorData {
}
@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++) {
@@ -20,9 +20,7 @@ public class EndGatewayData extends DecoratorData {
}
@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;
@@ -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;
}
}
@@ -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);
@@ -54,16 +54,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),
@@ -43,12 +43,11 @@ public class FinderQueue {
}
public void renderFinders(MatrixStack matrixStack) {
if(this.renderType == RenderType.OFF)return;
RenderSystem.pushMatrix();
RenderSystem.multMatrix(matrixStack.peek().getModel());
//System.out.println("rendering");
if(this.renderType == RenderType.OFF)return;
GlStateManager.disableTexture();
//Makes it render through blocks.
@@ -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;
});
@@ -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)));
}
@@ -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();
}
}
@@ -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 {
@@ -60,4 +61,12 @@ public class Line extends Renderer {
).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);
}
}
@@ -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 -1
View File
@@ -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!",