various additions

This commit is contained in:
Unknown
2019-12-06 20:25:41 -05:00
parent cbc59639c3
commit 7a3ab77769
38 changed files with 1099 additions and 331 deletions
+3 -3
View File
@@ -4,8 +4,8 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/use
minecraft_version=1.14.4
yarn_mappings=1.14.4+build.12
loader_version=0.6.2+build.166
yarn_mappings=1.14.4+build.15
loader_version=0.7.2+build.174
# Mod Properties
mod_version = 1.0.0
@@ -14,4 +14,4 @@ org.gradle.jvmargs=-Xmx1G
# Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.3.2+build.218-1.14
fabric_version=0.4.1+build.245-1.14
@@ -1,96 +0,0 @@
package kaptainwutax.seedcracker;
import com.mojang.blaze3d.platform.GlStateManager;
import io.netty.util.internal.ConcurrentSet;
import kaptainwutax.seedcracker.finder.*;
import kaptainwutax.seedcracker.util.FinderBuilder;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FinderQueue {
private final static FinderQueue INSTANCE = new FinderQueue();
public static final ExecutorService SERVICE = Executors.newFixedThreadPool(5);
public RenderType renderType = RenderType.XRAY;
private List<FinderBuilder> finderBuilders = new ArrayList<>();
private Set<Finder> activeFinders = new ConcurrentSet<>();
private FinderQueue() {
this.clear();
}
public static FinderQueue get() {
return INSTANCE;
}
public void onChunkData(World world, ChunkPos chunkPos) {
this.finderBuilders.forEach(finderBuilder -> {
SERVICE.submit(() -> {
List<Finder> finders = finderBuilder.build(world, chunkPos);
finders.forEach(finder -> {
if (finder.isValidDimension(finder.getWorld().dimension.getType())) {
finder.findInChunk();
if(!finder.isUseless()) {
this.activeFinders.add(finder);
}
}
});
});
});
}
public void renderFinders() {
if(this.renderType == RenderType.OFF)return;
GlStateManager.disableTexture();
//Makes it render through blocks.
if(this.renderType == RenderType.XRAY) {
GlStateManager.disableDepthTest();
}
this.activeFinders.forEach(finder -> {
if(finder.shouldRender()) {
finder.render();
}
});
GlStateManager.enableTexture();
if(this.renderType == RenderType.XRAY) {
GlStateManager.enableDepthTest();
}
}
public void clear() {
this.activeFinders.clear();
this.finderBuilders.clear();
this.finderBuilders.add(DungeonFinder::create);
this.finderBuilders.add(BuriedTreasureFinder::create);
this.finderBuilders.add(SwampHutFinder::create);
this.finderBuilders.add(DesertTempleFinder::create);
this.finderBuilders.add(JungleTempleFinder::create);
this.finderBuilders.add(EndPillarsFinder::create);
this.finderBuilders.add(BiomeFinder::create);
this.finderBuilders.add(OceanMonumentFinder::create);
this.finderBuilders.add(EndCityFinder::create);
this.finderBuilders.add(IglooFinder::create);
//this.finderBuilders.add(DiamondOreFinder::create);
//this.finderBuilders.add(InfestedStoneOreFinder::create);
}
public enum RenderType {
OFF, ON, XRAY
}
}
@@ -1,21 +1,31 @@
package kaptainwutax.seedcracker;
import com.google.common.collect.Lists;
import kaptainwutax.seedcracker.cracker.*;
import kaptainwutax.seedcracker.finder.FinderQueue;
import kaptainwutax.seedcracker.render.RenderQueue;
import kaptainwutax.seedcracker.util.Rand;
import net.fabricmc.api.ModInitializer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MutableIntBoundingBox;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import net.minecraft.world.biome.layer.BiomeLayerSampler;
import net.minecraft.world.biome.layer.BiomeLayers;
import net.minecraft.world.biome.source.BiomeSourceType;
import net.minecraft.world.gen.ChunkRandom;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.StrongholdFeature;
import net.minecraft.world.level.LevelGeneratorType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
public class SeedCracker implements ModInitializer {
@@ -31,9 +41,54 @@ public class SeedCracker implements ModInitializer {
private List<PopulationData> populationCache = new ArrayList<>();
private List<BiomeData> biomeCache = new ArrayList<>();
@Override
@Override
public void onInitialize() {
RenderQueue.get().add("hand", FinderQueue.get()::renderFinders);
DecoratorCache.get().initialize();
/*
System.out.println("FETCHING SEEDS============");
long structureSeed = 29131954246896L;
ChunkPos chunkPos = new ChunkPos(117, 23);
for(long j = 0; j < (1L << 16); j++) {
long worldSeed = (j << 48) | structureSeed;
if(initialize(worldSeed).contains(chunkPos)) {
System.out.println(worldSeed);
this.checkWorldSeed(worldSeed, chunkPos);
}
}
System.out.println("FETCHING SEEDS============");
*/
/*
System.out.println(9348141881871L ^ Rand.JAVA_LCG.multiplier);
DungeonData data = new DungeonData(new ChunkPos(18, 8), Biomes.JUNGLE, new ArrayList<>(), new ArrayList<>());
data.test(-2418316773073950375L);
try {
BufferedWriter writer = new BufferedWriter(new FileWriter("kaktoos14.txt"));
for(int i = 0; i < (1 << 16); i++) {
long worldSeed = 9368770777595L | ((long)i << 48);
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1];
if(sampler.sample(8, 8) == Biomes.DESERT) {
writer.write(worldSeed + "\n");
}
}
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}*/
}
private void checkWorldSeed(long worldSeed, ChunkPos pos) {
StrongholdFeature.Start start = new StrongholdFeature.Start(Feature.STRONGHOLD, pos.x, pos.z, Biomes.PLAINS, MutableIntBoundingBox.empty(), 0, worldSeed);
}
public static SeedCracker get() {
@@ -46,6 +101,7 @@ public class SeedCracker implements ModInitializer {
this.pillarSeeds = null;
this.structureCache.clear();
this.biomeCache.clear();
this.populationCache.clear();
}
public synchronized boolean onPillarData(PillarData pillarData) {
@@ -75,12 +131,13 @@ public class SeedCracker implements ModInitializer {
added = true;
}
if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() >= 3) {
if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() + this.populationCache.size() >= 5) {
this.structureSeeds = new ArrayList<>();
LOG.warn("Looking for structure seeds with " + this.structureCache.size() + " structure features.");
LOG.warn("Looking for structure seeds with " + this.populationCache.size() + " population features.");
this.pillarSeeds.forEach(pillarSeed -> {
timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.structureSeeds);
timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.populationCache, this.structureSeeds);
});
if(this.structureSeeds.size() > 0) {
@@ -113,37 +170,7 @@ public class SeedCracker implements ModInitializer {
added = true;
}
if(this.worldSeeds == null && this.structureSeeds != null && this.populationCache.size() >= 4) {
this.worldSeeds = new ArrayList<>();
LOG.warn("Looking for world seeds with " + this.populationCache.size() + " decorators.");
for(int i = 0; i < this.structureSeeds.size(); i++) {
SeedCracker.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;
for(PopulationData data: this.populationCache) {
if(!data.test(worldSeed)) {
goodSeed = false;
break;
}
}
if(goodSeed) {
this.worldSeeds.add(worldSeed);
}
}
}
LOG.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds."));
} else if(this.worldSeeds != null && populationData != null) {
this.worldSeeds.removeIf(worldSeed -> !populationData.test(worldSeed));
}
this.onStructureData(null);
return added;
}
@@ -209,8 +236,13 @@ public class SeedCracker implements ModInitializer {
return added;
}
public static void main(String[] args) {
Random rand = new Random(1234L);
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);
@@ -220,7 +252,100 @@ public class SeedCracker implements ModInitializer {
return new BlockPos(int_2, int_3, int_4);
}).forEach(pos -> {
System.out.println("Populating " + pos);
});
});*/
/*
System.out.println(validSeed(65867021031296932L));
BufferedReader reader = new BufferedReader(new FileReader("run/seeds.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("run/kaktoos14.txt"));
while(reader.ready()) {
long seed = Long.parseLong(reader.readLine().split(Pattern.quote(" "))[0]);
seed ^= Rand.JAVA_LCG.multiplier;
seed -= 60007;
writer.write(seed + "===========================================\n");
for(int i = 0; i < (1 << 16); i++) {
long worldSeed = seed | ((long)i << 48);
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[1];
if(sampler.sample(8, 8) == Biomes.DESERT) {
writer.write(worldSeed + "\n");
}
}
writer.flush();
}
writer.close();*/
}
private static List<ChunkPos> initialize(long worldSeed) {
BiomeLayerSampler sampler = BiomeLayers.build(worldSeed, LevelGeneratorType.DEFAULT,
BiomeSourceType.VANILLA_LAYERED.getConfig().getGeneratorSettings())[0];
List<ChunkPos> startPositions = new ArrayList<>();
List<Biome> validBiomes = Lists.newArrayList();
Iterator biomeIterator = Registry.BIOME.iterator();
while(biomeIterator.hasNext()) {
Biome biome = (Biome)biomeIterator.next();
if(biome != null && biome.hasStructureFeature(Feature.STRONGHOLD)) {
validBiomes.add(biome);
}
}
Random rand = new Random(worldSeed);
double randomRadian = rand.nextDouble() * Math.PI * 2.0D;
//Actually 128, but we don't care about all of them.
for(int i = 0; i < 3; ++i) {
double double_2 = 128.0D + (rand.nextDouble() - 0.5D) * 80.0D;
int x = (int)Math.round(Math.cos(randomRadian) * double_2);
int z = (int)Math.round(Math.sin(randomRadian) * double_2);
BlockPos locatedPos = locateBiome(sampler, (x << 4) + 8, (z << 4) + 8, 112, validBiomes, rand);
if(locatedPos != null) {
x = locatedPos.getX() >> 4;
z = locatedPos.getZ() >> 4;
}
startPositions.add(new ChunkPos(x, z));
randomRadian += (Math.PI * 2.0D) / 3.0d;
}
return startPositions;
}
public static BlockPos locateBiome(BiomeLayerSampler sampler, int x, int z, int size, List<Biome> validBiomes, Random rand) {
int int_4 = x - size >> 2;
int int_5 = z - size >> 2;
int int_6 = x + size >> 2;
int int_7 = z + size >> 2;
int int_8 = int_6 - int_4 + 1;
int int_9 = int_7 - int_5 + 1;
Biome[] biomeSample = sampler.sample(int_4, int_5, int_8, int_9);
BlockPos pos = null;
int int_10 = 0;
for(int i = 0; i < int_8 * int_9; ++i) {
int int_12 = int_4 + i % int_8 << 2;
int int_13 = int_5 + i / int_8 << 2;
if (validBiomes.contains(biomeSample[i])) {
if(pos == null || rand.nextInt(int_10 + 1) == 0) {
pos = new BlockPos(int_12, 0, int_13);
}
++int_10;
}
}
return pos;
}
}
@@ -2,10 +2,10 @@ package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import kaptainwutax.seedcracker.ClientCommands;
import net.minecraft.client.MinecraftClient;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText;
import net.minecraft.util.Formatting;
import static net.minecraft.server.command.CommandManager.literal;
@@ -16,7 +16,7 @@ public abstract class ClientCommand {
public abstract void build(LiteralArgumentBuilder<ServerCommandSource> builder);
protected final void sendFeedback(String message, boolean overlay) {
MinecraftClient.getInstance().player.addChatMessage(new LiteralText(message), overlay);
MinecraftClient.getInstance().player.addChatMessage(new LiteralText(message).formatted(Formatting.AQUA), overlay);
}
public final void register(CommandDispatcher<ServerCommandSource> dispatcher) {
@@ -1,10 +1,8 @@
package kaptainwutax.seedcracker;
package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import kaptainwutax.seedcracker.command.ClientCommand;
import kaptainwutax.seedcracker.command.RenderCommand;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.command.CommandException;
@@ -21,21 +19,23 @@ public class ClientCommands {
public static final List<ClientCommand> COMMANDS = new ArrayList<>();
public static RenderCommand RENDER;
public static FinderCommand FINDER;
static {
COMMANDS.add(RENDER = new RenderCommand());
COMMANDS.add(FINDER = new FinderCommand());
}
public static void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher) {
COMMANDS.forEach(clientCommand -> clientCommand.register(dispatcher));
}
public static boolean isClientSideCommand(String[] params) {
if(params.length < 2)return false;
if(!PREFIX.equals(params[0]))return false;
public static boolean isClientSideCommand(String[] args) {
if(args.length < 2)return false;
if(!PREFIX.equals(args[0]))return false;
for(ClientCommand command: COMMANDS) {
if(command.getName().equals(params[1])) {
if(command.getName().equals(args[1])) {
return true;
}
}
@@ -63,7 +63,7 @@ public class ClientCommands {
}
/**
* Shoutout to Earthcomputer for this awesome class.
* Magic class by Earthcomputer.
* https://github.com/Earthcomputer/clientcommands/blob/fabric/src/main/java/net/earthcomputer/clientcommands/command/FakeCommandSource.java
* */
public static class FakeCommandSource extends ServerCommandSource {
@@ -0,0 +1,59 @@
package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import kaptainwutax.seedcracker.finder.FinderConfig;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.server.command.ServerCommandSource;
import static net.minecraft.server.command.CommandManager.literal;
public class FinderCommand extends ClientCommand {
@Override
public String getName() {
return "finder";
}
@Override
public void build(LiteralArgumentBuilder<ServerCommandSource> builder) {
for(FinderConfig.Type finderType: FinderConfig.Type.values()) {
builder.then(literal("type")
.executes(context -> this.printFinderType(finderType))
.then(literal(finderType.toString())
.then(literal("ON").executes(context -> this.setFinderType(finderType, true)))
.then(literal("OFF").executes(context -> this.setFinderType(finderType, false))))
);
}
for(FinderConfig.Category finderCategory: FinderConfig.Category.values()) {
builder.then(literal("category")
.executes(context -> this.printFinderCategory(finderCategory))
.then(literal(finderCategory.toString())
.then(literal("ON").executes(context -> this.setFinderCategory(finderCategory, true)))
.then(literal("OFF").executes(context -> this.setFinderCategory(finderCategory, false))))
);
}
}
private int printFinderCategory(FinderConfig.Category finderCategory) {
FinderConfig.Type.getForCategory(finderCategory).forEach(this::printFinderType);
return 0;
}
private int printFinderType(FinderConfig.Type finderType) {
this.sendFeedback("Finder " + finderType + " is set to [" + String.valueOf(FinderQueue.get().finderConfig.getTypeState(finderType)).toUpperCase() + "].", false);
return 0;
}
private int setFinderCategory(FinderConfig.Category finderCategory, boolean flag) {
FinderConfig.Type.getForCategory(finderCategory).forEach(finderType -> this.setFinderType(finderType, flag));
return 0;
}
private int setFinderType(FinderConfig.Type finderType, boolean flag) {
FinderQueue.get().finderConfig.setTypeState(finderType, flag);
this.sendFeedback("Finder " + finderType + " has been set to [" + String.valueOf(flag).toUpperCase() + "].", false);
return 0;
}
}
@@ -1,7 +1,7 @@
package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import kaptainwutax.seedcracker.FinderQueue;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.server.command.ServerCommandSource;
import static net.minecraft.server.command.CommandManager.literal;
@@ -17,10 +17,13 @@ public class RenderCommand extends ClientCommand {
public void build(LiteralArgumentBuilder<ServerCommandSource> builder) {
builder.then(literal("outlines")
.executes(context -> this.printRenderMode())
.then(literal("XRAY").executes(context -> this.setRenderMode(FinderQueue.RenderType.XRAY)))
.then(literal("ON").executes(context -> this.setRenderMode(FinderQueue.RenderType.ON)))
.then(literal("OFF").executes(context -> this.setRenderMode(FinderQueue.RenderType.OFF)))
);
for(FinderQueue.RenderType renderType: FinderQueue.RenderType.values()) {
builder.then(literal("outlines")
.then(literal(renderType.toString()).executes(context -> this.setRenderMode(renderType)))
);
}
}
private int printRenderMode() {
@@ -0,0 +1,69 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.SeedCracker;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.decorator.Decorator;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DecoratedFeatureConfig;
import net.minecraft.world.gen.feature.FeatureConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DecoratorCache {
public static int INVALID = -1;
private static DecoratorCache INSTANCE = new DecoratorCache();
private boolean initialized = false;
private Map<Biome, Map<Decorator<?>, Integer>> decoratorSaltMap = new HashMap<>();
public static DecoratorCache get() {
return INSTANCE;
}
public void initialize() {
Registry.BIOME.forEach(biome -> {
this.decoratorSaltMap.put(biome, new HashMap<>());
for(GenerationStep.Feature genStep: GenerationStep.Feature.values()) {
this.initializeBiomeStep(biome, genStep);
}
});
this.initialized = true;
}
private void initializeBiomeStep(Biome biome, GenerationStep.Feature genStep) {
List<ConfiguredFeature<?>> features = biome.getFeaturesForStep(genStep);
for(int i = 0; i < features.size(); i++) {
FeatureConfig config = features.get(i).config;
if(!(config instanceof DecoratedFeatureConfig))continue;
this.decoratorSaltMap.get(biome).put(((DecoratedFeatureConfig)config).decorator.decorator, i + genStep.ordinal() * 10000);
}
}
public int getSalt(Biome biome, Decorator<?> feature, boolean debug) {
if(!this.initialized) {
this.initialize();
}
Integer salt = this.decoratorSaltMap.get(biome).get(feature);
if(salt == null) {
if(debug) {
SeedCracker.LOG.warn(biome.getClass().getSimpleName() + " does not have decorator " + feature + ".");
}
salt = INVALID;
}
return salt;
}
}
@@ -1,18 +1,20 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.ChunkRandom;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.ArrayList;
import java.util.List;
public class DungeonData extends PopulationData {
public static final Feature DUNGEON = new Feature(GenerationStep.Feature.UNDERGROUND_STRUCTURES, Decorator.DUNGEONS) {};
public static LCG REVERSE_SKIP = Rand.JAVA_LCG.combine(-1);
public static LCG Y_START_SKIP = Rand.JAVA_LCG.combine(2);
public static LCG Y_SKIP = Rand.JAVA_LCG.combine(5);
public static final Integer COBBLESTONE_CALL = 0;
public static final Integer MOSSY_COBBLESTONE_CALL = 1;
@@ -20,28 +22,37 @@ public class DungeonData extends PopulationData {
private final List<List<Integer>> floorCallsList;
public DungeonData(ChunkPos chunkPos, Biome biome, List<BlockPos> starts, List<List<Integer>> floorCallsList) {
super(chunkPos, DUNGEON, biome);
super(chunkPos, Decorator.DUNGEONS, biome);
this.starts = starts;
this.floorCallsList = floorCallsList;
}
@Override
public boolean test(ChunkRandom chunkRandom) {
List<Integer> idsToCheck = new ArrayList<>();
public boolean testDecorator(long decoratorSeed) {
if(this.starts.isEmpty())return false;
//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++) {
BlockPos pos = new BlockPos(chunkRandom.nextInt(16), chunkRandom.nextInt(256), chunkRandom.nextInt(16));
int a = this.starts.indexOf(pos);
if(a != -1)idsToCheck.add(a);
currentSeed = i == 0 ? Y_START_SKIP.nextSeed(currentSeed) : Y_SKIP.nextSeed(currentSeed);
//We assume the dungeon failed, skip 2 calls.
chunkRandom.nextBoolean();
chunkRandom.nextBoolean();
if(currentSeed >> 40 == start.getY()) {
valid = true;
break;
}
}
if(idsToCheck.size() != this.starts.size())return false;
if(!valid)return false;
//TODO: Implement floor calls.
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;
}
@@ -0,0 +1,55 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.List;
import java.util.stream.Collectors;
public class EmeraldOreData extends PopulationData {
public static final LCG[] SKIP = {
Rand.JAVA_LCG.combine(0),
Rand.JAVA_LCG.combine(1),
Rand.JAVA_LCG.combine(2),
Rand.JAVA_LCG.combine(3)
};
private List<BlockPos> starts;
public EmeraldOreData(ChunkPos chunkPos, Biome biome, List<BlockPos> ores) {
super(chunkPos, Decorator.EMERALD_ORE, biome);
this.starts = ores.stream().map(pos -> {
return new BlockPos(pos.getX() & 15, pos.getY(), pos.getZ() & 15);
}).collect(Collectors.toList());
}
@Override
public boolean testDecorator(long decoratorSeed) {
if(this.starts.isEmpty())return false;
//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; i++) {
int x = rand.nextInt(16);
int y = rand.nextInt(28) + 4;
int z = rand.nextInt(16);
if(x == start.getX() && y == start.getY() && z == start.getZ()) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,34 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.util.Rand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.decorator.Decorator;
public class EndGatewayData extends PopulationData {
private int xOffset;
private int zOffset;
private int height;
public EndGatewayData(ChunkPos chunkPos, Biome biome, BlockPos pos, int height) {
super(chunkPos, Decorator.END_GATEWAY, biome);
this.xOffset = pos.getX() & 15;
this.zOffset = pos.getZ() & 15;
this.height = height;
}
@Override
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;
if(rand.nextInt(7) != this.height - 3)return false;
return true;
}
}
@@ -1,5 +1,6 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.util.Rand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
@@ -10,26 +11,44 @@ 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 Feature feature;
private final Decorator<?> decorator;
private final Biome biome;
public PopulationData(ChunkPos chunkPos, Feature feature, Biome biome) {
public PopulationData(ChunkPos chunkPos, Decorator<?> decorator, Biome biome) {
this.chunkPos = chunkPos;
this.feature = feature;
this.decorator = decorator;
this.biome = biome;
}
public final boolean test(long worldSeed) {
ChunkRandom chunkRandom = this.feature.buildRand(worldSeed, this.biome, this.chunkPos);
return this.test(chunkRandom);
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 abstract boolean test(ChunkRandom chunkRandom);
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) {
@@ -37,7 +56,7 @@ public abstract class PopulationData {
if(obj instanceof PopulationData) {
PopulationData populationData = ((PopulationData)obj);
return populationData.chunkPos.equals(this.chunkPos) && populationData.feature == this.feature;
return populationData.chunkPos.equals(this.chunkPos) && populationData.decorator == this.decorator;
}
return false;
@@ -45,6 +64,8 @@ public abstract class PopulationData {
public abstract static class Feature {
private Map<Biome, Long> CACHE = new HashMap<>();
private GenerationStep.Feature genStep;
private Decorator decorator;
@@ -54,6 +75,10 @@ public abstract class PopulationData {
}
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++) {
@@ -65,7 +90,8 @@ public abstract class PopulationData {
BlockPos pos = new BlockPos(chunkPos.getStartX(), 0, chunkPos.getStartZ());
ChunkRandom chunkRandom = new ChunkRandom();
long populationSeed = chunkRandom.setSeed(worldSeed, pos.getX(), pos.getZ());
chunkRandom.setFeatureSeed(populationSeed, i, this.genStep.ordinal());
long seed = chunkRandom.setFeatureSeed(populationSeed, i, this.genStep.ordinal());
CACHE.put(biome, seed ^ Rand.JAVA_LCG.multiplier);
return chunkRandom;
}
}
@@ -6,7 +6,6 @@ import kaptainwutax.seedcracker.util.math.LCG;
import net.minecraft.world.gen.ChunkRandom;
import java.util.List;
import java.util.Set;
public class TimeMachine {
@@ -16,7 +15,7 @@ public class TimeMachine {
}
public List<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<Long> structureSeeds) {
public List<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<PopulationData> populationDataList, List<Long> structureSeeds) {
ChunkRandom chunkRandom = new ChunkRandom();
for(long i = 0; i < (1L << 32); i++) {
@@ -28,13 +27,15 @@ public class TimeMachine {
boolean goodSeed = true;
for(StructureData structureData: structureDataList) {
if(!goodSeed)break;
chunkRandom.setStructureSeed(structureSeed, structureData.getRegionX(),
structureData.getRegionZ(), structureData.getSalt());
if(!structureData.test(chunkRandom))goodSeed = false;
}
if(!structureData.test(chunkRandom)) {
goodSeed = false;
break;
}
for(PopulationData populationData: populationDataList) {
if(!goodSeed)break;
if(!populationData.test(structureSeed))goodSeed = false;
}
if(goodSeed) {
@@ -37,7 +37,7 @@ public class BiomeFinder extends Finder {
}
result.forEach(pos -> {
this.renderers.add(new Cube(pos, new Vector4f(0.0f, 1.0f, 0.0f, 1.0f)));
this.renderers.add(new Cube(pos, new Vector4f(0.05f, 0.2f, 0.125f, 1.0f)));
});
return result;
@@ -0,0 +1,13 @@
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);
this.typeStates.put(Type.MANSION, false);
}
}
@@ -0,0 +1,101 @@
package kaptainwutax.seedcracker.finder;
import kaptainwutax.seedcracker.finder.population.DungeonFinder;
import kaptainwutax.seedcracker.finder.population.EndGatewayFinder;
import kaptainwutax.seedcracker.finder.population.EndPillarsFinder;
import kaptainwutax.seedcracker.finder.population.ore.DiamondOreFinder;
import kaptainwutax.seedcracker.finder.population.ore.EmeraldOreFinder;
import kaptainwutax.seedcracker.finder.population.ore.InfestedStoneOreFinder;
import kaptainwutax.seedcracker.finder.structure.*;
import kaptainwutax.seedcracker.util.FinderBuilder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
public class FinderConfig {
protected Map<Type, Boolean> typeStates = new HashMap<>();
protected Map<Type, ConcurrentLinkedQueue<Finder>> activeFinders = new ConcurrentHashMap<>();
public FinderConfig() {
for(Type type: Type.values()) {
this.typeStates.put(type, true);
}
}
public List<Type> getActiveFinderTypes() {
return this.typeStates.entrySet().stream()
.filter(Map.Entry::getValue)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
public List<Finder> getActiveFinders() {
this.activeFinders.values().forEach(finders -> {
finders.removeIf(Finder::isUseless);
});
return this.activeFinders.values().stream()
.flatMap(Queue::stream).collect(Collectors.toList());
}
public void addFinder(Type type, Finder finder) {
if(finder.isUseless())return;
if(!this.activeFinders.containsKey(type)) {
this.activeFinders.put(type, new ConcurrentLinkedQueue<>());
}
this.activeFinders.get(type).add(finder);
}
public boolean getTypeState(Type type) {
return this.typeStates.get(type);
}
public void setTypeState(Type type, boolean flag) {
this.typeStates.put(type, flag);
}
public enum Category {
STRUCTURES,
BIOMES,
ORES,
OTHERS
}
public enum Type {
BURIED_TREASURE(BuriedTreasureFinder::create, Category.STRUCTURES),
DESERT_TEMPLE(DesertTempleFinder::create, Category.STRUCTURES),
END_CITY(EndCityFinder::create, Category.STRUCTURES),
IGLOO(IglooFinder::create, Category.STRUCTURES),
JUNGLE_TEMPLE(JungleTempleFinder::create, Category.STRUCTURES),
MONUMENT(OceanMonumentFinder::create, Category.STRUCTURES),
SWAMP_HUT(SwampHutFinder::create, Category.STRUCTURES),
MANSION(MansionFinder::create, Category.STRUCTURES),
END_PILLARS(EndPillarsFinder::create, Category.OTHERS),
END_GATEWAY(EndGatewayFinder::create, Category.OTHERS),
DUNGEON(DungeonFinder::create, Category.OTHERS),
DIAMOND_ORE(DiamondOreFinder::create, Category.ORES),
INFESTED_STONE_ORE(InfestedStoneOreFinder::create, Category.ORES),
EMERALD_ORE(EmeraldOreFinder::create, Category.ORES),
BIOME(BiomeFinder::create, Category.BIOMES);
public final FinderBuilder finderBuilder;
private final Category category;
Type(FinderBuilder finderBuilder, Category category) {
this.finderBuilder = finderBuilder;
this.category = category;
}
public static List<Type> getForCategory(Category category) {
return Arrays.stream(values()).filter(type -> type.category == category).collect(Collectors.toList());
}
}
}
@@ -0,0 +1,75 @@
package kaptainwutax.seedcracker.finder;
import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FinderQueue {
private final static FinderQueue INSTANCE = new FinderQueue();
public static ExecutorService SERVICE = Executors.newFixedThreadPool(5);
public RenderType renderType = RenderType.XRAY;
public FinderConfig finderConfig = new DefaultFinderConfig();
private FinderQueue() {
this.clear();
}
public static FinderQueue get() {
return INSTANCE;
}
public void onChunkData(World world, ChunkPos chunkPos) {
this.finderConfig.getActiveFinderTypes().forEach(type -> {
SERVICE.submit(() -> {
List<Finder> finders = type.finderBuilder.build(world, chunkPos);
finders.forEach(finder -> {
if(finder.isValidDimension(world.dimension.getType())) {
this.finderConfig.addFinder(type, finder);
finder.findInChunk();
this.finderConfig.addFinder(type, finder);
}
});
});
});
}
public void renderFinders() {
if(this.renderType == RenderType.OFF)return;
GlStateManager.disableTexture();
//Makes it render through blocks.
if(this.renderType == RenderType.XRAY) {
GlStateManager.disableDepthTest();
}
this.finderConfig.getActiveFinders().forEach(finder -> {
if(finder.shouldRender()) {
finder.render();
}
});
GlStateManager.enableTexture();
if(this.renderType == RenderType.XRAY) {
GlStateManager.enableDepthTest();
}
}
public void clear() {
this.renderType = RenderType.XRAY;
this.finderConfig = new DefaultFinderConfig();
}
public enum RenderType {
OFF, ON, XRAY
}
}
@@ -1,7 +1,9 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.population;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.DungeonData;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.util.PosIterator;
import net.minecraft.block.Block;
@@ -0,0 +1,91 @@
package kaptainwutax.seedcracker.finder.population;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.DecoratorCache;
import kaptainwutax.seedcracker.cracker.EndGatewayData;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.ArrayList;
import java.util.List;
public class EndGatewayFinder extends BlockFinder {
protected static List<BlockPos> SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> {
return false;
});
public EndGatewayFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos, Blocks.END_GATEWAY);
this.searchPositions = SEARCH_POSITIONS;
}
@Override
public List<BlockPos> findInChunk() {
//If no end gateway is supposed to populate in this chunk, return.
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(8, 0, 8));
if(DecoratorCache.get().getSalt(biome, Decorator.END_GATEWAY, false) == DecoratorCache.INVALID) {
return new ArrayList<>();
}
List<BlockPos> result = super.findInChunk();
List<BlockPos> newResult = new ArrayList<>();
result.forEach(pos -> {
int height = this.findHeight(pos);
if(height >= 3 && height <= 9) {
newResult.add(pos);
System.out.println("Height is " + 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)));
}
}
});
return newResult;
}
private int findHeight(BlockPos pos) {
int height = 0;
while(pos.getY() >= 0) {
pos = pos.down();
height++;
BlockState state = this.world.getBlockState(pos);
//Bedrock generates below gateways.
if(state.getBlock() == Blocks.BEDROCK || state.getBlock() != Blocks.END_STONE) {
continue;
}
break;
}
return height;
}
@Override
public boolean isValidDimension(DimensionType dimension) {
return dimension == DimensionType.THE_END;
}
public static List<Finder> create(World world, ChunkPos chunkPos) {
List<Finder> finders = new ArrayList<>();
finders.add(new EndGatewayFinder(world, chunkPos));
return finders;
}
}
@@ -1,7 +1,9 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.population;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.PillarData;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
@@ -45,8 +47,11 @@ public class EndPillarsFinder extends Finder {
if(result.size() == this.bedrockMarkers.length) {
PillarData pillarData = new PillarData(result.stream().map(Vec3i::getY).collect(Collectors.toList()));
result.forEach(pos -> this.renderers.add(new Cube(pos, new Vector4f(0.5f, 0.0f, 0.5f, 1.0f))));
SeedCracker.get().onPillarData(pillarData);
if(SeedCracker.get().onPillarData(pillarData)){
result.forEach(pos -> this.renderers.add(new Cube(pos, new Vector4f(0.5f, 0.0f, 0.5f, 1.0f))));
}
}
return result;
@@ -1,5 +1,6 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.population;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.util.PosIterator;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
@@ -1,6 +1,6 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.finder.Finder;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
@@ -10,14 +10,13 @@ import net.minecraft.world.gen.feature.OreFeatureConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class DiamondOreFinder extends OreFinder {
public class DiamondOreFinder extends SimpleOreFinder {
public static OreFeatureConfig CONFIG = new OreFeatureConfig(OreFeatureConfig.Target.NATURAL_STONE, Blocks.DIAMOND_ORE.getDefaultState(), 8);
protected static List<BlockPos> SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> {
if(pos.getY() > 16)return true;
if(pos.getY() > 16 + 4)return true;
return false;
});
@@ -27,22 +26,8 @@ public class DiamondOreFinder extends OreFinder {
}
@Override
public void findOreVeins(List<Set<BlockPos>> veins) {
List<BlockPos> starts = new ArrayList<>();
for(Set<BlockPos> vein: veins) {
BlockPos oreStart = new BlockPos(
this.findX(vein, OreFinder.HIGHEST),
this.findY(vein, OreFinder.LOWEST) + 3,
this.findZ(vein, OreFinder.HIGHEST)
);
starts.add(oreStart);
}
starts.forEach(start -> {
this.renderers.add(new Cube(start, new Vector4f(1.0f, 1.0f, 1.0f, 1.0f)));
});
public Vector4f getRenderColor() {
return new Vector4f(0.0f, 1.0f, 1.0f, 1.0f);
}
public static List<Finder> create(World world, ChunkPos chunkPos) {
@@ -0,0 +1,57 @@
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.DecoratorCache;
import kaptainwutax.seedcracker.cracker.EmeraldOreData;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.ArrayList;
import java.util.List;
public class EmeraldOreFinder extends BlockFinder {
public EmeraldOreFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos, Blocks.EMERALD_ORE);
}
@Override
public List<BlockPos> findInChunk() {
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(8, 0, 8));
if(DecoratorCache.get().getSalt(biome, Decorator.EMERALD_ORE, false) == DecoratorCache.INVALID) {
return new ArrayList<>();
}
List<BlockPos> result = super.findInChunk();
if(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)));
});
}
return result;
}
@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 EmeraldOreFinder(world, chunkPos));
return finders;
}
}
@@ -1,6 +1,6 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.finder.Finder;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
@@ -10,14 +10,13 @@ import net.minecraft.world.gen.feature.OreFeatureConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class InfestedStoneOreFinder extends OreFinder {
public class InfestedStoneOreFinder extends SimpleOreFinder {
public static OreFeatureConfig CONFIG = new OreFeatureConfig(OreFeatureConfig.Target.NATURAL_STONE, Blocks.INFESTED_STONE.getDefaultState(), 9);
protected static List<BlockPos> SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> {
if(pos.getY() > 70)return true;
protected static List<BlockPos> SEARCH_POSITIONS = Finder.buildSearchPositions(Finder.CHUNK_POSITIONS, pos -> {
if(pos.getY() > 64 + 4)return true;
return false;
});
@@ -27,24 +26,8 @@ public class InfestedStoneOreFinder extends OreFinder {
}
@Override
public void findOreVeins(List<Set<BlockPos>> veins) {
List<BlockPos> starts = new ArrayList<>();
for(Set<BlockPos> vein: veins) {
if(vein.size() != 8)continue;
BlockPos oreStart = new BlockPos(
this.findX(vein, OreFinder.HIGHEST),
this.findY(vein, OreFinder.LOWEST) + 3,
this.findZ(vein, OreFinder.HIGHEST)
);
starts.add(oreStart);
}
starts.forEach(start -> {
this.renderers.add(new Cube(start, new Vector4f(0.0f, 1.0f, 1.0f, 1.0f)));
});
public Vector4f getRenderColor() {
return new Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
}
public static List<Finder> create(World world, ChunkPos chunkPos) {
@@ -0,0 +1,50 @@
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.finder.population.OreFinder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public abstract class SimpleOreFinder extends OreFinder {
public SimpleOreFinder(World world, ChunkPos chunkPos, OreFeatureConfig oreFeatureConfig) {
super(world, chunkPos, oreFeatureConfig);
}
@Override
public void findOreVeins(List<Set<BlockPos>> veins) {
List<BlockPos> starts = new ArrayList<>();
for(Set<BlockPos> vein: veins) {
//This is a semi-accurate estimate.
BlockPos oreStart = new BlockPos(
this.findX(vein, OreFinder.HIGHEST),
this.findY(vein, OreFinder.LOWEST) + 2,
this.findZ(vein, OreFinder.HIGHEST)
);
starts.add(oreStart);
}
//If the start overlaps with another chunk, get rid of it.
starts.removeIf(start -> {
if((start.getX() & 15) == 0 || (start.getX() & 15) == 15)return true;
if((start.getZ() & 15) == 0 || (start.getZ() & 15) == 15)return true;
return false;
});
starts.forEach(start -> {
this.renderers.add(new Cuboid(start.add(-1, -1, -1), start.add(1, 0, 1), this.getRenderColor()));
});
}
public abstract Vector4f getRenderColor();
}
@@ -1,11 +1,14 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.finder.Finder;
import net.minecraft.util.math.BlockPos;
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.StructureFeature;
import java.util.ArrayList;
import java.util.HashMap;
@@ -40,9 +43,17 @@ public abstract class AbstractTempleFinder extends Finder {
}
public List<BlockPos> findInChunkPiece(PieceFinder pieceFinder) {
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(9, 0, 9));
if(!biome.hasStructureFeature(this.getStructureFeature())) {
return new ArrayList<>();
}
return pieceFinder.findInChunk();
}
protected abstract StructureFeature<?> getStructureFeature();
public Map<PieceFinder, List<BlockPos>> findInChunkPieces() {
Map<PieceFinder, List<BlockPos>> result = new HashMap<>();
@@ -1,7 +1,9 @@
package kaptainwutax.seedcracker.finder;
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 net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
@@ -41,6 +43,9 @@ public class BuriedTreasureFinder extends BlockFinder {
CHEST_HOLDERS.add(Blocks.COAL_ORE.getDefaultState());
CHEST_HOLDERS.add(Blocks.IRON_ORE.getDefaultState());
CHEST_HOLDERS.add(Blocks.GOLD_ORE.getDefaultState());
//Ocean can turn stone into gravel.
CHEST_HOLDERS.add(Blocks.GRAVEL.getDefaultState());
}
public BuriedTreasureFinder(World world, ChunkPos chunkPos) {
@@ -1,7 +1,8 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
@@ -12,8 +13,8 @@ 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.gen.feature.Feature;
import net.minecraft.world.gen.feature.StructureFeature;
import java.util.ArrayList;
import java.util.List;
@@ -31,13 +32,6 @@ public class DesertTempleFinder extends AbstractTempleFinder {
List<BlockPos> combinedResult = new ArrayList<>();
result.forEach((pieceFinder, positions) -> {
positions.removeIf(pos -> {
Biome biome = world.getBiome(pos.add(9, 0, 9));
if(!biome.hasStructureFeature(Feature.DESERT_PYRAMID))return true;
return false;
});
combinedResult.addAll(positions);
positions.forEach(pos -> {
@@ -50,6 +44,11 @@ public class DesertTempleFinder extends AbstractTempleFinder {
return combinedResult;
}
@Override
protected StructureFeature<?> getStructureFeature() {
return Feature.DESERT_PYRAMID;
}
@Override
public void buildStructure(PieceFinder finder) {
BlockState blockState_1 = Blocks.SANDSTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.NORTH);
@@ -1,7 +1,8 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
@@ -1,7 +1,8 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
@@ -9,39 +10,52 @@ import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
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.dimension.DimensionType;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.StructureFeature;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class IglooFinder extends Finder {
public class IglooFinder extends AbstractTempleFinder {
protected static List<BlockPos> SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> {
return false;
});
protected List<PieceFinder> finders = new ArrayList<>();
protected final Vec3i size = new Vec3i(7, 5, 8);
public IglooFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos);
Direction.Type.HORIZONTAL.forEach(direction -> {
PieceFinder finder = new PieceFinder(world, chunkPos, direction, size);
super(world, chunkPos, new Vec3i(7, 5, 8));
//Igloos are weird.
this.finders.forEach(finder -> {
finder.searchPositions = SEARCH_POSITIONS;
buildStructure(finder);
this.finders.add(finder);
});
}
private void buildStructure(PieceFinder finder) {
@Override
public List<BlockPos> findInChunk() {
Map<PieceFinder, List<BlockPos>> result = this.findInChunkPieces();
List<BlockPos> combinedResult = new ArrayList<>();
result.forEach((pieceFinder, positions) -> {
combinedResult.addAll(positions);
positions.forEach(pos -> {
if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureData.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)));
}
});
});
return combinedResult;
}
@Override
public void buildStructure(PieceFinder finder) {
BlockState air = Blocks.AIR.getDefaultState();
BlockState snow = Blocks.SNOW_BLOCK.getDefaultState();
BlockState ice = Blocks.ICE.getDefaultState();
@@ -72,37 +86,8 @@ public class IglooFinder extends Finder {
}
@Override
public List<BlockPos> findInChunk() {
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.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)));
}
});
});
return combinedResult;
}
public Map<PieceFinder, List<BlockPos>> findInChunkPieces() {
Map<PieceFinder, List<BlockPos>> result = new HashMap<>();
this.finders.forEach(pieceFinder -> {
result.put(pieceFinder, pieceFinder.findInChunk());
});
return result;
protected StructureFeature<?> getStructureFeature() {
return Feature.IGLOO;
}
@Override
@@ -1,7 +1,8 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.*;
import net.minecraft.block.enums.WallMountLocation;
@@ -12,8 +13,8 @@ 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.gen.feature.Feature;
import net.minecraft.world.gen.feature.StructureFeature;
import java.util.ArrayList;
import java.util.List;
@@ -31,13 +32,6 @@ public class JungleTempleFinder extends AbstractTempleFinder {
List<BlockPos> combinedResult = new ArrayList<>();
result.forEach((pieceFinder, positions) -> {
positions.removeIf(pos -> {
Biome biome = world.getBiome(pos.add(9, 0, 9));
if(!biome.hasStructureFeature(Feature.JUNGLE_TEMPLE))return true;
return false;
});
combinedResult.addAll(positions);
positions.forEach(pos -> {
@@ -50,6 +44,11 @@ public class JungleTempleFinder extends AbstractTempleFinder {
return combinedResult;
}
@Override
protected StructureFeature<?> getStructureFeature() {
return Feature.JUNGLE_TEMPLE;
}
@Override
public void buildStructure(PieceFinder finder) {
BlockState eastStairs = Blocks.COBBLESTONE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.EAST);
@@ -0,0 +1,103 @@
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
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.dimension.DimensionType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
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;
});
protected List<PieceFinder> finders = new ArrayList<>();
protected Vec3i size = new Vec3i(16, 8, 16);
public MansionFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos);
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() {
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))) {
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)));
}
});
});
return combinedResult;
}
public Map<PieceFinder, List<BlockPos>> findInChunkPieces() {
Map<PieceFinder, List<BlockPos>> result = new HashMap<>();
this.finders.forEach(pieceFinder -> {
result.put(pieceFinder, pieceFinder.findInChunk());
});
return result;
}
public void buildStructure(PieceFinder finder) {
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.
}
@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 MansionFinder(world, chunkPos));
return finders;
}
}
@@ -1,7 +1,8 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
@@ -1,22 +1,23 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.finder.Finder;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.BlockMirror;
import net.minecraft.util.BlockRotation;
import net.minecraft.util.math.*;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.dimension.DimensionType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class PieceFinder extends Finder {
protected Map<BlockPos, BlockState> structure = new HashMap<>();
protected Map<BlockPos, BlockState> structure = new LinkedHashMap<>();
private MutableIntBoundingBox boundingBox;
protected List<BlockPos> searchPositions = new ArrayList<>();
@@ -28,6 +29,8 @@ public class PieceFinder extends Finder {
protected int height;
protected int depth;
private boolean debug;
public PieceFinder(World world, ChunkPos chunkPos, Direction facing, Vec3i size) {
super(world, chunkPos);
@@ -61,19 +64,22 @@ public class PieceFinder extends Finder {
public List<BlockPos> findInChunk() {
List<BlockPos> result = new ArrayList<>();
Chunk chunk = this.world.getChunk(this.chunkPos.getCenterBlockPos());
if(this.structure.isEmpty()) {
return result;
}
//FOR DEBUGGING PIECES.
if(this.debug) {
MinecraftClient.getInstance().execute(() -> {
int y = this.rotation.ordinal() * 10 + this.mirror.ordinal() * 20 + 100;
/*//FOR DEBUGGING PIECES.
MinecraftClient.getInstance().execute(() -> {
int y = this.rotation.ordinal() * 10 + this.mirror.ordinal() * 20 + 80;
if(this.chunkPos.x % 2 == 0 && this.chunkPos.z % 2 == 0) {
this.structure.forEach((pos, state) -> {
this.world.setBlockState(this.chunkPos.getCenterBlockPos().add(pos).add(0, y, 0), state);
});
}
});*/
if (this.chunkPos.x % 2 == 0 && this.chunkPos.z % 2 == 0) {
this.structure.forEach((pos, state) -> {
this.world.setBlockState(this.chunkPos.getCenterBlockPos().add(pos).add(0, y, 0), state, 0);
});
}
});
}
for(BlockPos center: this.searchPositions) {
boolean found = true;
@@ -221,4 +227,9 @@ public class PieceFinder extends Finder {
public boolean isValidDimension(DimensionType dimension) {
return true;
}
public void setDebug() {
this.debug = true;
}
}
@@ -1,7 +1,8 @@
package kaptainwutax.seedcracker.finder;
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.StructureData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
@@ -13,8 +14,8 @@ 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.gen.feature.Feature;
import net.minecraft.world.gen.feature.StructureFeature;
import java.util.ArrayList;
import java.util.List;
@@ -32,13 +33,6 @@ public class SwampHutFinder extends AbstractTempleFinder {
List<BlockPos> combinedResult = new ArrayList<>();
result.forEach((pieceFinder, positions) -> {
positions.removeIf(pos -> {
Biome biome = world.getBiome(pos.add(9, 0, 9));
if(!biome.hasStructureFeature(Feature.SWAMP_HUT))return true;
return false;
});
combinedResult.addAll(positions);
positions.forEach(pos -> {
@@ -51,6 +45,11 @@ public class SwampHutFinder extends AbstractTempleFinder {
return combinedResult;
}
@Override
protected StructureFeature<?> getStructureFeature() {
return Feature.SWAMP_HUT;
}
@Override
public void buildStructure(PieceFinder finder) {
finder.fillWithOutline(1, 1, 1, 5, 1, 7, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false);
@@ -2,8 +2,8 @@ package kaptainwutax.seedcracker.mixin;
import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.CommandDispatcher;
import kaptainwutax.seedcracker.ClientCommands;
import kaptainwutax.seedcracker.FinderQueue;
import kaptainwutax.seedcracker.command.ClientCommands;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.ClientPlayNetworkHandler;
@@ -1,13 +1,15 @@
package kaptainwutax.seedcracker.mixin;
import com.mojang.brigadier.StringReader;
import kaptainwutax.seedcracker.ClientCommands;
import kaptainwutax.seedcracker.command.ClientCommands;
import net.minecraft.client.network.ClientPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.regex.Pattern;
@Mixin(ClientPlayerEntity.class)
public class ClientPlayerEntityMixin {
@@ -17,10 +19,8 @@ public class ClientPlayerEntityMixin {
StringReader reader = new StringReader(message);
reader.skip();
int cursor = reader.getCursor();
reader.setCursor(cursor);
if(ClientCommands.isClientSideCommand(message.substring(1).split(" "))) {
if(ClientCommands.isClientSideCommand(message.substring(1).split(Pattern.quote(" ")))) {
ClientCommands.executeCommand(reader);
ci.cancel();
}
@@ -1,6 +1,6 @@
package kaptainwutax.seedcracker.mixin;
import kaptainwutax.seedcracker.FinderQueue;
import kaptainwutax.seedcracker.finder.FinderQueue;
import kaptainwutax.seedcracker.SeedCracker;
import net.minecraft.client.world.ClientWorld;
import org.spongepowered.asm.mixin.Mixin;
@@ -8,6 +8,8 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.concurrent.Executors;
@Mixin(ClientWorld.class)
public abstract class ClientWorldMixin {
@@ -15,6 +17,8 @@ public abstract class ClientWorldMixin {
private void disconnect(CallbackInfo ci) {
SeedCracker.get().clear();
FinderQueue.get().clear();
FinderQueue.SERVICE.shutdown();
FinderQueue.SERVICE = Executors.newFixedThreadPool(5);
}
}