├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── assets │ │ └── seedcrackerx │ │ │ ├── icon.png │ │ │ └── lang │ │ │ ├── zh_cn.json │ │ │ ├── hi_in.json │ │ │ ├── en_us.json │ │ │ ├── tr_tr.json │ │ │ └── ru_ru.json │ ├── pack.mcmeta │ ├── seedcracker.mixins.json │ └── META-INF │ │ └── mods.toml │ └── java │ └── kaptainwutax │ └── seedcrackerX │ ├── api │ └── SeedCrackerAPI.java │ ├── finder │ ├── FinderBuilder.java │ ├── FinderControl.java │ ├── BlockFinder.java │ ├── ReloadFinders.java │ ├── BlockUpdateQueue.java │ ├── decorator │ │ ├── ore │ │ │ └── EmeraldOreFinder.java │ │ ├── EndGatewayFinder.java │ │ ├── EndPillarsFinder.java │ │ └── DesertWellFinder.java │ ├── structure │ │ ├── AbstractTempleFinder.java │ │ ├── JigsawFinder.java │ │ ├── BuriedTreasureFinder.java │ │ ├── OutpostFinder.java │ │ ├── IglooFinder.java │ │ ├── MonumentFinder.java │ │ ├── SwampHutFinder.java │ │ └── EndCityFinder.java │ ├── BiomeFinder.java │ ├── FinderQueue.java │ └── Finder.java │ ├── util │ ├── FeatureToggle.java │ ├── Predicates.java │ ├── PosIterator.java │ ├── HeightContext.java │ ├── BiomeFixer.java │ ├── Log.java │ └── Database.java │ ├── render │ ├── Cube.java │ ├── Renderer.java │ ├── Color.java │ ├── Line.java │ └── Cuboid.java │ ├── cracker │ ├── HashedSeedData.java │ ├── DataAddedEvent.java │ ├── storage │ │ ├── ProgressListener.java │ │ └── ScheduledSet.java │ ├── PillarData.java │ ├── BiomeData.java │ └── decorator │ │ ├── DeepDungeon.java │ │ ├── Decorator.java │ │ ├── EmeraldOre.java │ │ ├── FullFungusData.java │ │ └── WarpedFungus.java │ ├── mixin │ ├── ClientPlayerEntityMixin.java │ ├── GameRendererMixin.java │ ├── ClientWorldMixin.java │ └── ClientPlayNetworkHandlerMixin.java │ ├── command │ ├── GuiCommand.java │ ├── DatabaseCommand.java │ ├── VersionCommand.java │ ├── ClientCommand.java │ ├── RenderCommand.java │ ├── CrackerCommand.java │ ├── DataCommand.java │ └── FinderCommand.java │ ├── init │ └── ClientCommands.java │ ├── SeedCracker.java │ ├── Features.java │ └── config │ ├── Config.java │ ├── StructureSave.java │ └── ConfigScreen.java ├── .gitattributes ├── .gitignore ├── settings.gradle ├── gradlew.bat ├── gradle.properties └── README.md /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onePlaceholder/SeedCrackerX-Forge/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/seedcrackerx/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onePlaceholder/SeedCrackerX-Forge/HEAD/src/main/resources/assets/seedcrackerx/icon.png -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": { 4 | "text": "${mod_id} resources" 5 | }, 6 | "pack_format": 15 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/api/SeedCrackerAPI.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.api; 2 | 3 | public interface SeedCrackerAPI { 4 | void pushWorldSeed(long seed); 5 | } 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable autocrlf on generated files, they always generate with LF 2 | # Add any extra files or paths here to make git stop saying they 3 | # are changed when only line endings change. 4 | src/generated/**/.cache/cache text eol=lf 5 | src/generated/**/*.json text eol=lf 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | *.ipr 12 | *.iws 13 | *.iml 14 | .idea 15 | 16 | # gradle 17 | build 18 | .gradle 19 | 20 | # other 21 | eclipse 22 | run 23 | 24 | # Files from Forge MDK 25 | forge*changelog.txt 26 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | maven { 5 | name = 'MinecraftForge' 6 | url = 'https://maven.minecraftforge.net/' 7 | } 8 | } 9 | } 10 | 11 | plugins { 12 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' 13 | } -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/FinderBuilder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | import net.minecraft.world.level.ChunkPos; 4 | import net.minecraft.world.level.Level; 5 | 6 | import java.util.List; 7 | 8 | @FunctionalInterface 9 | public interface FinderBuilder { 10 | 11 | List build(Level world, ChunkPos chunkPos); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/seedcracker.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "kaptainwutax.seedcrackerX.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [ 7 | ], 8 | "client": [ 9 | "ClientPlayerEntityMixin", 10 | "ClientPlayNetworkHandlerMixin", 11 | "ClientWorldMixin", 12 | "GameRendererMixin" 13 | ], 14 | "injectors": { 15 | "defaultRequire": 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/util/FeatureToggle.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.util; 2 | 3 | public class FeatureToggle { 4 | 5 | //This is for The featureToggles in the config object 6 | //It allows for the booleans to be passed around by reference 7 | //(I know that it's a hacky workaround) 8 | private boolean enabled; 9 | 10 | public FeatureToggle(boolean flag) { 11 | enabled = flag; 12 | } 13 | 14 | public void set(boolean flag) { 15 | enabled = flag; 16 | } 17 | 18 | public boolean get() { 19 | return enabled; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/render/Cube.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.render; 2 | 3 | 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.core.Vec3i; 6 | 7 | public class Cube extends Cuboid { 8 | 9 | public Cube() { 10 | this(BlockPos.ZERO, Color.WHITE); 11 | } 12 | 13 | public Cube(BlockPos pos) { 14 | this(pos, Color.WHITE); 15 | } 16 | 17 | public Cube(BlockPos pos, Color color) { 18 | super(pos, new Vec3i(1, 1, 1), color); 19 | } 20 | 21 | @Override 22 | public BlockPos getPos() { 23 | return this.start; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/HashedSeedData.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker; 2 | 3 | import com.seedfinding.mccore.rand.seed.WorldSeed; 4 | import com.seedfinding.mcseed.rand.JRand; 5 | 6 | public class HashedSeedData { 7 | 8 | private final long hashedSeed; 9 | 10 | public HashedSeedData(long hashedSeed) { 11 | this.hashedSeed = hashedSeed; 12 | } 13 | 14 | public boolean test(long seed, JRand rand) { 15 | return WorldSeed.toHash(seed) == this.hashedSeed; 16 | } 17 | 18 | public long getHashedSeed() { 19 | return this.hashedSeed; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/util/Predicates.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.util; 2 | 3 | import java.util.function.BiPredicate; 4 | 5 | public class Predicates { 6 | 7 | public static BiPredicate EQUAL_TO = Integer::equals; 8 | public static BiPredicate NOT_EQUAL_TO = (a, b) -> !a.equals(b); 9 | public static BiPredicate LESS_THAN = (a, b) -> a < b; 10 | public static BiPredicate MORE_THAN = (a, b) -> a > b; 11 | public static BiPredicate LESS_OR_EQUAL_TO = (a, b) -> a <= b; 12 | public static BiPredicate MORE_OR_EQUAL_TO = (a, b) -> a >= b; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/mixin/ClientPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.mixin; 2 | 3 | import kaptainwutax.seedcrackerX.SeedCracker; 4 | import net.minecraft.client.player.LocalPlayer; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | @Mixin(LocalPlayer.class) 11 | public abstract class ClientPlayerEntityMixin { 12 | 13 | @Inject(method = "tick", at = @At("HEAD")) 14 | private void tick(CallbackInfo ci) { 15 | SeedCracker.get().getDataStorage().tick(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/render/Renderer.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.render; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import com.mojang.blaze3d.vertex.VertexConsumer; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.world.phys.Vec3; 8 | 9 | public abstract class Renderer { 10 | 11 | protected Minecraft mc = Minecraft.getInstance(); 12 | 13 | public abstract void render(PoseStack matrixStack, VertexConsumer vertexConsumer, Vec3 cameraPos); 14 | 15 | public abstract BlockPos getPos(); 16 | 17 | protected Vec3 toVec3d(BlockPos pos) { 18 | return new Vec3(pos.getX(), pos.getY(), pos.getZ()); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/util/PosIterator.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.util; 2 | 3 | 4 | import net.minecraft.core.BlockPos; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public class PosIterator { 10 | 11 | public static Set create(BlockPos start, BlockPos end) { 12 | Set result = new HashSet<>(); 13 | 14 | for (int x = start.getX(); x <= end.getX(); x++) { 15 | for (int z = start.getZ(); z <= end.getZ(); z++) { 16 | for (int y = start.getY(); y <= end.getY(); y++) { 17 | result.add(new BlockPos(x, y, z)); 18 | } 19 | } 20 | } 21 | 22 | return result; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/DataAddedEvent.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker; 2 | 3 | import kaptainwutax.seedcrackerX.cracker.storage.DataStorage; 4 | import kaptainwutax.seedcrackerX.cracker.storage.TimeMachine; 5 | 6 | @FunctionalInterface 7 | public interface DataAddedEvent { 8 | 9 | DataAddedEvent POKE_PILLARS = s -> s.getTimeMachine().poke(TimeMachine.Phase.PILLARS); 10 | DataAddedEvent POKE_STRUCTURES = s -> s.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES); 11 | DataAddedEvent POKE_LIFTING = s -> s.getTimeMachine().poke(TimeMachine.Phase.LIFTING); 12 | DataAddedEvent POKE_BIOMES = s -> s.getTimeMachine().poke(TimeMachine.Phase.BIOMES); 13 | 14 | void onDataAdded(DataStorage dataStorage); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/util/HeightContext.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.util; 2 | 3 | public class HeightContext { 4 | private final int bottomY; 5 | private final int topY; 6 | 7 | public HeightContext(int minY, int maxY) { 8 | this.bottomY = minY; 9 | this.topY = maxY; 10 | } 11 | 12 | public int getTopY() { 13 | return topY; 14 | } 15 | 16 | public int getBottomY() { 17 | return bottomY; 18 | } 19 | 20 | public int getHeight() { 21 | return topY - bottomY; 22 | } 23 | 24 | public int getDistanceToBottom(int yValue) { 25 | return yValue - bottomY; 26 | } 27 | 28 | public int getDistanceToTop(int yValue) { 29 | return topY - yValue - 1; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/storage/ProgressListener.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker.storage; 2 | 3 | import kaptainwutax.seedcrackerX.util.Log; 4 | 5 | public class ProgressListener { 6 | 7 | protected float progress; 8 | protected int count = 0; 9 | 10 | public ProgressListener() { 11 | this(0.0F); 12 | } 13 | 14 | public ProgressListener(float progress) { 15 | this.progress = progress; 16 | } 17 | 18 | public synchronized void addPercent(float percent, boolean debug) { 19 | if ((this.count & 3) == 0 && debug) { 20 | Log.debug(Log.translate("tmachine.progress") + ": " + this.progress + "%"); 21 | } 22 | 23 | this.count++; 24 | this.progress += percent; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/GuiCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import net.minecraft.commands.CommandSourceStack; 7 | 8 | public class GuiCommand extends ClientCommand { 9 | 10 | @Override 11 | public String getName() { 12 | return "gui"; 13 | } 14 | 15 | @Override 16 | public void build(LiteralArgumentBuilder builder) { 17 | builder.executes(this::openGui); 18 | } 19 | 20 | private int openGui(CommandContext context) { 21 | SeedCracker.get().getDataStorage().openGui = true; //gui needs to open on the main thread 22 | return 0; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/DatabaseCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | 4 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 5 | import com.mojang.brigadier.context.CommandContext; 6 | import net.minecraft.Util; 7 | import net.minecraft.commands.CommandSourceStack; 8 | 9 | public class DatabaseCommand extends ClientCommand { 10 | 11 | public static String databaseURL = "https://docs.google.com/spreadsheets/d/1tuQiE-0leW88em9OHbZnH-RFNhVqgoHhIt9WQbeqqWw/edit?usp=sharing"; 12 | 13 | @Override 14 | public String getName() { 15 | return "database"; 16 | } 17 | 18 | @Override 19 | public void build(LiteralArgumentBuilder builder) { 20 | builder.executes(this::openURL); 21 | } 22 | 23 | public int openURL(CommandContext context) { 24 | Util.getPlatform().openUri(databaseURL); 25 | return 0; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/render/Color.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.render; 2 | 3 | public class Color { 4 | 5 | public static final Color WHITE = new Color(255, 255, 255); 6 | 7 | private final int red; 8 | private final int green; 9 | private final int blue; 10 | 11 | public Color(int red, int green, int blue) { 12 | this.red = red; 13 | this.green = green; 14 | this.blue = blue; 15 | } 16 | 17 | public int getRed() { 18 | return this.red; 19 | } 20 | 21 | public int getGreen() { 22 | return this.green; 23 | } 24 | 25 | public int getBlue() { 26 | return this.blue; 27 | } 28 | 29 | public float getFRed() { 30 | return this.getRed() / 255.0F; 31 | } 32 | 33 | public float getFGreen() { 34 | return this.getGreen() / 255.0F; 35 | } 36 | 37 | public float getFBlue() { 38 | return this.getBlue() / 255.0F; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/PillarData.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Random; 7 | 8 | public class PillarData { 9 | 10 | private final List heights; 11 | 12 | public PillarData(List heights) { 13 | this.heights = heights; 14 | } 15 | 16 | public boolean test(long seed) { 17 | List h = this.getPillarHeights((int) seed); 18 | return h.equals(this.heights); 19 | } 20 | 21 | public List getPillarHeights(int pillarSeed) { 22 | List indices = new ArrayList<>(); 23 | 24 | for (int i = 0; i < 10; i++) { 25 | indices.add(i); 26 | } 27 | 28 | Collections.shuffle(indices, new Random(pillarSeed)); 29 | 30 | List heights = new ArrayList<>(); 31 | 32 | for (Integer index : indices) { 33 | heights.add(76 + index * 3); 34 | } 35 | 36 | return heights; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/mixin/GameRendererMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.mixin; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import kaptainwutax.seedcrackerX.finder.FinderQueue; 5 | import net.minecraft.client.Camera; 6 | import net.minecraft.client.renderer.GameRenderer; 7 | import org.spongepowered.asm.mixin.Final; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(GameRenderer.class) 15 | public abstract class GameRendererMixin { 16 | 17 | 18 | @Shadow @Final private Camera mainCamera; 19 | 20 | @Inject(method = "renderLevel", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", args = {"ldc=hand"})) 21 | private void renderWorldHand(float p_109090_, long p_109091_, PoseStack p_109092_, CallbackInfo ci) { 22 | FinderQueue.get().renderFinders(p_109092_, mainCamera); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/FinderControl.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Queue; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.ConcurrentLinkedQueue; 8 | import java.util.stream.Collectors; 9 | 10 | public class FinderControl { 11 | 12 | private final Map> activeFinders = new ConcurrentHashMap<>(); 13 | 14 | public void deleteFinders() { 15 | this.activeFinders.clear(); 16 | } 17 | 18 | public List getActiveFinders() { 19 | this.activeFinders.values().forEach(finders -> { 20 | finders.removeIf(Finder::isUseless); 21 | }); 22 | 23 | return this.activeFinders.values().stream() 24 | .flatMap(Queue::stream).collect(Collectors.toList()); 25 | } 26 | 27 | public void addFinder(Finder.Type type, Finder finder) { 28 | if (finder.isUseless()) return; 29 | 30 | if (!this.activeFinders.containsKey(type)) { 31 | this.activeFinders.put(type, new ConcurrentLinkedQueue<>()); 32 | } 33 | 34 | this.activeFinders.get(type).add(finder); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/VersionCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import com.seedfinding.mccore.version.MCVersion; 5 | import kaptainwutax.seedcrackerX.config.Config; 6 | import kaptainwutax.seedcrackerX.util.Log; 7 | import net.minecraft.ChatFormatting; 8 | import net.minecraft.commands.CommandSourceStack; 9 | 10 | import static net.minecraft.commands.Commands.literal; 11 | 12 | public class VersionCommand extends ClientCommand { 13 | 14 | @Override 15 | public String getName() { 16 | return "version"; 17 | } 18 | 19 | @Override 20 | public void build(LiteralArgumentBuilder builder) { 21 | for (MCVersion version : MCVersion.values()) { 22 | if (version.isOlderThan(MCVersion.v1_8)) continue; 23 | builder.then(literal(version.name).executes(context -> this.setVersion(version))); 24 | } 25 | } 26 | 27 | private int setVersion(MCVersion version) { 28 | Config.get().setVersion(version); 29 | Config.save(); 30 | ClientCommand.sendFeedback(Log.translate("version.setVersion") + " " + version + ".", ChatFormatting.AQUA, true); 31 | return 0; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/BiomeData.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker; 2 | 3 | import com.seedfinding.mcbiome.biome.Biome; 4 | import com.seedfinding.mcbiome.source.BiomeSource; 5 | import com.seedfinding.mccore.version.MCVersion; 6 | import kaptainwutax.seedcrackerX.config.Config; 7 | 8 | public class BiomeData { 9 | 10 | public final Biome biome; 11 | public final int x; 12 | public final int z; 13 | 14 | public BiomeData(Biome biome, int x, int z) { 15 | this.biome = biome; 16 | this.x = x; 17 | this.z = z; 18 | } 19 | 20 | public boolean test(BiomeSource source) { 21 | if (Config.get().getVersion().isNewerOrEqualTo(MCVersion.v1_15)) { 22 | return source.getBiomeForNoiseGen(this.x, 0, this.z) == this.biome; 23 | } else { 24 | return source.getBiome(this.x, 0, this.z) == this.biome; 25 | } 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (this == o) return true; 31 | if (!(o instanceof BiomeData)) return false; 32 | BiomeData data = (BiomeData) o; 33 | return this.biome == data.biome; 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | return this.biome.getName().hashCode(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/storage/ScheduledSet.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker.storage; 2 | 3 | import java.util.*; 4 | 5 | public class ScheduledSet implements Iterable { 6 | 7 | protected final Set baseSet; 8 | protected final Set scheduledSet; 9 | 10 | public ScheduledSet(Comparator comparator) { 11 | if (comparator != null) { 12 | this.baseSet = new TreeSet<>(comparator); 13 | } else { 14 | this.baseSet = new HashSet<>(); 15 | } 16 | 17 | this.scheduledSet = new HashSet<>(); 18 | } 19 | 20 | public synchronized void scheduleAdd(T e) { 21 | this.scheduledSet.add(e); 22 | } 23 | 24 | public synchronized void dump() { 25 | synchronized (this.baseSet) { 26 | this.baseSet.addAll(this.scheduledSet); 27 | this.scheduledSet.clear(); 28 | } 29 | } 30 | 31 | public synchronized boolean contains(T e) { 32 | return this.baseSet.contains(e) || this.scheduledSet.contains(e); 33 | } 34 | 35 | public Set getBaseSet() { 36 | return this.baseSet; 37 | } 38 | 39 | @Override 40 | public synchronized Iterator iterator() { 41 | return this.baseSet.iterator(); 42 | } 43 | 44 | public synchronized int size() { 45 | return this.baseSet.size(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/init/ClientCommands.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.init; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import kaptainwutax.seedcrackerX.command.*; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.commands.CommandSourceStack; 7 | import net.minecraftforge.client.ClientCommandHandler; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class ClientCommands { 13 | 14 | public static final String PREFIX = "seedcracker"; 15 | public static final List COMMANDS = new ArrayList<>(); 16 | 17 | public static RenderCommand RENDER; 18 | public static FinderCommand FINDER; 19 | public static DataCommand DATA; 20 | public static CrackerCommand CRACKER; 21 | public static VersionCommand VERSION; 22 | public static GuiCommand GUI; 23 | public static DatabaseCommand DATABASE; 24 | 25 | static { 26 | COMMANDS.add(RENDER = new RenderCommand()); 27 | COMMANDS.add(FINDER = new FinderCommand()); 28 | COMMANDS.add(DATA = new DataCommand()); 29 | COMMANDS.add(CRACKER = new CrackerCommand()); 30 | COMMANDS.add(VERSION = new VersionCommand()); 31 | COMMANDS.add(GUI = new GuiCommand()); 32 | COMMANDS.add(DATABASE = new DatabaseCommand()); 33 | } 34 | 35 | public static void registerCommands(CommandDispatcher dispatcher) { 36 | COMMANDS.forEach(clientCommand -> clientCommand.register(dispatcher)); 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/ClientCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 5 | import kaptainwutax.seedcrackerX.init.ClientCommands; 6 | import kaptainwutax.seedcrackerX.util.Log; 7 | import net.minecraft.ChatFormatting; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.commands.CommandSourceStack; 10 | import net.minecraft.network.chat.Component; 11 | 12 | import static net.minecraft.commands.Commands.literal; 13 | 14 | public abstract class ClientCommand { 15 | 16 | public static void sendFeedback(String message, ChatFormatting color, boolean overlay) { 17 | try { 18 | Minecraft.getInstance().player.displayClientMessage(Component.literal(message).withStyle(color), overlay); 19 | } catch (Exception ignored) {} 20 | } 21 | 22 | public abstract String getName(); 23 | 24 | public abstract void build(LiteralArgumentBuilder builder); 25 | 26 | public final void register(CommandDispatcher dispatcher) { 27 | LiteralArgumentBuilder builder = literal(this.getName()); 28 | this.build(builder); 29 | LiteralArgumentBuilder seedCrackerRootCommand = literal(ClientCommands.PREFIX) 30 | .executes(context -> { 31 | Log.error("Error: please enter a valid seedcracker command"); 32 | return 1; 33 | }); 34 | dispatcher.register(seedCrackerRootCommand.then(builder)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/RenderCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import kaptainwutax.seedcrackerX.config.Config; 5 | import kaptainwutax.seedcrackerX.util.Log; 6 | import net.minecraft.ChatFormatting; 7 | import net.minecraft.commands.CommandSourceStack; 8 | 9 | import static net.minecraft.commands.Commands.literal; 10 | 11 | public class RenderCommand extends ClientCommand { 12 | 13 | @Override 14 | public String getName() { 15 | return "render"; 16 | } 17 | 18 | @Override 19 | public void build(LiteralArgumentBuilder builder) { 20 | builder.then(literal("outlines") 21 | .executes(context -> this.printRenderMode()) 22 | ); 23 | 24 | for (Config.RenderType renderType : Config.RenderType.values()) { 25 | builder.then(literal("outlines") 26 | .then(literal(renderType.toString()).executes(context -> this.setRenderMode(renderType))) 27 | ); 28 | } 29 | } 30 | 31 | private int printRenderMode() { 32 | sendFeedback(Log.translate("render.getRenderMode") + " [" + Config.get().render + "].", ChatFormatting.AQUA, false); 33 | return 0; 34 | } 35 | 36 | private int setRenderMode(Config.RenderType renderType) { 37 | Config.get().render = renderType; 38 | Config.save(); 39 | sendFeedback(Log.translate("render.setRenderMode") + " [" + Config.get().render + "].", ChatFormatting.AQUA, false); 40 | return 0; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/BlockFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.world.level.ChunkPos; 6 | import net.minecraft.world.level.Level; 7 | import net.minecraft.world.level.block.Block; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | import net.minecraft.world.level.chunk.ChunkAccess; 10 | 11 | import java.util.*; 12 | import java.util.stream.Collectors; 13 | 14 | public abstract class BlockFinder extends Finder { 15 | 16 | private final Set targetBlockStates = new HashSet<>(); 17 | protected List searchPositions = new ArrayList<>(); 18 | 19 | public BlockFinder(Level world, ChunkPos chunkPos, Block block) { 20 | super(world, chunkPos); 21 | this.targetBlockStates.addAll(block.getStateDefinition().getPossibleStates()); 22 | } 23 | 24 | public BlockFinder(Level world, ChunkPos chunkPos, BlockState... blockStates) { 25 | super(world, chunkPos); 26 | this.targetBlockStates.addAll(Arrays.stream(blockStates).collect(Collectors.toList())); 27 | } 28 | 29 | @Override 30 | public List findInChunk() { 31 | List result = new ArrayList<>(); 32 | ChunkAccess chunk = this.world.getChunk(this.chunkPos.getWorldPosition()); 33 | 34 | for (BlockPos blockPos : this.searchPositions) { 35 | BlockState currentState = chunk.getBlockState(blockPos); 36 | 37 | if (this.targetBlockStates.contains(currentState)) { 38 | result.add(this.chunkPos.getWorldPosition().offset(blockPos)); 39 | } 40 | } 41 | 42 | return result; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/SeedCracker.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX; 2 | 3 | import kaptainwutax.seedcrackerX.api.SeedCrackerAPI; 4 | import kaptainwutax.seedcrackerX.config.Config; 5 | import kaptainwutax.seedcrackerX.cracker.storage.DataStorage; 6 | import kaptainwutax.seedcrackerX.finder.FinderQueue; 7 | import kaptainwutax.seedcrackerX.init.ClientCommands; 8 | import net.minecraftforge.api.distmarker.Dist; 9 | import net.minecraftforge.client.event.RegisterClientCommandsEvent; 10 | import net.minecraftforge.common.MinecraftForge; 11 | import net.minecraftforge.fml.DistExecutor; 12 | import net.minecraftforge.fml.common.Mod; 13 | 14 | import java.util.ArrayList; 15 | 16 | @Mod("seedcracker") 17 | public class SeedCracker { 18 | public static final ArrayList entrypoints = new ArrayList<>(); 19 | private static SeedCracker INSTANCE; 20 | private final DataStorage dataStorage = new DataStorage(); 21 | 22 | public static SeedCracker get() { 23 | return INSTANCE; 24 | } 25 | 26 | public SeedCracker() { 27 | INSTANCE = this; 28 | DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> () -> { 29 | Config.load(); 30 | Features.init(Config.get().getVersion()); 31 | MinecraftForge.EVENT_BUS.addListener(this::onRegisterClientCommands); 32 | }); 33 | } 34 | 35 | public void onRegisterClientCommands(RegisterClientCommandsEvent event) { 36 | ClientCommands.registerCommands(event.getDispatcher()); 37 | } 38 | 39 | public DataStorage getDataStorage() { 40 | return this.dataStorage; 41 | } 42 | 43 | public void reset() { 44 | SeedCracker.get().getDataStorage().clear(); 45 | FinderQueue.get().finderControl.deleteFinders(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/render/Line.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.render; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import com.mojang.blaze3d.vertex.VertexConsumer; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.world.phys.Vec3; 7 | 8 | public class Line extends Renderer { 9 | 10 | public Vec3 start; 11 | public Vec3 end; 12 | public Color color; 13 | 14 | public Line() { 15 | this(Vec3.ZERO, Vec3.ZERO, Color.WHITE); 16 | } 17 | 18 | public Line(Vec3 start, Vec3 end) { 19 | this(start, end, Color.WHITE); 20 | } 21 | 22 | public Line(Vec3 start, Vec3 end, Color color) { 23 | this.start = start; 24 | this.end = end; 25 | this.color = color; 26 | } 27 | 28 | @Override 29 | public void render(PoseStack matrixStack, VertexConsumer vertexConsumer, Vec3 cameraPos) { 30 | this.putVertex(vertexConsumer, matrixStack, this.start, cameraPos); 31 | this.putVertex(vertexConsumer, matrixStack, this.end, cameraPos); 32 | } 33 | 34 | protected void putVertex(VertexConsumer vertexConsumer, PoseStack matrixStack, Vec3 pos, Vec3 cameraPos) { 35 | vertexConsumer.vertex( 36 | matrixStack.last().pose(), 37 | (float) (pos.x - cameraPos.x), 38 | (float) (pos.y - cameraPos.y), 39 | (float) (pos.z - cameraPos.z) 40 | ).color( 41 | this.color.getFRed(), 42 | this.color.getFGreen(), 43 | this.color.getFBlue(), 44 | 1.0F 45 | ).endVertex(); 46 | } 47 | 48 | @Override 49 | public BlockPos getPos() { 50 | double x = (this.end.x() - this.start.x()) / 2 + this.start.x(); 51 | double y = (this.end.y() - this.start.y()) / 2 + this.start.y(); 52 | double z = (this.end.z() - this.start.z()) / 2 + this.start.z(); 53 | return BlockPos.containing(x, y, z); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/ReloadFinders.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | import kaptainwutax.seedcrackerX.finder.decorator.EndPillarsFinder; 4 | import kaptainwutax.seedcrackerX.finder.decorator.ore.EmeraldOreFinder; 5 | import kaptainwutax.seedcrackerX.finder.structure.*; 6 | import kaptainwutax.seedcrackerX.util.HeightContext; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.world.level.ChunkPos; 10 | 11 | public class ReloadFinders { 12 | 13 | public static void reloadHeight(int minY, int maxY) { 14 | Finder.CHUNK_POSITIONS.clear(); 15 | for (int x = 0; x < 16; x++) { 16 | for (int z = 0; z < 16; z++) { 17 | for (int y = minY; y < maxY; y++) { 18 | Finder.CHUNK_POSITIONS.add(new BlockPos(x, y, z)); 19 | } 20 | } 21 | } 22 | Finder.heightContext = new HeightContext(minY, maxY); 23 | 24 | EmeraldOreFinder.reloadSearchPositions(); 25 | EndPillarsFinder.BedrockMarkerFinder.reloadSearchPositions(); 26 | AbstractTempleFinder.reloadSearchPositions(); 27 | BuriedTreasureFinder.reloadSearchPositions(); 28 | EndCityFinder.reloadSearchPositions(); 29 | MonumentFinder.reloadSearchPositions(); 30 | OutpostFinder.reloadSearchPositions(); 31 | IglooFinder.reloadSearchPositions(); 32 | } 33 | 34 | public void reload() { 35 | Minecraft client = Minecraft.getInstance(); 36 | 37 | int renderdistance = client.options.renderDistance().get(); 38 | 39 | int playerChunkX = (int) (Math.round(client.player.getX()) >> 4); 40 | int playerChunkZ = (int) (Math.round(client.player.getZ()) >> 4); 41 | for (int i = playerChunkX - renderdistance; i < playerChunkX + renderdistance; i++) { 42 | for (int j = playerChunkZ - renderdistance; j < playerChunkZ + renderdistance; j++) { 43 | FinderQueue.get().onChunkData(client.level, new ChunkPos(i, j)); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/BlockUpdateQueue.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.core.Direction; 7 | import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; 8 | import net.minecraft.util.Tuple; 9 | 10 | import java.util.ArrayList; 11 | import java.util.HashSet; 12 | import java.util.LinkedList; 13 | import java.util.Queue; 14 | 15 | public class BlockUpdateQueue { 16 | private final Queue>> blocksAndAction = new LinkedList<>(); 17 | private final HashSet alreadyChecked = new HashSet<>(); 18 | 19 | public boolean add(ArrayList blockPoses, BlockPos originPos, Thread operationAtEnd) { 20 | if (alreadyChecked.add(originPos)) { 21 | blocksAndAction.add(new Tuple<>(operationAtEnd, blockPoses)); 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | public void tick() { 28 | if (blocksAndAction.isEmpty()) return; 29 | 30 | Tuple> current = blocksAndAction.peek(); 31 | ArrayList currentBlocks = current.getB(); 32 | for (int i = 0; i < 5; i++) { 33 | if (currentBlocks.isEmpty()) { 34 | current.getA().start(); 35 | blocksAndAction.remove(); 36 | if (blocksAndAction.isEmpty()) { 37 | return; 38 | } else { 39 | current = blocksAndAction.peek(); 40 | currentBlocks = current.getB(); 41 | } 42 | } 43 | if (Minecraft.getInstance().getConnection() == null) { 44 | blocksAndAction.clear(); 45 | return; 46 | } 47 | ServerboundPlayerActionPacket p = new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK, currentBlocks.remove(0), 48 | Direction.DOWN); 49 | Minecraft.getInstance().getConnection().send(p); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/mixin/ClientWorldMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.mixin; 2 | 3 | import kaptainwutax.seedcrackerX.SeedCracker; 4 | import kaptainwutax.seedcrackerX.config.StructureSave; 5 | import net.minecraft.client.multiplayer.ClientLevel; 6 | import net.minecraft.core.Holder; 7 | import net.minecraft.core.RegistryAccess; 8 | import net.minecraft.core.registries.Registries; 9 | import net.minecraft.resources.ResourceKey; 10 | import net.minecraft.util.profiling.ProfilerFiller; 11 | import net.minecraft.world.level.Level; 12 | import net.minecraft.world.level.biome.Biome; 13 | import net.minecraft.world.level.biome.Biomes; 14 | import net.minecraft.world.level.dimension.DimensionType; 15 | import net.minecraft.world.level.storage.WritableLevelData; 16 | import org.spongepowered.asm.mixin.Mixin; 17 | import org.spongepowered.asm.mixin.injection.At; 18 | import org.spongepowered.asm.mixin.injection.Inject; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 20 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 21 | 22 | import java.util.function.Supplier; 23 | 24 | @Mixin(ClientLevel.class) 25 | public abstract class ClientWorldMixin extends Level { 26 | 27 | protected ClientWorldMixin(WritableLevelData p_270739_, ResourceKey p_270683_, RegistryAccess p_270200_, Holder p_270240_, Supplier p_270692_, boolean p_270904_, boolean p_270470_, long p_270248_, int p_270466_) { 28 | super(p_270739_, p_270683_, p_270200_, p_270240_, p_270692_, p_270904_, p_270470_, p_270248_, p_270466_); 29 | } 30 | 31 | @Inject(method = "disconnect", at = @At("HEAD")) 32 | private void disconnect(CallbackInfo ci) { 33 | StructureSave.saveStructures(SeedCracker.get().getDataStorage().baseSeedData); 34 | SeedCracker.get().reset(); 35 | } 36 | 37 | @Inject(method = "getUncachedNoiseBiome", at = @At("HEAD"), cancellable = true) 38 | private void getGeneratorStoredBiome(int p_205516_, int p_205517_, int p_205518_, CallbackInfoReturnable> cir) { 39 | var biome = registryAccess().registryOrThrow(Registries.BIOME).getHolder(Biomes.THE_VOID); 40 | biome.ifPresent(cir::setReturnValue); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/CrackerCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import kaptainwutax.seedcrackerX.config.Config; 5 | import kaptainwutax.seedcrackerX.util.Log; 6 | import net.minecraft.ChatFormatting; 7 | import net.minecraft.commands.CommandSourceStack; 8 | 9 | import static net.minecraft.commands.Commands.literal; 10 | 11 | public class CrackerCommand extends ClientCommand { 12 | 13 | @Override 14 | public String getName() { 15 | return "cracker"; 16 | } 17 | 18 | @Override 19 | public void build(LiteralArgumentBuilder builder) { 20 | builder.then(literal("ON").executes(context -> this.setActive(true))) 21 | .then(literal("OFF").executes(context -> this.setActive(false))) 22 | .executes(context -> this.toggleActive()); 23 | 24 | builder.then(literal("debug") 25 | .then(literal("ON").executes(context -> this.setDebug(true))) 26 | .then(literal("OFF").executes(context -> this.setDebug(false))) 27 | .executes(context -> this.toggleDebug())); 28 | } 29 | 30 | private void feedback(boolean success, boolean flag) { 31 | String action = Log.translate(flag ? "cracker.enabled" : "cracker.disabled"); 32 | if (success) { 33 | sendFeedback(Log.translate("cracker.successfully") + action, ChatFormatting.GREEN, false); 34 | } else { 35 | sendFeedback(Log.translate("cracker.already") + action, ChatFormatting.RED, false); 36 | } 37 | Config.save(); 38 | } 39 | 40 | private int setActive(boolean flag) { 41 | feedback(Config.get().active != flag, flag); 42 | Config.get().active = flag; 43 | return 0; 44 | } 45 | 46 | private int toggleActive() { 47 | Config.get().active = !Config.get().active; 48 | feedback(true, Config.get().active); 49 | return 0; 50 | } 51 | 52 | private int setDebug(boolean flag) { 53 | feedback(Config.get().debug != flag, flag); 54 | Config.get().debug = flag; 55 | return 0; 56 | } 57 | 58 | private int toggleDebug() { 59 | Config.get().debug = !Config.get().debug; 60 | feedback(true, Config.get().debug); 61 | return 0; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/Features.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX; 2 | 3 | import com.seedfinding.mccore.version.MCVersion; 4 | import com.seedfinding.mcfeature.decorator.DesertWell; 5 | import com.seedfinding.mcfeature.decorator.EndGateway; 6 | import com.seedfinding.mcfeature.structure.*; 7 | import kaptainwutax.seedcrackerX.cracker.decorator.DeepDungeon; 8 | import kaptainwutax.seedcrackerX.cracker.decorator.Dungeon; 9 | import kaptainwutax.seedcrackerX.cracker.decorator.EmeraldOre; 10 | import kaptainwutax.seedcrackerX.cracker.decorator.WarpedFungus; 11 | 12 | public class Features { 13 | 14 | public static BuriedTreasure BURIED_TREASURE; 15 | public static DesertPyramid DESERT_PYRAMID; 16 | public static EndCity END_CITY; 17 | public static JunglePyramid JUNGLE_PYRAMID; 18 | public static Monument MONUMENT; 19 | public static Shipwreck SHIPWRECK; 20 | public static SwampHut SWAMP_HUT; 21 | public static PillagerOutpost PILLAGER_OUTPOST; 22 | public static Igloo IGLOO; 23 | 24 | public static EndGateway END_GATEWAY; 25 | public static DesertWell DESERT_WELL; 26 | public static EmeraldOre EMERALD_ORE; 27 | public static Dungeon DUNGEON; 28 | public static DeepDungeon DEEP_DUNGEON; 29 | public static WarpedFungus WARPED_FUNGUS; 30 | 31 | public static void init(MCVersion version) { 32 | safe(() -> BURIED_TREASURE = new BuriedTreasure(version)); 33 | safe(() -> DESERT_PYRAMID = new DesertPyramid(version)); 34 | safe(() -> END_CITY = new EndCity(version)); 35 | safe(() -> JUNGLE_PYRAMID = new JunglePyramid(version)); 36 | safe(() -> MONUMENT = new Monument(version)); 37 | safe(() -> SHIPWRECK = new Shipwreck(version)); 38 | safe(() -> SWAMP_HUT = new SwampHut(version)); 39 | safe(() -> PILLAGER_OUTPOST = new PillagerOutpost(version)); 40 | safe(() -> IGLOO = new Igloo(version)); 41 | 42 | safe(() -> END_GATEWAY = new EndGateway(version)); 43 | safe(() -> DESERT_WELL = new DesertWell(version)); 44 | safe(() -> EMERALD_ORE = new EmeraldOre(version)); 45 | safe(() -> DUNGEON = new Dungeon(version)); 46 | safe(() -> DEEP_DUNGEON = new DeepDungeon(version)); 47 | safe(() -> WARPED_FUNGUS = new WarpedFungus(version)); 48 | } 49 | 50 | private static void safe(Runnable runnable) { 51 | try { 52 | runnable.run(); 53 | } catch (Exception e) { 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/decorator/ore/EmeraldOreFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.decorator.ore; 2 | 3 | import kaptainwutax.seedcrackerX.Features; 4 | import kaptainwutax.seedcrackerX.SeedCracker; 5 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 6 | import kaptainwutax.seedcrackerX.cracker.decorator.EmeraldOre; 7 | import kaptainwutax.seedcrackerX.finder.BlockFinder; 8 | import kaptainwutax.seedcrackerX.finder.Finder; 9 | import kaptainwutax.seedcrackerX.render.Color; 10 | import kaptainwutax.seedcrackerX.render.Cube; 11 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 12 | import net.minecraft.core.BlockPos; 13 | import net.minecraft.world.level.ChunkPos; 14 | import net.minecraft.world.level.Level; 15 | import net.minecraft.world.level.biome.Biome; 16 | import net.minecraft.world.level.block.Blocks; 17 | import net.minecraft.world.level.dimension.DimensionType; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class EmeraldOreFinder extends BlockFinder { 23 | 24 | protected static List SEARCH_POSITIONS; 25 | 26 | public EmeraldOreFinder(Level world, ChunkPos chunkPos) { 27 | super(world, chunkPos, Blocks.EMERALD_ORE); 28 | this.searchPositions = SEARCH_POSITIONS; 29 | } 30 | 31 | public static void reloadSearchPositions() { 32 | SEARCH_POSITIONS = Finder.buildSearchPositions(Finder.CHUNK_POSITIONS, pos -> { 33 | if (pos.getY() < 4) return true; 34 | return pos.getY() > 28 + 4; 35 | }); 36 | } 37 | 38 | public static List create(Level world, ChunkPos chunkPos) { 39 | List finders = new ArrayList<>(); 40 | finders.add(new EmeraldOreFinder(world, chunkPos)); 41 | return finders; 42 | } 43 | 44 | @Override 45 | public List findInChunk() { 46 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2).value(); 47 | 48 | List result = super.findInChunk(); 49 | if (result.isEmpty()) return result; 50 | 51 | BlockPos pos = result.get(0); 52 | 53 | EmeraldOre.Data data = Features.EMERALD_ORE.at(pos.getX(), pos.getY(), pos.getZ(), BiomeFixer.swap(biome)); 54 | 55 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 56 | this.renderers.add(new Cube(pos, new Color(0, 255, 0))); 57 | } 58 | 59 | return result; 60 | } 61 | 62 | @Override 63 | public boolean isValidDimension(DimensionType dimension) { 64 | return this.isOverworld(dimension); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/DataCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import com.mojang.brigadier.context.CommandContext; 5 | import com.seedfinding.mcfeature.structure.RegionStructure; 6 | import kaptainwutax.seedcrackerX.SeedCracker; 7 | import kaptainwutax.seedcrackerX.config.StructureSave; 8 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 9 | import kaptainwutax.seedcrackerX.cracker.storage.DataStorage; 10 | import kaptainwutax.seedcrackerX.util.Log; 11 | import net.minecraft.ChatFormatting; 12 | import net.minecraft.commands.CommandSourceStack; 13 | import net.minecraft.locale.Language; 14 | 15 | import static net.minecraft.commands.Commands.literal; 16 | 17 | public class DataCommand extends ClientCommand { 18 | 19 | @Override 20 | public String getName() { 21 | return "data"; 22 | } 23 | 24 | @Override 25 | public void build(LiteralArgumentBuilder builder) { 26 | builder.then(literal("clear") 27 | .executes(this::clear) 28 | ); 29 | 30 | builder.then(literal("bits") 31 | .executes(this::printBits) 32 | ); 33 | 34 | builder.then(literal("restore") 35 | .executes(this::restoreData) 36 | ); 37 | } 38 | 39 | public int clear(CommandContext context) { 40 | SeedCracker.get().reset(); 41 | 42 | sendFeedback(Language.getInstance().getOrDefault("data.clearData"), ChatFormatting.GREEN, false); 43 | return 0; 44 | } 45 | 46 | private int printBits(CommandContext context) { 47 | DataStorage s = SeedCracker.get().getDataStorage(); 48 | String message = Language.getInstance().getOrDefault("data.collectedBits").formatted((int) s.getBaseBits(), (int) s.getWantedBits()); 49 | String message2 = Language.getInstance().getOrDefault("data.collectedLiftingBits").formatted((int) s.getLiftingBits(), 40); 50 | sendFeedback(message, ChatFormatting.GREEN, false); 51 | sendFeedback(message2, ChatFormatting.GREEN, false); 52 | return 0; 53 | } 54 | 55 | private int restoreData(CommandContext context) { 56 | var preloaded = StructureSave.loadStructures(); 57 | if (!preloaded.isEmpty()) { 58 | for (RegionStructure.Data data : preloaded) { 59 | SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_LIFTING); 60 | } 61 | Log.warn("data.restoreStructures",preloaded.size()); 62 | } else { 63 | Log.warn("data.restoreFailed"); 64 | } 65 | return 0; 66 | } 67 | 68 | } 69 | 70 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/AbstractTempleFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import kaptainwutax.seedcrackerX.finder.Finder; 4 | import kaptainwutax.seedcrackerX.render.Color; 5 | import kaptainwutax.seedcrackerX.render.Cube; 6 | import kaptainwutax.seedcrackerX.render.Cuboid; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.Direction; 9 | import net.minecraft.core.Vec3i; 10 | import net.minecraft.world.level.ChunkPos; 11 | import net.minecraft.world.level.Level; 12 | import net.minecraft.world.level.biome.Biome; 13 | import net.minecraft.world.level.dimension.DimensionType; 14 | 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | public abstract class AbstractTempleFinder extends Finder { 21 | 22 | protected static List SEARCH_POSITIONS; 23 | protected final Vec3i size; 24 | protected List finders = new ArrayList<>(); 25 | 26 | public AbstractTempleFinder(Level world, ChunkPos chunkPos, Vec3i size) { 27 | super(world, chunkPos); 28 | 29 | Direction.Plane.HORIZONTAL.forEach(direction -> { 30 | PieceFinder finder = new PieceFinder(world, chunkPos, direction, size); 31 | 32 | finder.searchPositions = SEARCH_POSITIONS; 33 | 34 | buildStructure(finder); 35 | this.finders.add(finder); 36 | }); 37 | 38 | this.size = size; 39 | } 40 | 41 | public static void reloadSearchPositions() { 42 | SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 43 | if (pos.getX() != 0) return true; 44 | if (pos.getY() < 0) return true; 45 | if (pos.getY() > 200) return true; 46 | return pos.getZ() != 0; 47 | }); 48 | } 49 | 50 | public List findInChunkPiece(PieceFinder pieceFinder) { 51 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 64, (this.chunkPos.z << 2) + 2).value(); 52 | 53 | if (!isValidBiome(biome)) { 54 | return new ArrayList<>(); 55 | } 56 | 57 | return pieceFinder.findInChunk(); 58 | } 59 | 60 | protected abstract boolean isValidBiome(Biome biome); 61 | 62 | public void addRenderers(PieceFinder pieceFinder, BlockPos origin, Color color) { 63 | this.renderers.add(new Cuboid(origin, pieceFinder.getLayout(), color)); 64 | BlockPos chunkStart = new BlockPos(origin.getX() & -16, origin.getY(), origin.getZ() & -16); 65 | this.renderers.add(new Cube(chunkStart, color)); 66 | } 67 | 68 | public Map> findInChunkPieces() { 69 | Map> result = new HashMap<>(); 70 | 71 | this.finders.forEach(pieceFinder -> { 72 | result.put(pieceFinder, this.findInChunkPiece(pieceFinder)); 73 | }); 74 | 75 | return result; 76 | } 77 | 78 | public abstract void buildStructure(PieceFinder finder); 79 | 80 | @Override 81 | public boolean isValidDimension(DimensionType dimension) { 82 | return this.isOverworld(dimension); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/decorator/DeepDungeon.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker.decorator; 2 | 3 | import com.seedfinding.mcbiome.biome.Biome; 4 | import com.seedfinding.mcbiome.biome.Biomes; 5 | import com.seedfinding.mccore.rand.ChunkRand; 6 | import com.seedfinding.mccore.state.Dimension; 7 | import com.seedfinding.mccore.version.MCVersion; 8 | import com.seedfinding.mccore.version.VersionMap; 9 | import net.minecraft.world.level.levelgen.WorldgenRandom; 10 | 11 | public class DeepDungeon extends Decorator { 12 | 13 | public static final VersionMap CONFIGS = new VersionMap() 14 | .add(MCVersion.v1_18, new Decorator.Config(3, 3)); 15 | 16 | public DeepDungeon(MCVersion version) { 17 | super(CONFIGS.getAsOf(version), version); 18 | } 19 | 20 | @Override 21 | public String getName() { 22 | return "dungeon"; 23 | } 24 | 25 | @Override 26 | public boolean canStart(DeepDungeon.Data data, long structureSeed, ChunkRand rand) { 27 | return true; 28 | } 29 | 30 | @Override 31 | public boolean canStart(DeepDungeon.Data data, long worldSeed, WorldgenRandom rand) { 32 | super.canStart(data, worldSeed, rand); 33 | int x, y, z; 34 | 35 | for (int i = 0; i < 4; i++) { 36 | 37 | x = rand.nextInt(16); 38 | z = rand.nextInt(16); 39 | y = rand.nextInt(58)-58; 40 | 41 | if (y == data.blockY && x == data.offsetX && z == data.offsetZ) { 42 | return true; 43 | } 44 | 45 | rand.nextInt(2); 46 | rand.nextInt(2); 47 | } 48 | return false; 49 | } 50 | 51 | @Override 52 | public boolean isValidDimension(Dimension dimension) { 53 | return dimension == Dimension.OVERWORLD; 54 | } 55 | 56 | @Override 57 | public Dimension getValidDimension() { 58 | return Dimension.OVERWORLD; 59 | } 60 | 61 | @Override 62 | public boolean isValidBiome(Biome biome) { 63 | return biome != Biomes.NETHER_WASTES && biome != Biomes.SOUL_SAND_VALLEY && biome != Biomes.WARPED_FOREST 64 | && biome != Biomes.CRIMSON_FOREST && biome != Biomes.BASALT_DELTAS && biome != Biomes.END_MIDLANDS 65 | && biome != Biomes.END_HIGHLANDS && biome != Biomes.END_BARRENS && biome != Biomes.SMALL_END_ISLANDS 66 | && biome != Biomes.THE_VOID && biome == Biomes.THE_END; 67 | } 68 | 69 | public DeepDungeon.Data at(int blockX, int blockY, int blockZ, Biome biome) { 70 | return new DeepDungeon.Data(this, blockX, blockY, blockZ, biome); 71 | } 72 | 73 | public static class Data extends Decorator.Data { 74 | 75 | public final int offsetX; 76 | public final int offsetZ; 77 | public final int blockY; 78 | 79 | public Data(DeepDungeon feature, int blockX, int blockY, int blockZ, Biome biome) { 80 | super(feature, blockX >> 4, blockZ >> 4, biome); 81 | this.offsetX = blockX & 15; 82 | this.offsetZ = blockZ & 15; 83 | this.blockY = blockY; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/util/BiomeFixer.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.util; 2 | 3 | import com.seedfinding.mcbiome.biome.Biome; 4 | import com.seedfinding.mcbiome.biome.Biomes; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.multiplayer.ClientPacketListener; 7 | import net.minecraft.core.registries.Registries; 8 | import net.minecraft.data.registries.VanillaRegistries; 9 | import net.minecraft.resources.ResourceKey; 10 | import net.minecraft.resources.ResourceLocation; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | public class BiomeFixer { 16 | 17 | private static final Map COMPATREGISTRY = new HashMap<>(); 18 | 19 | static { 20 | for (Biome biome : Biomes.REGISTRY.values()) { 21 | COMPATREGISTRY.put(biome.getName(), biome); 22 | } 23 | //renamed 24 | COMPATREGISTRY.put("snowy_plains", Biomes.SNOWY_TUNDRA); 25 | COMPATREGISTRY.put("old_growth_birch_forest", Biomes.TALL_BIRCH_FOREST); 26 | COMPATREGISTRY.put("old_growth_pine_taiga", Biomes.GIANT_TREE_TAIGA); 27 | COMPATREGISTRY.put("old_growth_spruce_taiga", Biomes.GIANT_TREE_TAIGA); 28 | COMPATREGISTRY.put("windswept_hills", Biomes.EXTREME_HILLS); 29 | COMPATREGISTRY.put("windswept_forest", Biomes.WOODED_MOUNTAINS); 30 | COMPATREGISTRY.put("windswept_gravelly_hills", Biomes.GRAVELLY_MOUNTAINS); 31 | COMPATREGISTRY.put("windswept_savanna", Biomes.SHATTERED_SAVANNA); 32 | COMPATREGISTRY.put("sparse_jungle", Biomes.JUNGLE_EDGE); 33 | COMPATREGISTRY.put("stony_shore", Biomes.STONE_SHORE); 34 | //new 35 | COMPATREGISTRY.put("meadow", Biomes.PLAINS); 36 | COMPATREGISTRY.put("grove", Biomes.TAIGA); 37 | COMPATREGISTRY.put("snowy_slopes", Biomes.SNOWY_TUNDRA); 38 | COMPATREGISTRY.put("frozen_peaks", Biomes.TAIGA); 39 | COMPATREGISTRY.put("jagged_peaks", Biomes.TAIGA); 40 | COMPATREGISTRY.put("stony_peaks", Biomes.TAIGA); 41 | COMPATREGISTRY.put("mangrove_swamp", Biomes.SWAMP); 42 | 43 | //unsure what to do with those, they'll return THE_VOID for now 44 | //dripstone_caves 45 | //lush_caves 46 | //deep_dark 47 | } 48 | 49 | public static Biome swap(net.minecraft.world.level.biome.Biome biome) { 50 | ClientPacketListener networkHandler = Minecraft.getInstance().getConnection(); 51 | if (networkHandler == null) return Biomes.VOID; 52 | 53 | ResourceLocation biomeID = networkHandler.registryAccess().registryOrThrow(Registries.BIOME).getKey(biome); 54 | 55 | if (biomeID == null) return Biomes.THE_VOID; 56 | 57 | return COMPATREGISTRY.getOrDefault(biomeID.getPath(), Biomes.VOID); 58 | } 59 | 60 | public static net.minecraft.world.level.biome.Biome swap(Biome biome) { 61 | // internal, meh 62 | var biomeRegistries = VanillaRegistries.createLookup().lookupOrThrow(Registries.BIOME); 63 | 64 | return biomeRegistries.get(ResourceKey.create(Registries.BIOME, new ResourceLocation(biome.getName()))).orElse( 65 | biomeRegistries.getOrThrow(net.minecraft.world.level.biome.Biomes.THE_VOID) 66 | ).value(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/decorator/EndGatewayFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.decorator; 2 | 3 | import com.seedfinding.mcfeature.decorator.EndGateway; 4 | import kaptainwutax.seedcrackerX.Features; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.finder.BlockFinder; 8 | import kaptainwutax.seedcrackerX.finder.Finder; 9 | import kaptainwutax.seedcrackerX.render.Color; 10 | import kaptainwutax.seedcrackerX.render.Cuboid; 11 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 12 | import net.minecraft.core.BlockPos; 13 | import net.minecraft.world.level.ChunkPos; 14 | import net.minecraft.world.level.Level; 15 | import net.minecraft.world.level.biome.Biome; 16 | import net.minecraft.world.level.block.Blocks; 17 | import net.minecraft.world.level.block.state.BlockState; 18 | import net.minecraft.world.level.dimension.DimensionType; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | public class EndGatewayFinder extends BlockFinder { 24 | 25 | public EndGatewayFinder(Level world, ChunkPos chunkPos) { 26 | super(world, chunkPos, Blocks.END_GATEWAY); 27 | this.searchPositions = CHUNK_POSITIONS; 28 | } 29 | 30 | public static List create(Level world, ChunkPos chunkPos) { 31 | List finders = new ArrayList<>(); 32 | finders.add(new EndGatewayFinder(world, chunkPos)); 33 | return finders; 34 | } 35 | 36 | @Override 37 | public List findInChunk() { 38 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 64, (this.chunkPos.z << 2) + 2).value(); 39 | if(!Features.END_GATEWAY.isValidBiome(BiomeFixer.swap(biome)))return new ArrayList<>(); 40 | 41 | List result = super.findInChunk(); 42 | List newResult = new ArrayList<>(); 43 | 44 | result.forEach(pos -> { 45 | int height = this.findHeight(pos); 46 | 47 | if (height >= 3 && height <= 9) { 48 | newResult.add(pos); 49 | 50 | EndGateway.Data data = Features.END_GATEWAY.at(pos.getX(), pos.getZ(), height); 51 | 52 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 53 | this.renderers.add(new Cuboid(pos.offset(-1, -2, -1), pos.offset(2, 3, 2), new Color(102, 102, 210))); 54 | } 55 | } 56 | }); 57 | 58 | return newResult; 59 | } 60 | 61 | private int findHeight(BlockPos pos) { 62 | int height = 0; 63 | 64 | while (pos.getY() >= 0) { 65 | pos = pos.below(); 66 | height++; 67 | 68 | BlockState state = this.world.getBlockState(pos); 69 | 70 | //Bedrock generates below gateways. 71 | if (state.getBlock() == Blocks.BEDROCK || state.getBlock() != Blocks.END_STONE) { 72 | continue; 73 | } 74 | 75 | break; 76 | } 77 | 78 | return height - 1; 79 | } 80 | 81 | @Override 82 | public boolean isValidDimension(DimensionType dimension) { 83 | return this.isEnd(dimension); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/mixin/ClientPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.mixin; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import kaptainwutax.seedcrackerX.SeedCracker; 5 | import kaptainwutax.seedcrackerX.config.Config; 6 | import kaptainwutax.seedcrackerX.config.StructureSave; 7 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 8 | import kaptainwutax.seedcrackerX.cracker.HashedSeedData; 9 | import kaptainwutax.seedcrackerX.finder.FinderQueue; 10 | import kaptainwutax.seedcrackerX.finder.ReloadFinders; 11 | import kaptainwutax.seedcrackerX.util.Log; 12 | import net.minecraft.client.Minecraft; 13 | import net.minecraft.client.multiplayer.ClientLevel; 14 | import net.minecraft.client.multiplayer.ClientPacketListener; 15 | import net.minecraft.commands.CommandSource; 16 | import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; 17 | import net.minecraft.network.protocol.game.ClientboundLoginPacket; 18 | import net.minecraft.network.protocol.game.ClientboundRespawnPacket; 19 | import net.minecraft.world.level.ChunkPos; 20 | import net.minecraft.world.level.dimension.DimensionType; 21 | import org.spongepowered.asm.mixin.Mixin; 22 | import org.spongepowered.asm.mixin.Shadow; 23 | import org.spongepowered.asm.mixin.injection.At; 24 | import org.spongepowered.asm.mixin.injection.Inject; 25 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 26 | 27 | @Mixin(ClientPacketListener.class) 28 | public abstract class ClientPlayNetworkHandlerMixin { 29 | 30 | @Shadow private ClientLevel level; 31 | 32 | @Inject(method = "handleLevelChunkWithLight", at = @At(value = "TAIL")) 33 | private void onChunkData(ClientboundLevelChunkWithLightPacket packet, CallbackInfo ci) { 34 | int chunkX = packet.getX(); 35 | int chunkZ = packet.getZ(); 36 | FinderQueue.get().onChunkData(this.level, new ChunkPos(chunkX, chunkZ)); 37 | } 38 | 39 | @Inject(method = "handleLogin", at = @At(value = "TAIL")) 40 | public void onGameJoin(ClientboundLoginPacket packet, CallbackInfo ci) { 41 | newDimension(new HashedSeedData(packet.seed()), false); 42 | var preloaded = StructureSave.loadStructures(); 43 | if (!preloaded.isEmpty()) { 44 | Log.warn("foundRestorableStructures", preloaded.size()); 45 | } 46 | } 47 | 48 | @Inject(method = "handleRespawn", at = @At(value = "TAIL")) 49 | public void onPlayerRespawn(ClientboundRespawnPacket packet, CallbackInfo ci) { 50 | newDimension(new HashedSeedData(packet.getSeed()), true); 51 | } 52 | 53 | public void newDimension(HashedSeedData hashedSeedData, boolean dimensionChange) { 54 | DimensionType dimension = Minecraft.getInstance().level.dimensionType(); 55 | ReloadFinders.reloadHeight(dimension.minY(), dimension.minY() + dimension.logicalHeight()); 56 | 57 | if (SeedCracker.get().getDataStorage().addHashedSeedData(hashedSeedData, DataAddedEvent.POKE_BIOMES) && Config.get().active && dimensionChange) { 58 | Log.error(Log.translate("fetchedHashedSeed")); 59 | if (Config.get().debug) { 60 | Log.error("Hashed seed [" + hashedSeedData.getHashedSeed() + "]"); 61 | } 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/command/FinderCommand.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import kaptainwutax.seedcrackerX.config.Config; 5 | import kaptainwutax.seedcrackerX.finder.Finder; 6 | import kaptainwutax.seedcrackerX.finder.ReloadFinders; 7 | import kaptainwutax.seedcrackerX.util.Log; 8 | import net.minecraft.ChatFormatting; 9 | import net.minecraft.commands.CommandSourceStack; 10 | 11 | import static net.minecraft.commands.Commands.literal; 12 | 13 | public class FinderCommand extends ClientCommand { 14 | ReloadFinders reloadFinders = new ReloadFinders(); 15 | 16 | @Override 17 | public String getName() { 18 | return "finder"; 19 | } 20 | 21 | @Override 22 | public void build(LiteralArgumentBuilder builder) { 23 | for (Finder.Type finderType : Finder.Type.values()) { 24 | builder.then(literal("type") 25 | .then(literal(finderType.toString()) 26 | .then(literal("ON").executes(context -> this.setFinderType(finderType, true, true))) 27 | .then(literal("OFF").executes(context -> this.setFinderType(finderType, false, true))) 28 | .executes(context -> this.printFinderType(finderType))) 29 | ); 30 | } 31 | 32 | for (Finder.Category finderCategory : Finder.Category.values()) { 33 | builder.then(literal("category") 34 | .then(literal(finderCategory.toString()) 35 | .then(literal("ON").executes(context -> this.setFinderCategory(finderCategory, true))) 36 | .then(literal("OFF").executes(context -> this.setFinderCategory(finderCategory, false))) 37 | .executes(context -> this.printFinderCategory(finderCategory))) 38 | ); 39 | } 40 | builder.then(literal("reload").executes(context -> this.reload())); 41 | } 42 | 43 | private int printFinderCategory(Finder.Category finderCategory) { 44 | Finder.Type.getForCategory(finderCategory).forEach(this::printFinderType); 45 | return 0; 46 | } 47 | 48 | private int printFinderType(Finder.Type finderType) { 49 | sendFeedback(Log.translate("finder.isFinder").formatted(Log.translate(finderType.nameKey)) + " [" + String.valueOf(finderType.enabled.get()).toUpperCase() + "].", ChatFormatting.AQUA, false); 50 | return 0; 51 | } 52 | 53 | private int setFinderCategory(Finder.Category finderCategory, boolean flag) { 54 | Finder.Type.getForCategory(finderCategory).forEach(finderType -> this.setFinderType(finderType, flag, false)); 55 | Config.save(); 56 | return 0; 57 | } 58 | 59 | private int setFinderType(Finder.Type finderType, boolean flag, boolean save) { 60 | finderType.enabled.set(flag); 61 | if (save) Config.save(); 62 | sendFeedback(Log.translate("finder.setFinder").formatted(Log.translate(finderType.nameKey)) + " [" + String.valueOf(flag).toUpperCase() + "].", ChatFormatting.AQUA, false); 63 | return 0; 64 | } 65 | 66 | private int reload() { 67 | reloadFinders.reload(); 68 | return 0; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/BiomeFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | import com.seedfinding.mcbiome.biome.Biomes; 4 | import com.seedfinding.mccore.version.MCVersion; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.config.Config; 7 | import kaptainwutax.seedcrackerX.cracker.BiomeData; 8 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 9 | import kaptainwutax.seedcrackerX.render.Color; 10 | import kaptainwutax.seedcrackerX.render.Cube; 11 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 12 | import kaptainwutax.seedcrackerX.util.Log; 13 | import net.minecraft.core.BlockPos; 14 | import net.minecraft.world.level.ChunkPos; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraft.world.level.biome.Biome; 17 | import net.minecraft.world.level.dimension.DimensionType; 18 | import net.minecraft.world.level.levelgen.Heightmap; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | public class BiomeFinder extends Finder { 24 | 25 | public BiomeFinder(Level world, ChunkPos chunkPos) { 26 | super(world, chunkPos); 27 | } 28 | 29 | public static List create(Level world, ChunkPos chunkPos) { 30 | List finders = new ArrayList<>(); 31 | finders.add(new BiomeFinder(world, chunkPos)); 32 | return finders; 33 | } 34 | 35 | @Override 36 | public List findInChunk() { 37 | List result = new ArrayList<>(); 38 | 39 | for (int x = 0; x < 16; x += 4) { 40 | for (int z = 0; z < 16; z += 4) { 41 | BlockPos blockPos = this.chunkPos.getWorldPosition().offset(x, 0, z); 42 | Biome biome; 43 | if (Config.get().getVersion().isNewerOrEqualTo(MCVersion.v1_15)) { 44 | biome = this.world.getNoiseBiome(blockPos.getX() >> 2, 0, blockPos.getZ() >> 2).value(); 45 | } else { 46 | biome = this.world.getBiome(blockPos).value(); 47 | 48 | } 49 | com.seedfinding.mcbiome.biome.Biome otherBiome = BiomeFixer.swap(biome); 50 | if (otherBiome == Biomes.THE_VOID) { 51 | continue; 52 | } 53 | 54 | BiomeData data; 55 | if (Config.get().getVersion().isNewerOrEqualTo(MCVersion.v1_15)) { 56 | data = new BiomeData(otherBiome, blockPos.getX() >> 2, blockPos.getZ() >> 2); 57 | } else { 58 | data = new BiomeData(otherBiome, blockPos.getX(), blockPos.getZ()); 59 | } 60 | if (SeedCracker.get().getDataStorage().addBiomeData(data, DataAddedEvent.POKE_BIOMES)) { 61 | blockPos = this.world.getHeightmapPos(Heightmap.Types.WORLD_SURFACE, blockPos).below(); 62 | if (Config.get().debug) Log.warn(blockPos.toShortString() + ", " + otherBiome.getName()); 63 | result.add(blockPos); 64 | } 65 | } 66 | } 67 | result.forEach(pos -> this.renderers.add(new Cube(pos, new Color(51, 204, 128)))); 68 | 69 | return result; 70 | } 71 | 72 | @Override 73 | public boolean isValidDimension(DimensionType dimension) { 74 | return this.isOverworld(dimension); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/config/Config.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.config; 2 | 3 | 4 | import com.google.gson.Gson; 5 | import com.google.gson.GsonBuilder; 6 | import com.seedfinding.mccore.version.MCVersion; 7 | import kaptainwutax.seedcrackerX.Features; 8 | import kaptainwutax.seedcrackerX.util.FeatureToggle; 9 | 10 | import net.minecraftforge.fml.loading.FMLPaths; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.io.*; 15 | 16 | public class Config { 17 | private static final Logger logger = LoggerFactory.getLogger("config"); 18 | 19 | private static final File file = new File(FMLPaths.CONFIGDIR.get().toFile(), "seedcracker.json"); 20 | private static Config INSTANCE = new Config(); 21 | public FeatureToggle buriedTreasure = new FeatureToggle(true); 22 | public FeatureToggle desertTemple = new FeatureToggle(true); 23 | public FeatureToggle endCity = new FeatureToggle(true); 24 | public FeatureToggle jungleTemple = new FeatureToggle(true); 25 | public FeatureToggle monument = new FeatureToggle(true); 26 | public FeatureToggle swampHut = new FeatureToggle(true); 27 | public FeatureToggle shipwreck = new FeatureToggle(true); 28 | public FeatureToggle outpost = new FeatureToggle(true); 29 | public FeatureToggle igloo = new FeatureToggle(true); 30 | public FeatureToggle endPillars = new FeatureToggle(true); 31 | public FeatureToggle endGateway = new FeatureToggle(false); 32 | public FeatureToggle dungeon = new FeatureToggle(true); 33 | public FeatureToggle emeraldOre = new FeatureToggle(false); 34 | public FeatureToggle desertWell = new FeatureToggle(false); 35 | public FeatureToggle warpedFungus = new FeatureToggle(false); 36 | public FeatureToggle biome = new FeatureToggle(false); 37 | public RenderType render = RenderType.XRAY; 38 | public boolean active = true; 39 | public boolean debug = false; 40 | public boolean antiXrayBypass = true; 41 | private MCVersion version = MCVersion.latest(); 42 | public boolean databaseSubmits = false; 43 | public boolean anonymusSubmits = false; 44 | 45 | public static void save() { 46 | Gson gson = new GsonBuilder().setPrettyPrinting().create(); 47 | // make sure that the config directory exists 48 | file.getParentFile().mkdirs(); 49 | 50 | try (FileWriter writer = new FileWriter(file)) { 51 | gson.toJson(INSTANCE, writer); 52 | } catch (IOException e) { 53 | logger.error("seedcracker couldn't save config", e); 54 | } 55 | } 56 | 57 | public static void load() { 58 | Gson gson = new Gson(); 59 | 60 | if (!file.exists()) return; 61 | 62 | try (Reader reader = new FileReader(file)) { 63 | INSTANCE = gson.fromJson(reader, Config.class); 64 | } catch (Exception e) { 65 | logger.error("seedcracker couldn't load config, deleting it...", e); 66 | file.delete(); 67 | } 68 | } 69 | 70 | public static Config get() { 71 | return INSTANCE; 72 | } 73 | 74 | public MCVersion getVersion() { 75 | return version; 76 | } 77 | 78 | public void setVersion(MCVersion version) { 79 | if (this.version == version) return; 80 | this.version = version; 81 | Features.init(version); 82 | } 83 | 84 | public enum RenderType { 85 | OFF, ON, XRAY 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/util/Log.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.util; 2 | 3 | import net.minecraft.ChatFormatting; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.locale.Language; 6 | import net.minecraft.network.chat.ClickEvent; 7 | import net.minecraft.network.chat.Component; 8 | import net.minecraft.network.chat.ComponentUtils; 9 | import net.minecraft.network.chat.HoverEvent; 10 | import net.minecraft.world.entity.player.Player; 11 | 12 | import java.util.regex.Pattern; 13 | 14 | public class Log { 15 | 16 | public static void debug(String message) { 17 | Player player = getPlayer(); 18 | 19 | if (player != null) { 20 | schedule(() -> player.displayClientMessage(Component.literal(message), false)); 21 | } 22 | } 23 | 24 | public static void warn(String translateKey, Object... args) { 25 | String message = translate(translateKey).formatted(args); 26 | Player player = getPlayer(); 27 | 28 | if (player != null) { 29 | schedule(() -> player.displayClientMessage(Component.literal(message).withStyle(ChatFormatting.GREEN), false)); 30 | } 31 | } 32 | 33 | public static void warn(String translateKey) { 34 | warn(translateKey, new Object[]{}); 35 | } 36 | 37 | public static void error(String translateKey) { 38 | String message = translate(translateKey); 39 | Player player = getPlayer(); 40 | 41 | if (player != null) { 42 | schedule(() -> player.displayClientMessage(Component.literal(message).withStyle(ChatFormatting.RED), false)); 43 | } 44 | } 45 | 46 | public static void printSeed(String translateKey, long seedValue) { 47 | String message = translate(translateKey); 48 | String[] data = message.split(Pattern.quote("${SEED}")); 49 | String seed = String.valueOf(seedValue); 50 | Component component = ComponentUtils.wrapInSquareBrackets((Component.literal(seed)).withStyle(style -> style.withColor(ChatFormatting.GREEN).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, seed)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable("chat.copy.click"))).withInsertion(seed))); 51 | 52 | Player player = getPlayer(); 53 | 54 | if (player != null) { 55 | schedule(() -> player.displayClientMessage(Component.literal(data[0]).append(component).append(Component.literal(data[1])), false)); 56 | } 57 | } 58 | 59 | public static void printDungeonInfo(String message) { 60 | Component component = ComponentUtils.wrapInSquareBrackets((Component.literal(message)).withStyle(style -> style.withColor(ChatFormatting.GREEN).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, message)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable("chat.copy.click"))).withInsertion(message))); 61 | 62 | Player player = getPlayer(); 63 | 64 | if (player != null) { 65 | schedule(() -> player.displayClientMessage(component, false)); 66 | } 67 | } 68 | 69 | public static String translate(String translateKey) { 70 | return Language.getInstance().getOrDefault(translateKey); 71 | } 72 | 73 | private static void schedule(Runnable runnable) { 74 | Minecraft.getInstance().execute(runnable); 75 | } 76 | 77 | private static Player getPlayer() { 78 | return Minecraft.getInstance().player; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/decorator/Decorator.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker.decorator; 2 | 3 | import com.seedfinding.mcbiome.biome.Biome; 4 | import com.seedfinding.mcbiome.source.BiomeSource; 5 | import com.seedfinding.mccore.rand.ChunkRand; 6 | import com.seedfinding.mccore.version.MCVersion; 7 | import com.seedfinding.mcfeature.Feature; 8 | import com.seedfinding.mcterrain.TerrainGenerator; 9 | import net.minecraft.world.level.levelgen.WorldgenRandom; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public abstract class Decorator> extends Feature { 15 | 16 | public Decorator(C config, MCVersion version) { 17 | super(config, version); 18 | } 19 | 20 | public int getIndex(Biome biome) { 21 | return this.getConfig().getSalt(biome) % 10000; 22 | } 23 | 24 | public int getStep(Biome biome) { 25 | return this.getConfig().getSalt(biome) / 10000; 26 | } 27 | 28 | @Override 29 | public boolean canStart(D data, long structureSeed, ChunkRand rand) { 30 | rand.setDecoratorSeed(structureSeed, data.chunkX << 4, data.chunkZ << 4, 31 | this.getIndex(data.biome), this.getStep(data.biome), this.getVersion()); 32 | return true; 33 | } 34 | 35 | public boolean canStart(D data, long worldSeed, WorldgenRandom rand) { 36 | long l = rand.setDecorationSeed(worldSeed, data.chunkX << 4, data.chunkZ << 4); 37 | rand.setFeatureSeed(l, this.getIndex(data.biome), this.getStep(data.biome)); 38 | return true; 39 | } 40 | 41 | @Override 42 | public boolean canGenerate(D data, TerrainGenerator generator) { 43 | return true; 44 | } 45 | 46 | @Override 47 | public final boolean canSpawn(D data, BiomeSource source) { 48 | return this.canSpawn(data.chunkX, data.chunkZ, source); 49 | } 50 | 51 | public boolean canSpawn(int chunkX, int chunkZ, BiomeSource source) { 52 | if (this.getVersion().isOlderThan(MCVersion.v1_16)) { 53 | return this.isValidBiome(source.getBiome((chunkX << 4) + 8, 0, (chunkZ << 4) + 8)); 54 | } 55 | 56 | return this.isValidBiome(source.getBiomeForNoiseGen((chunkX << 2) + 2, 0, (chunkZ << 2) + 2)); 57 | } 58 | 59 | public abstract boolean isValidBiome(Biome biome); 60 | 61 | public static class Config extends Feature.Config { 62 | public final int defaultSalt; 63 | public final Map salts = new HashMap<>(); 64 | 65 | public Config(int step, int index) { 66 | this.defaultSalt = step * 10000 + index; 67 | } 68 | 69 | public Config add(int step, int index, Biome... biomes) { 70 | for (Biome biome : biomes) { 71 | this.salts.put(biome, step * 10000 + index); 72 | } 73 | 74 | return this; 75 | } 76 | 77 | public int getSalt(Biome biome) { 78 | return this.salts.getOrDefault(biome, this.defaultSalt); 79 | } 80 | } 81 | 82 | public static class Data> extends Feature.Data { 83 | public final Biome biome; 84 | 85 | public Data(T feature, int chunkX, int chunkZ, Biome biome) { 86 | super(feature, chunkX, chunkZ); 87 | this.biome = biome; 88 | } 89 | 90 | public boolean testStart(long worldSeed, WorldgenRandom rand) { 91 | return ((Decorator) this.feature).canStart(this, worldSeed, rand); 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Sets default memory used for gradle commands. Can be overridden by user or command line properties. 2 | # This is required to provide enough memory for the Minecraft decompilation process. 3 | org.gradle.jvmargs=-Xmx4G 4 | org.gradle.daemon=false 5 | 6 | 7 | ## Environment Properties 8 | 9 | # The Minecraft version must agree with the Forge version to get a valid artifact 10 | minecraft_version=1.20.1 11 | # The Minecraft version range can use any release version of Minecraft as bounds. 12 | # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly 13 | # as they do not follow standard versioning conventions. 14 | minecraft_version_range=[1.20.1,1.21) 15 | # The Forge version must agree with the Minecraft version to get a valid artifact 16 | forge_version=47.1.43 17 | # The Forge version range can use any version of Forge as bounds or match the loader version range 18 | forge_version_range=[47,) 19 | # The loader version range can only use the major version of Forge/FML as bounds 20 | loader_version_range=[47,) 21 | # The mapping channel to use for mappings. 22 | # The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"]. 23 | # Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin. 24 | # 25 | # | Channel | Version | | 26 | # |-----------|----------------------|--------------------------------------------------------------------------------| 27 | # | official | MCVersion | Official field/method names from Mojang mapping files | 28 | # | parchment | YYYY.MM.DD-MCVersion | Open community-sourced parameter names and javadocs layered on top of official | 29 | # 30 | # You must be aware of the Mojang license when using the 'official' or 'parchment' mappings. 31 | # See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md 32 | # 33 | # Parchment is an unofficial project maintained by ParchmentMC, separate from Minecraft Forge. 34 | # Additional setup is needed to use their mappings, see https://parchmentmc.org/docs/getting-started 35 | mapping_channel=official 36 | # The mapping version to query from the mapping channel. 37 | # This must match the format required by the mapping channel. 38 | mapping_version=1.20.1 39 | 40 | 41 | ## Mod Properties 42 | 43 | # The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} 44 | # Must match the String constant located in the main mod class annotated with @Mod. 45 | mod_id=seedcracker 46 | # The human-readable display name for the mod. 47 | mod_name=SeedCrackerX 48 | # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. 49 | mod_license=All Rights Reserved 50 | # The mod version. See https://semver.org/ 51 | mod_version=2.14.4.1 52 | # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. 53 | # This should match the base package used for the mod sources. 54 | # See https://maven.apache.org/guides/mini/guide-naming-conventions.html 55 | mod_group_id=kaptainwutax.seedcrackerX 56 | # The authors of the mod. This is a simple text string that is used for display purposes in the mod list. 57 | mod_authors=thePlaceholder, 19MisterX98 58 | # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. 59 | mod_description=a port of 19MisterX98's SeedcrackerX for forge -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/render/Cuboid.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.render; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import com.mojang.blaze3d.vertex.VertexConsumer; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.core.Vec3i; 7 | import net.minecraft.world.level.levelgen.structure.BoundingBox; 8 | import net.minecraft.world.phys.Vec3; 9 | 10 | public class Cuboid extends Renderer { 11 | 12 | private final Line[] edges = new Line[12]; 13 | public BlockPos start; 14 | public Vec3i size; 15 | public BlockPos pos; 16 | 17 | public Cuboid() { 18 | this(BlockPos.ZERO, BlockPos.ZERO, Color.WHITE); 19 | } 20 | 21 | public Cuboid(BlockPos pos) { 22 | this(pos, new BlockPos(1, 1, 1), Color.WHITE); 23 | } 24 | 25 | public Cuboid(BlockPos start, BlockPos end, Color color) { 26 | this(start, new Vec3i(end.getX() - start.getX(), end.getY() - start.getY(), end.getZ() - start.getZ()), color); 27 | } 28 | 29 | public Cuboid(BoundingBox box, Color color) { 30 | this(new BlockPos(box.minX(), box.minY(), box.minZ()), new BlockPos(box.maxX(), box.maxY(), box.maxZ()), color); 31 | } 32 | 33 | public Cuboid(BlockPos start, Vec3i size, Color color) { 34 | this.start = start; 35 | this.size = size; 36 | this.pos = this.start.offset(this.size.getX() / 2, this.size.getY() / 2, this.size.getZ() / 2); 37 | this.edges[0] = new Line(toVec3d(this.start), toVec3d(this.start.offset(this.size.getX(), 0, 0)), color); 38 | this.edges[1] = new Line(toVec3d(this.start), toVec3d(this.start.offset(0, this.size.getY(), 0)), color); 39 | this.edges[2] = new Line(toVec3d(this.start), toVec3d(this.start.offset(0, 0, this.size.getZ())), color); 40 | this.edges[3] = new Line(toVec3d(this.start.offset(this.size.getX(), 0, this.size.getZ())), toVec3d(this.start.offset(this.size.getX(), 0, 0)), color); 41 | this.edges[4] = new Line(toVec3d(this.start.offset(this.size.getX(), 0, this.size.getZ())), toVec3d(this.start.offset(this.size.getX(), this.size.getY(), this.size.getZ())), color); 42 | this.edges[5] = new Line(toVec3d(this.start.offset(this.size.getX(), 0, this.size.getZ())), toVec3d(this.start.offset(0, 0, this.size.getZ())), color); 43 | this.edges[6] = new Line(toVec3d(this.start.offset(this.size.getX(), this.size.getY(), 0)), toVec3d(this.start.offset(this.size.getX(), 0, 0)), color); 44 | this.edges[7] = new Line(toVec3d(this.start.offset(this.size.getX(), this.size.getY(), 0)), toVec3d(this.start.offset(0, this.size.getY(), 0)), color); 45 | this.edges[8] = new Line(toVec3d(this.start.offset(this.size.getX(), this.size.getY(), 0)), toVec3d(this.start.offset(this.size.getX(), this.size.getY(), this.size.getZ())), color); 46 | this.edges[9] = new Line(toVec3d(this.start.offset(0, this.size.getY(), this.size.getZ())), toVec3d(this.start.offset(0, 0, this.size.getZ())), color); 47 | this.edges[10] = new Line(toVec3d(this.start.offset(0, this.size.getY(), this.size.getZ())), toVec3d(this.start.offset(0, this.size.getY(), 0)), color); 48 | this.edges[11] = new Line(toVec3d(this.start.offset(0, this.size.getY(), this.size.getZ())), toVec3d(this.start.offset(this.size.getX(), this.size.getY(), this.size.getZ())), color); 49 | } 50 | 51 | @Override 52 | public void render(PoseStack matrixStack, VertexConsumer vertexConsumer, Vec3 cameraPos) { 53 | if (this.start == null || this.size == null || this.edges == null) return; 54 | 55 | for (Line edge : this.edges) { 56 | if (edge == null) continue; 57 | edge.render(matrixStack, vertexConsumer, cameraPos); 58 | } 59 | } 60 | 61 | @Override 62 | public BlockPos getPos() { 63 | return pos; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/FinderQueue.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | import com.mojang.blaze3d.platform.GlStateManager; 4 | import com.mojang.blaze3d.systems.RenderSystem; 5 | import com.mojang.blaze3d.vertex.*; 6 | import kaptainwutax.seedcrackerX.config.Config; 7 | import net.minecraft.client.Camera; 8 | import net.minecraft.client.renderer.GameRenderer; 9 | import net.minecraft.world.level.ChunkPos; 10 | import net.minecraft.world.level.Level; 11 | import net.minecraft.world.phys.Vec3; 12 | 13 | import java.util.Arrays; 14 | import java.util.List; 15 | import java.util.concurrent.ExecutorService; 16 | import java.util.concurrent.Executors; 17 | import java.util.stream.Collectors; 18 | 19 | public class FinderQueue { 20 | 21 | private final static FinderQueue INSTANCE = new FinderQueue(); 22 | public static ExecutorService SERVICE = Executors.newFixedThreadPool(5); 23 | 24 | public FinderControl finderControl = new FinderControl(); 25 | 26 | private FinderQueue() { 27 | this.clear(); 28 | } 29 | 30 | public static FinderQueue get() { 31 | return INSTANCE; 32 | } 33 | 34 | public void onChunkData(Level world, ChunkPos chunkPos) { 35 | if (!Config.get().active) return; 36 | 37 | getActiveFinderTypes().forEach(type -> { 38 | SERVICE.submit(() -> { 39 | try { 40 | List finders = type.finderBuilder.build(world, chunkPos); 41 | 42 | finders.forEach(finder -> { 43 | if (finder.isValidDimension(world.dimensionType())) { 44 | finder.findInChunk(); 45 | this.finderControl.addFinder(type, finder); 46 | } 47 | }); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | }); 52 | }); 53 | } 54 | 55 | public void renderFinders(PoseStack matrixStack, Camera camera) { 56 | if (Config.get().render == Config.RenderType.OFF) return; 57 | 58 | matrixStack.pushPose(); 59 | 60 | Vec3 camPos = camera.getPosition(); 61 | 62 | Tesselator tessellator = Tesselator.getInstance(); 63 | BufferBuilder buffer = tessellator.getBuilder(); 64 | 65 | if (Config.get().render == Config.RenderType.XRAY) { 66 | RenderSystem.disableDepthTest(); 67 | } 68 | RenderSystem.setShader(GameRenderer::getPositionColorShader); 69 | RenderSystem.enableBlend(); 70 | RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); 71 | RenderSystem.lineWidth(2.0f); 72 | 73 | buffer.begin(VertexFormat.Mode.DEBUG_LINES, DefaultVertexFormat.POSITION_COLOR); 74 | 75 | this.finderControl.getActiveFinders().forEach(finder -> { 76 | if (finder.shouldRender()) { 77 | finder.render(matrixStack, buffer, camPos); 78 | } 79 | }); 80 | 81 | if (buffer.building()) { 82 | tessellator.end(); 83 | } 84 | RenderSystem.enableDepthTest(); 85 | RenderSystem.disableBlend(); 86 | 87 | matrixStack.popPose(); 88 | RenderSystem.applyModelViewMatrix(); 89 | } 90 | 91 | public List getActiveFinderTypes() { 92 | return Arrays.stream(Finder.Type.values()) 93 | .filter(type -> type.enabled.get()) 94 | .collect(Collectors.toList()); 95 | } 96 | 97 | public void clear() { 98 | this.finderControl = new FinderControl(); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/util/Database.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.util; 2 | 3 | import com.mojang.authlib.HttpAuthenticationService; 4 | import com.mojang.authlib.exceptions.AuthenticationException; 5 | import com.mojang.authlib.exceptions.AuthenticationUnavailableException; 6 | import com.mojang.authlib.exceptions.InsufficientPrivilegesException; 7 | import com.mojang.authlib.exceptions.InvalidCredentialsException; 8 | import kaptainwutax.seedcrackerX.config.Config; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.network.chat.Component; 11 | 12 | import java.io.IOException; 13 | import java.net.URI; 14 | import java.net.http.HttpClient; 15 | import java.net.http.HttpRequest; 16 | import java.net.http.HttpResponse; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | public class Database { 21 | 22 | public static Component joinFakeServerForAuth() { 23 | try { 24 | Minecraft client = Minecraft.getInstance(); 25 | client.getMinecraftSessionService().joinServer(client.getUser().getGameProfile(), client.getUser().getAccessToken(), "seedcrackerx"); 26 | } 27 | catch (AuthenticationUnavailableException authenticationUnavailableException) { 28 | return Component.translatable("disconnect.loginFailedInfo", Component.translatable("disconnect.loginFailedInfo.serversUnavailable")); 29 | } 30 | catch (InvalidCredentialsException authenticationUnavailableException) { 31 | return Component.translatable("disconnect.loginFailedInfo", Component.translatable("disconnect.loginFailedInfo.invalidSession")); 32 | } 33 | catch (InsufficientPrivilegesException authenticationUnavailableException) { 34 | return Component.translatable("disconnect.loginFailedInfo", Component.translatable("disconnect.loginFailedInfo.insufficientPrivileges")); 35 | } 36 | catch (AuthenticationException authenticationUnavailableException) { 37 | return Component.translatable("disconnect.loginFailedInfo", authenticationUnavailableException.getMessage()); 38 | } 39 | return null; 40 | } 41 | 42 | public static void handleDatabaseCall(Long seed) { 43 | HttpClient httpClient = HttpClient.newBuilder() 44 | .version(HttpClient.Version.HTTP_2) 45 | .build(); 46 | Minecraft client = Minecraft.getInstance(); 47 | Map data = new HashMap<>(); 48 | data.put("serverIp", client.getConnection().getConnection().getRemoteAddress().toString()); 49 | data.put("dimension", client.level.dimensionType().effectsLocation().getPath()); 50 | data.put("seed", seed+"L"); //javascript backend likes floating point. so we need to convert it to a string 51 | data.put("version", Config.get().getVersion().name); 52 | data.put("username", client.player.getName().getString()); 53 | data.put("hash", Config.get().anonymusSubmits? 1 : 0); 54 | 55 | 56 | HttpRequest request = HttpRequest.newBuilder() 57 | .POST(HttpRequest.BodyPublishers.ofString(HttpAuthenticationService.buildQuery(data))) 58 | .uri(URI.create("https://script.google.com/macros/s/AKfycbzU-o8IUaKMQ-MOJEqD8hFGTAC7E15l4uiVqkQsOWxGXgh_HVny6x_TSDVKR8V2wmm9Aw/exec")) 59 | .setHeader("User-Agent", "SeedcrackerX mod") 60 | .header("Content-Type", "application/x-www-form-urlencoded") 61 | .build(); 62 | 63 | try { 64 | HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); 65 | if (response.statusCode() == 302) { //the page says "document moved" but the post gets processed 66 | Log.warn("database.success"); 67 | } else { 68 | Log.warn("database.fail"); 69 | } 70 | } catch (IOException | InterruptedException e) { 71 | Log.warn("database.fail"); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/JigsawFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import net.minecraft.core.BlockPos; 4 | import net.minecraft.core.Direction; 5 | import net.minecraft.core.Vec3i; 6 | import net.minecraft.world.level.ChunkPos; 7 | import net.minecraft.world.level.Level; 8 | import net.minecraft.world.level.block.Mirror; 9 | import net.minecraft.world.level.block.Rotation; 10 | 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | public class JigsawFinder extends PieceFinder { 17 | public JigsawFinder(Level world, ChunkPos chunkPos, Direction facing, Vec3i size) { 18 | super(world, chunkPos, facing, size); 19 | } 20 | 21 | public static Map> getSearchPositions(int xRotation, int zRotation, int xOffset, int zOffset, Vec3i size) { 22 | Map> positions = new HashMap<>(); 23 | 24 | for(Direction direction : Direction.Plane.HORIZONTAL) { 25 | positions.put(direction, new ArrayList<>()); 26 | //this was painful and my hope is to never do it again 27 | int x = switch (direction) { 28 | case EAST -> xRotation-size.getZ()+1+zRotation-zOffset; 29 | case SOUTH -> xRotation-size.getX()+1+xRotation-xOffset; 30 | case WEST -> xRotation-zRotation+zOffset; 31 | default -> xOffset; 32 | }; 33 | int z = switch (direction) { 34 | case EAST -> zRotation-xRotation+xOffset; 35 | case SOUTH -> zRotation-size.getZ()+1+zRotation-zOffset; 36 | case WEST -> zRotation-size.getX()+1+xRotation-xOffset; 37 | default -> zOffset; 38 | }; 39 | if (x >= 0 && x < 16 && z >= 0 && z < 16 ) { 40 | int startIndex = heightContext.getHeight()*x*16+heightContext.getHeight()*z; 41 | for (int y = 0; y < heightContext.getHeight(); y++) { 42 | positions.get(direction).add(CHUNK_POSITIONS.get(y+startIndex)); 43 | } 44 | } else { 45 | for (int y = heightContext.getBottomY(); y < heightContext.getTopY(); y++) { 46 | positions.get(direction).add(new BlockPos(x, y, z)); 47 | } 48 | } 49 | } 50 | return positions; 51 | } 52 | 53 | 54 | @Override 55 | public void setOrientation(Direction facing) { 56 | this.facing = facing; 57 | this.mirror = Mirror.NONE; 58 | if (facing == null) { 59 | this.rotation = Rotation.NONE; 60 | } else { 61 | switch (facing) { 62 | case SOUTH -> this.rotation = Rotation.CLOCKWISE_180; 63 | case WEST -> this.rotation = Rotation.COUNTERCLOCKWISE_90; 64 | case EAST -> this.rotation = Rotation.CLOCKWISE_90; 65 | default -> this.rotation = Rotation.NONE; 66 | } 67 | } 68 | } 69 | 70 | @Override 71 | protected int applyXTransform(int x, int z) { 72 | if (this.facing == null) { 73 | return x; 74 | } else { 75 | return switch (this.facing) { 76 | case EAST -> -z + this.getLayout().getX()-1; 77 | case SOUTH -> -x + this.getLayout().getX()-1; 78 | case WEST -> z; 79 | 80 | default -> x; 81 | }; 82 | } 83 | } 84 | 85 | @Override 86 | protected int applyZTransform(int x, int z) { 87 | if (this.facing == null) { 88 | return z; 89 | } else { 90 | return switch (this.facing) { 91 | case EAST -> x; 92 | case SOUTH -> -z + this.getLayout().getZ()-1; 93 | case WEST -> -x + this.getLayout().getZ()-1; 94 | 95 | default -> z; 96 | }; 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/resources/assets/seedcrackerx/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Seed Cracker X", 3 | "settings": "设置", 4 | "settings.active": "激活", 5 | "settings.database": "把有10+玩家的服务器的种子发送到数据库", 6 | "settings.hideNameDatabase": "在种子数据库中隐藏用户名", 7 | "settings.openDatabase": "打开数据库", 8 | "settings.version": "版本", 9 | "settings.visuals": "视觉效果", 10 | "settings.outline": "渲染轮廓", 11 | "settings.finderToggles": "切换查找器", 12 | "settings.antiXrayMode": "绕过反矿透模式", 13 | "settings.antiAntiXrayExplained": "如果地牢的地板不只有圆石和苔石,则向服务器发送数据包。作为回应,服务器会告诉客户端真正的区块。这可能会触发超级严格的反作弊,但还没有人抱怨被封禁/踢出服务器(2.9.0版本一直有这个功能,目前有~2000次下载)。它使整个过程更加顺畅,因此我强烈建议将其打开", 14 | "finder.buriedTreasures": "埋藏的宝藏", 15 | "finder.desertTemples": "沙漠神殿", 16 | "finder.endCities": "末地城", 17 | "finder.jungleTemples": "丛林神庙", 18 | "finder.monuments": "海底神殿", 19 | "finder.swampHuts": "沼泽小屋", 20 | "finder.shipwrecks": "沉船", 21 | "finder.outposts": "掠夺者前哨站", 22 | "finder.igloo": "雪屋", 23 | "finder.endPillars": "黑曜石柱", 24 | "finder.endGateways": "末地折跃门", 25 | "finder.dungeons": "地牢", 26 | "finder.emeraldOres": "绿宝石矿石", 27 | "finder.desertWells": "沙漠水井", 28 | "finder.warpedFungus": "诡异菌", 29 | "finder.biomes": "生物群系", 30 | "finder.isFinder": "查找器 %s 被设置为", 31 | "finder.setFinder": "查找器 %s 已被设置为", 32 | "info": "信息", 33 | "info.clearData": "清除数据", 34 | "info.worldSeeds": "世界种子", 35 | "info.noWorldSeeds": "没有找到世界种子", 36 | "info.structureSeeds": "结构种子", 37 | "info.noStructureSeeds": "没有找到结构种子", 38 | "info.pillarSeeds": "黑曜石柱的种子", 39 | "info.noPillarSeeds": "没有找到黑曜石柱的种子", 40 | "info.hashedSeed": "散列化的种子", 41 | "info.noHashedSeed": "没有找到散列化的种子", 42 | "fetchedHashedSeed": "获取散列化的世界种子", 43 | "foundRestorableStructures": "找到了前一个会话中的 %s 结构。用/seedcracker data restore来恢复它们", 44 | "foundStructureSeed": "发现结构种子 ${SEED}", 45 | "finishedSearchNoResult": "搜索完成,无结果。", 46 | "crossCompare": "交叉比较了种子,并还原为${SEED}。", 47 | "data.clearData": "清除了数据存储", 48 | "data.collectedBits": "您当前已收集了 %s 位从 %s 位中。", 49 | "data.collectedLiftingBits": "您当前已收集了 %s 位从 %s 位的可挖掘结构中。", 50 | "data.restoreStructures": "恢复了 %s 结构", 51 | "data.restoreFailed": "没有发现前一个会话的结构", 52 | "cracker.successfully": "成功 ", 53 | "cracker.already": "已经 ", 54 | "cracker.enabled": "启用", 55 | "cracker.disabled": "禁用", 56 | "render.getRenderMode": "当前的渲染模式被设置为", 57 | "render.setRenderMode": "改变渲染模式为", 58 | "version.setVersion": "改变版本为", 59 | "tmachine.lookingForPillarSeed": "正在搜索黑曜石柱种子...", 60 | "tmachine.foundPillarSeed": "发现黑曜石柱种子 ${SEED}。", 61 | "tmachine.pillarSeedSearchFinished": "完成了黑曜石柱种子的搜索。", 62 | "tmachine.lookingForStructureSeeds": "正在搜索带有黑曜石柱种子[%s]的结构种子...", 63 | "tmachine.progress": "进度", 64 | "tmachine.structureSeedSearchFinished": "完成了对结构种子的搜索。", 65 | "tmachine.decoratorWorldSeedSearch": "正在用装饰搜索世界种子...", 66 | "tmachine.hashedSeedWorldSeedSearch": "正在搜索世界种子...", 67 | "tmachine.foundWorldSeed": "发现世界种子${SEED}。", 68 | "tmachine.worldSeedSearchFinished": "完成了对世界种子的搜索。", 69 | "tmachine.noResultsRevertingToBiomes": "完成了搜索,没有结果,重新回到生物群系。", 70 | "tmachine.moreBiomesNeeded": "你需要收集更多的生物群系信息", 71 | "tmachine.biomeWorldSeedSearch": "搜索具有%s生物群系的世界种子...", 72 | "tmachine.fuzzyBiomeSearch": "尝试模糊的生物群系搜索", 73 | "tmachine.deepBiomeSearch": "尝试深度生物群系搜索", 74 | "tmachine.printSeedsInConsole": "[防刷屏]在控制台输出所有其他种子", 75 | "tmachine.deleteBiomeInformation": "删除生物群系信息,因为没有找到匹配的种子", 76 | "tmachine.randomSeedSearch": "如果世界使用随机种子,则搜索可能的世界种子", 77 | "tmachine.startLifting": "用 %s 个结构开始挖掘。这可能要花费几分钟。", 78 | "tmachine.reduceSeeds":"减少结构种子", 79 | "tmachine.succeedReducing": "减少到了 %s 个结构种子", 80 | "tmachine.failedReducing": "无法减少种子", 81 | "dungeon.start": "开始搜索地牢...", 82 | "dungeon.structureSeedSearchFailed": "完成了地牢搜索,没有找到种子,", 83 | "dungeon.finishedNeedAnotherOne": "完成了地牢搜索。你需要另一个地牢", 84 | "fungus.start": "在 %s %s 运行搜索器", 85 | "fungus.fungusSeed": "菌类种子:${SEED}", 86 | "fungus.wrongData": "没有菌类种子,菌类被修改了(也包括生成过程中的变化)", 87 | "fungus.noStructureSeedsFound": "没有找到这个菌类的种子。", 88 | "fungus.gotStructureSeeds": "找到了结构种子:", 89 | "fungus.usableAsWorldSeed": "这个结构种子也可用作世界种子", 90 | "database.success": "发送成功", 91 | "database.fail": "发送失败" 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/decorator/EmeraldOre.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker.decorator; 2 | 3 | import com.seedfinding.mcbiome.biome.Biome; 4 | import com.seedfinding.mcbiome.biome.Biomes; 5 | import com.seedfinding.mccore.rand.ChunkRand; 6 | import com.seedfinding.mccore.state.Dimension; 7 | import com.seedfinding.mccore.version.MCVersion; 8 | import com.seedfinding.mccore.version.VersionMap; 9 | import net.minecraft.world.level.levelgen.WorldgenRandom; 10 | 11 | public class EmeraldOre extends Decorator { 12 | 13 | public static final VersionMap CONFIGS = new VersionMap() 14 | .add(MCVersion.v1_13, new Decorator.Config(4, 14)) 15 | .add(MCVersion.v1_16, new Decorator.Config(6, 14)) 16 | .add(MCVersion.v1_17, new Decorator.Config(6, 17)); 17 | 18 | public EmeraldOre(MCVersion version) { 19 | super(CONFIGS.getAsOf(version), version); 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return "emerald_ore"; 25 | } 26 | 27 | @Override 28 | public boolean canStart(Data data, long structureSeed, ChunkRand rand) { 29 | if (this.getVersion().isNewerThan(MCVersion.v1_17_1)) return true; 30 | super.canStart(data, structureSeed, rand); 31 | 32 | int bound = this.getVersion() == MCVersion.v1_17 ? rand.nextInt(19) + 6 : rand.nextInt(6) + 3; 33 | 34 | for (int i = 0; i < bound; i++) { 35 | int x, y, z; 36 | 37 | if (this.getVersion().isOlderThan(MCVersion.v1_15)) { 38 | x = rand.nextInt(16); 39 | y = rand.nextInt(28) + 4; 40 | z = rand.nextInt(16); 41 | } else { 42 | x = rand.nextInt(16); 43 | z = rand.nextInt(16); 44 | y = rand.nextInt(28) + 4; 45 | } 46 | 47 | if (y == data.blockY && x == data.offsetX && z == data.offsetZ) { 48 | return true; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | 55 | @Override 56 | public boolean canStart(EmeraldOre.Data data, long structureSeed, WorldgenRandom rand) { 57 | return true; 58 | //super.canStart(data, structureSeed, rand); 59 | //int x, y, z; 60 | // 61 | //for (int i = 0; i < 10; i++) { 62 | // 63 | // x = rand.nextInt(16); 64 | // z = rand.nextInt(16); 65 | // y = rand.nextInt(); 66 | // 67 | // if (y == data.blockY && x == data.offsetX && z == data.offsetZ) { 68 | // return true; 69 | // } 70 | // 71 | // rand.nextInt(2); 72 | // rand.nextInt(2); 73 | //} 74 | //return false; 75 | } 76 | 77 | @Override 78 | public boolean isValidDimension(Dimension dimension) { 79 | return dimension == Dimension.OVERWORLD; 80 | } 81 | 82 | @Override 83 | public boolean isValidBiome(Biome biome) { 84 | return biome == Biomes.GRAVELLY_MOUNTAINS || biome == Biomes.MODIFIED_GRAVELLY_MOUNTAINS 85 | || biome == Biomes.MOUNTAINS || biome == Biomes.WOODED_MOUNTAINS || biome == Biomes.MOUNTAIN_EDGE; 86 | } 87 | 88 | @Override 89 | public Dimension getValidDimension() { 90 | return Dimension.OVERWORLD; 91 | } 92 | 93 | 94 | public EmeraldOre.Data at(int blockX, int blockY, int blockZ, Biome biome) { 95 | return new EmeraldOre.Data(this, blockX, blockY, blockZ, biome); 96 | } 97 | 98 | public static class Data extends Decorator.Data { 99 | public final int offsetX; 100 | public final int blockY; 101 | public final int offsetZ; 102 | 103 | public Data(EmeraldOre feature, int blockX, int blockY, int blockZ, Biome biome) { 104 | super(feature, blockX >> 4, blockZ >> 4, biome); 105 | this.offsetX = blockX & 15; 106 | this.blockY = blockY; 107 | this.offsetZ = blockZ & 15; 108 | } 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SeedCrackerX-Forge 2 | a port of 19MisterX98's SeedcrackerX for forge 3 | 4 | ## Installation 5 | 6 | ### Vanilla Launcher 7 | 8 | Download and install the [forge mod loader](https://files.minecraftforge.net/). 9 | 10 | ### MultiMC 11 | 12 | Add a new minecraft instance and press "Install Forge" in the instance options. 13 | 14 | ### Mod Installation 15 | 16 | Download the lastest [release](https://github.com/someElseIsHere/SeedCrackerX-Forge/releases) of SeedCrackerX Forge 17 | Download [Cloth Config](https://www.curseforge.com/minecraft/mc-mods/cloth-config) 18 | 19 | put the .jar files in your mods directory, either %appdata%/.minecraft/mods/ folder for the vanilla launcher or your own MultiMC instance folder. 20 | 21 | ## Usage 22 | 23 | Run around in the world until the mod finds a dungeon. After the mod found one the cracking process starts automaticly. If it doesnt get you a world seed you may want to find another dungeon. This mod also supports cracking the seed via [structures and endpillars](https://youtu.be/aUuPSZVPH8E?t=462) and [warped fungus](https://www.youtube.com/watch?v=HKjwgofhKs4) 24 | 25 | ### Supported Structures 26 | - Ocean Monument 27 | - End City 28 | - Buried Treasure 29 | - Desert Pyramid 30 | - Jungle Temple 31 | - Swamp Hut 32 | - Shipwreck 33 | 34 | ### Supported Decorators 35 | - Dungeon 36 | - End Gateway 37 | - Desert Well 38 | - Emerald Ore 39 | - Warped Fungus 40 | 41 | ## Commands(Deprecated, use the GUI instead) 42 | 43 | The command prefix for this mod is /seed. 44 | 45 | ### Render Command (Currently Broken) 46 | -`/seed render outlines ` 47 | 48 | This command only affects the renderer feedback. The default value is 'XRAY' and highlights data through blocks. You can set the render mod to 'ON' for more standard rendering. 49 | 50 | ### Finder Command 51 | -`/seed finder type (ON/OFF)` 52 | 53 | -`/seed finder category (BIOMES/ORES/OTHERS/STRUCTURES) (ON/OFF)` 54 | 55 | This command is used to disable finders in case you are aware the data is wrong. For example, a map generated in 1.14 has different decorators and would require you to disable them while going through those chunks. 56 | 57 | -`/seed finder reload` 58 | 59 | Searches the loaded area again 60 | 61 | ### Data Command 62 | - `/seed data clear` 63 | 64 | Clears all the collected data without requiring a relog. This is useful for multi-world servers. 65 | 66 | - `/seed data bits` 67 | 68 | Display how many bits of information have been collected. Even though this is an approximate, it serves as a good basis to guess when the brute-forcing should start. 69 | 70 | ### Cracker Command 71 | - `/seed cracker ` 72 | 73 | Enables or disables the mod completely. Unlike the other commands, this one is persistent across reloads. 74 | 75 | - `/seed cracker debug` 76 | 77 | Additional info is shown 78 | 79 | ## Video Tutorials 80 | 81 | https://youtu.be/1ChmLi9og8Q 82 | 83 | https://youtu.be/8ytfZ2MXosY 84 | 85 | ## Upcoming Features 86 | 87 | A list of features I have on my mind... they won't necessarily be implemented in this order if at all. 88 | 89 | - Stronghold portal room cracker. (alternative to dungeon floor?) 90 | - Tree data collection (probably only oak and birch. Puts info into a file that can be compiled to run on GPU) 91 | 92 | ## Setting up the Workspace 93 | 94 | -Clone the repository. 95 | 96 | -Run `gradlew genSources `. 97 | 98 | ## Building the Mod 99 | 100 | -Update the version in `build.gradle` and `mod.toml`. 101 | 102 | -Run `gradlew build`. 103 | 104 | ## Contributors 105 | 106 | [KaptainWutax](https://github.com/KaptainWutax) - Author 107 | 108 | [neil](https://www.youtube.com/watch?v=aUuPSZVPH8E) - Video Tutorial 109 | 110 | [Nekzuris](https://github.com/Nekzuris) - README 111 | 112 | [19MisterX98](https://www.youtube.com/channel/UCby9ZxEjJCqmccQGF3GSYlA) - Author of SeedCrackerX 113 | 114 | [someElseIsHere](https://github.com/someElseIsHere/) Author of this Fork 115 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/BuriedTreasureFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import com.seedfinding.mcfeature.structure.RegionStructure; 4 | import kaptainwutax.seedcrackerX.Features; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.finder.BlockFinder; 8 | import kaptainwutax.seedcrackerX.finder.Finder; 9 | import kaptainwutax.seedcrackerX.render.Color; 10 | import kaptainwutax.seedcrackerX.render.Cube; 11 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 12 | import net.minecraft.core.BlockPos; 13 | import net.minecraft.world.level.ChunkPos; 14 | import net.minecraft.world.level.Level; 15 | import net.minecraft.world.level.biome.Biome; 16 | import net.minecraft.world.level.block.Blocks; 17 | import net.minecraft.world.level.block.ChestBlock; 18 | import net.minecraft.world.level.block.state.BlockState; 19 | import net.minecraft.world.level.dimension.DimensionType; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class BuriedTreasureFinder extends BlockFinder { 25 | 26 | protected static final List CHEST_HOLDERS = new ArrayList<>(); 27 | protected static List SEARCH_POSITIONS; 28 | 29 | static { 30 | CHEST_HOLDERS.add(Blocks.SANDSTONE.defaultBlockState()); 31 | CHEST_HOLDERS.add(Blocks.STONE.defaultBlockState()); 32 | CHEST_HOLDERS.add(Blocks.ANDESITE.defaultBlockState()); 33 | CHEST_HOLDERS.add(Blocks.GRANITE.defaultBlockState()); 34 | CHEST_HOLDERS.add(Blocks.DIORITE.defaultBlockState()); 35 | 36 | //Population can turn stone, andesite, granite and diorite into ores... 37 | CHEST_HOLDERS.add(Blocks.COAL_ORE.defaultBlockState()); 38 | CHEST_HOLDERS.add(Blocks.IRON_ORE.defaultBlockState()); 39 | CHEST_HOLDERS.add(Blocks.GOLD_ORE.defaultBlockState()); 40 | 41 | //Ocean can turn stone into gravel. 42 | CHEST_HOLDERS.add(Blocks.GRAVEL.defaultBlockState()); 43 | } 44 | 45 | public BuriedTreasureFinder(Level world, ChunkPos chunkPos) { 46 | super(world, chunkPos, Blocks.CHEST); 47 | this.searchPositions = SEARCH_POSITIONS; 48 | } 49 | 50 | public static void reloadSearchPositions() { 51 | SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 52 | //Buried treasure chests always generate at (9, 9) within a chunk. 53 | int localX = pos.getX() & 15; 54 | int localZ = pos.getZ() & 15; 55 | if (localX != 9 || localZ != 9) return true; 56 | return pos.getY() > 90 && pos.getY() < 0; 57 | }); 58 | } 59 | 60 | public static List create(Level world, ChunkPos chunkPos) { 61 | List finders = new ArrayList<>(); 62 | finders.add(new BuriedTreasureFinder(world, chunkPos)); 63 | return finders; 64 | } 65 | 66 | @Override 67 | public List findInChunk() { 68 | 69 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 64, (this.chunkPos.z << 2) + 2).value(); 70 | if (!Features.BURIED_TREASURE.isValidBiome(BiomeFixer.swap(biome))) return new ArrayList<>(); 71 | 72 | List result = super.findInChunk(); 73 | 74 | result.removeIf(pos -> { 75 | BlockState chest = world.getBlockState(pos); 76 | if (chest.hasProperty(ChestBlock.WATERLOGGED)) return true; 77 | 78 | BlockState chestHolder = world.getBlockState(pos.below()); 79 | return !CHEST_HOLDERS.contains(chestHolder); 80 | }); 81 | 82 | result.forEach(pos -> { 83 | RegionStructure.Data data = Features.BURIED_TREASURE.at(this.chunkPos.x, this.chunkPos.z); 84 | 85 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 86 | this.renderers.add(new Cube(pos, new Color(255, 255, 0))); 87 | } 88 | }); 89 | 90 | return result; 91 | } 92 | 93 | @Override 94 | public boolean isValidDimension(DimensionType dimension) { 95 | return this.isOverworld(dimension); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/decorator/EndPillarsFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.decorator; 2 | 3 | import com.seedfinding.mccore.version.MCVersion; 4 | import kaptainwutax.seedcrackerX.SeedCracker; 5 | import kaptainwutax.seedcrackerX.config.Config; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.cracker.PillarData; 8 | import kaptainwutax.seedcrackerX.finder.BlockFinder; 9 | import kaptainwutax.seedcrackerX.finder.Finder; 10 | import kaptainwutax.seedcrackerX.render.Color; 11 | import kaptainwutax.seedcrackerX.render.Cube; 12 | import net.minecraft.core.BlockPos; 13 | import net.minecraft.core.Vec3i; 14 | import net.minecraft.world.level.ChunkPos; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraft.world.level.block.Blocks; 17 | import net.minecraft.world.level.dimension.DimensionType; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.stream.Collectors; 22 | 23 | public class EndPillarsFinder extends Finder { 24 | 25 | private final boolean alreadyFound; 26 | protected BedrockMarkerFinder[] bedrockMarkers = new BedrockMarkerFinder[10]; 27 | 28 | public EndPillarsFinder(Level world, ChunkPos chunkPos) { 29 | super(world, chunkPos); 30 | 31 | this.alreadyFound = !SeedCracker.get().getDataStorage().addPillarData(null, DataAddedEvent.POKE_PILLARS); 32 | if (this.alreadyFound) return; 33 | 34 | for (int i = 0; i < this.bedrockMarkers.length; i++) { 35 | double x = 42.0D * Math.cos(2.0D * (-Math.PI + (Math.PI / 10.0D) * (double) i)); 36 | double z = 42.0D * Math.sin(2.0D * (-Math.PI + (Math.PI / 10.0D) * (double) i)); 37 | if (Config.get().getVersion().isOlderThan(MCVersion.v1_14)) { 38 | x = Math.round(x); 39 | z = Math.round(z); 40 | } 41 | this.bedrockMarkers[i] = new BedrockMarkerFinder(this.world, new ChunkPos(BlockPos.containing(x, 0, z)), BlockPos.containing(x, 0, z)); 42 | } 43 | } 44 | 45 | public static List create(Level world, ChunkPos chunkPos) { 46 | List finders = new ArrayList<>(); 47 | finders.add(new EndPillarsFinder(world, chunkPos)); 48 | return finders; 49 | } 50 | 51 | @Override 52 | public List findInChunk() { 53 | List result = new ArrayList<>(); 54 | 55 | for (BedrockMarkerFinder bedrockMarker : this.bedrockMarkers) { 56 | if (bedrockMarker == null) continue; 57 | result.addAll(bedrockMarker.findInChunk()); 58 | } 59 | 60 | if (result.size() == this.bedrockMarkers.length) { 61 | PillarData pillarData = new PillarData(result.stream().map(Vec3i::getY).collect(Collectors.toList())); 62 | 63 | if (SeedCracker.get().getDataStorage().addPillarData(pillarData, DataAddedEvent.POKE_PILLARS)) { 64 | result.forEach(pos -> this.renderers.add(new Cube(pos, new Color(128, 0, 128)))); 65 | } 66 | 67 | } 68 | 69 | return result; 70 | } 71 | 72 | @Override 73 | public boolean isValidDimension(DimensionType dimension) { 74 | return this.isEnd(dimension); 75 | } 76 | 77 | public static class BedrockMarkerFinder extends BlockFinder { 78 | 79 | protected static List SEARCH_POSITIONS; 80 | 81 | public BedrockMarkerFinder(Level world, ChunkPos chunkPos, BlockPos xz) { 82 | super(world, chunkPos, Blocks.BEDROCK); 83 | this.searchPositions = SEARCH_POSITIONS; 84 | } 85 | 86 | public static void reloadSearchPositions() { 87 | SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> { 88 | if (pos.getY() < 76) return true; 89 | return pos.getY() > 76 + 3 * 10; 90 | }); 91 | } 92 | 93 | @Override 94 | public List findInChunk() { 95 | return super.findInChunk(); 96 | } 97 | 98 | @Override 99 | public boolean isValidDimension(DimensionType dimension) { 100 | return true; 101 | } 102 | 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/decorator/DesertWellFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.decorator; 2 | 3 | import com.seedfinding.mcfeature.decorator.DesertWell; 4 | import kaptainwutax.seedcrackerX.Features; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.finder.Finder; 8 | import kaptainwutax.seedcrackerX.finder.structure.PieceFinder; 9 | import kaptainwutax.seedcrackerX.render.Color; 10 | import kaptainwutax.seedcrackerX.render.Cube; 11 | import kaptainwutax.seedcrackerX.render.Cuboid; 12 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 13 | import net.minecraft.core.BlockPos; 14 | import net.minecraft.core.Direction; 15 | import net.minecraft.core.Vec3i; 16 | import net.minecraft.world.level.ChunkPos; 17 | import net.minecraft.world.level.Level; 18 | import net.minecraft.world.level.biome.Biome; 19 | import net.minecraft.world.level.block.Blocks; 20 | import net.minecraft.world.level.block.state.BlockState; 21 | import net.minecraft.world.level.dimension.DimensionType; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class DesertWellFinder extends PieceFinder { 27 | 28 | protected static Vec3i SIZE = new Vec3i(5, 6, 5); 29 | 30 | public DesertWellFinder(Level world, ChunkPos chunkPos) { 31 | super(world, chunkPos, Direction.NORTH, SIZE); 32 | this.searchPositions = CHUNK_POSITIONS; 33 | this.buildStructure(); 34 | } 35 | 36 | public static List create(Level world, ChunkPos chunkPos) { 37 | List finders = new ArrayList<>(); 38 | finders.add(new DesertWellFinder(world, chunkPos)); 39 | 40 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 41 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 42 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 43 | 44 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z))); 45 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1))); 46 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1))); 47 | 48 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 49 | finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z + 1))); 50 | return finders; 51 | } 52 | 53 | @Override 54 | public List findInChunk() { 55 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 0, (this.chunkPos.z << 2) + 2).value(); 56 | 57 | if (!Features.DESERT_WELL.isValidBiome(BiomeFixer.swap(biome))) { 58 | return new ArrayList<>(); 59 | } 60 | 61 | List result = super.findInChunk(); 62 | 63 | result.forEach(pos -> { 64 | pos = pos.offset(2, 1, 2); 65 | 66 | DesertWell.Data data = Features.DESERT_WELL.at(pos.getX(), pos.getZ()); 67 | 68 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 69 | this.renderers.add(new Cuboid(pos.offset(-2, -1, -2), SIZE, new Color(128, 128, 255))); 70 | this.renderers.add(new Cube(pos, new Color(128, 128, 255))); 71 | } 72 | }); 73 | 74 | return result; 75 | } 76 | 77 | @Override 78 | public boolean isValidDimension(DimensionType dimension) { 79 | return this.isOverworld(dimension); 80 | } 81 | 82 | protected void buildStructure() { 83 | BlockState sandstone = Blocks.SANDSTONE.defaultBlockState(); 84 | BlockState sandstoneSlab = Blocks.SANDSTONE_SLAB.defaultBlockState(); 85 | BlockState water = Blocks.WATER.defaultBlockState(); 86 | 87 | this.fillWithOutline(0, 0, 0, 4, 1, 4, sandstone, sandstone, false); 88 | this.fillWithOutline(1, 5, 1, 3, 5, 3, sandstoneSlab, sandstoneSlab, false); 89 | this.addBlock(sandstone, 2, 5, 2); 90 | 91 | BlockPos p1 = new BlockPos(2, 1, 2); 92 | this.addBlock(water, p1.getX(), p1.getY(), p1.getZ()); 93 | 94 | Direction.Plane.HORIZONTAL.forEach(facing -> { 95 | BlockPos p2 = p1.relative(facing); 96 | this.addBlock(water, p2.getX(), p2.getY(), p2.getZ()); 97 | }); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | # This is an example mods.toml file. It contains the data relating to the loading mods. 2 | # There are several mandatory fields (#mandatory), and many more that are optional (#optional). 3 | # The overall format is standard TOML format, v0.5.0. 4 | # Note that there are a couple of TOML lists in this file. 5 | # Find more information on toml format here: https://github.com/toml-lang/toml 6 | # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml 7 | modLoader="javafml" #mandatory 8 | # A version range to match for said mod loader - for regular FML @Mod it will be the forge version 9 | loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. 10 | # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. 11 | # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. 12 | license="${mod_license}" 13 | # A URL to refer people to when problems occur with this mod 14 | #issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional 15 | # A list of mods - how many allowed here is determined by the individual mod loader 16 | [[mods]] #mandatory 17 | # The modid of the mod 18 | modId="seedcracker" #mandatory 19 | # The version number of the mod 20 | version="2.14.4.1" #mandatory 21 | # A display name for the mod 22 | displayName="SeedCrackerX" #mandatory 23 | # A URL to query for updates for this mod. See the JSON update specification https://docs.minecraftforge.net/en/latest/misc/updatechecker/ 24 | #updateJSONURL="https://change.me.example.invalid/updates.json" #optional 25 | # A URL for the "homepage" for this mod, displayed in the mod UI 26 | #displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional 27 | # A file name (in the root of the mod JAR) containing a logo for display 28 | #logoFile="examplemod.png" #optional 29 | # A text field displayed in the mod UI 30 | #credits="" #optional 31 | # A text field displayed in the mod UI 32 | authors="thePlaceholder, 19MisterX98" #optional 33 | # Display Test controls the display for your mod in the server connection screen 34 | # MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. 35 | # IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. 36 | # IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. 37 | # NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. 38 | # IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself. 39 | #displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) 40 | 41 | # The description text for the mod (multi line!) (#mandatory) 42 | description='''a port of 19MisterX98's SeedcrackerX for forge''' 43 | # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. 44 | [[dependencies.seedcracker]] #optional 45 | # the modid of the dependency 46 | modId="forge" #mandatory 47 | # Does this dependency have to exist - if not, ordering below must be specified 48 | mandatory=true #mandatory 49 | # The version range of the dependency 50 | versionRange="[47,)" #mandatory 51 | # An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory 52 | # BEFORE - This mod is loaded BEFORE the dependency 53 | # AFTER - This mod is loaded AFTER the dependency 54 | ordering="NONE" 55 | # Side this dependency is applied on - BOTH, CLIENT, or SERVER 56 | side="CLIENT" 57 | # Here's another dependency 58 | [[dependencies.seedcracker]] 59 | modId="minecraft" 60 | mandatory=true 61 | # This version range declares a minimum of the current minecraft version up to but not including the next major version 62 | versionRange="[1.20.1,1.21)" 63 | ordering="NONE" 64 | side="CLIENT" 65 | 66 | [[dependencies.seedcracker]] 67 | modId="cloth_config" 68 | mandatory=true 69 | versionRange="[4.11.37,)" 70 | ordering="BEFORE" 71 | side="CLIENT" -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/config/StructureSave.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.config; 2 | 3 | import com.seedfinding.mcfeature.Feature; 4 | import com.seedfinding.mcfeature.structure.RegionStructure; 5 | import com.seedfinding.mcfeature.structure.Structure; 6 | import kaptainwutax.seedcrackerX.Features; 7 | import kaptainwutax.seedcrackerX.cracker.storage.DataStorage; 8 | import kaptainwutax.seedcrackerX.cracker.storage.ScheduledSet; 9 | 10 | import java.io.*; 11 | import java.nio.file.Files; 12 | import java.nio.file.Path; 13 | import java.nio.file.Paths; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Scanner; 17 | 18 | import net.minecraft.client.Minecraft; 19 | import net.minecraft.network.Connection; 20 | import net.minecraft.world.level.storage.LevelResource; 21 | import net.minecraftforge.fml.loading.FMLPaths; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | public class StructureSave { 26 | private static final Logger logger = LoggerFactory.getLogger("structureSave"); 27 | 28 | public static final Path saveDir = Paths.get(FMLPaths.CONFIGDIR.get().toString(), "SeedCrackerX saved structures"); 29 | private static final List> structureTypes = List.of(Features.IGLOO,Features.BURIED_TREASURE, 30 | Features.PILLAGER_OUTPOST,Features.DESERT_PYRAMID, Features.JUNGLE_PYRAMID, Features.END_CITY, 31 | Features.MONUMENT, Features.SHIPWRECK, Features.SWAMP_HUT); 32 | 33 | public static void saveStructures(ScheduledSet>> baseData) { 34 | try { 35 | Files.createDirectories(saveDir); 36 | Path saveFile = saveDir.resolve(getWorldName()); 37 | Files.deleteIfExists(saveFile); 38 | Files.createFile(saveFile); 39 | try (FileWriter writer = new FileWriter(saveFile.toFile())) { 40 | for (DataStorage.Entry> dataEntry : baseData) { 41 | if (dataEntry.data.feature instanceof Structure structure) { 42 | String data = Structure.getName(structure.getClass()) + 43 | ";" + dataEntry.data.chunkX + 44 | ";" + dataEntry.data.chunkZ + 45 | "\n"; 46 | writer.write(data); 47 | } 48 | } 49 | } 50 | } catch (IOException e) { 51 | logger.error("seedcracker couldn't save structures", e); 52 | } 53 | } 54 | 55 | public static List> loadStructures() { 56 | List> result = new ArrayList<>(); 57 | try { 58 | Files.createDirectories(saveDir); 59 | Path saveFile = saveDir.resolve(getWorldName()); 60 | try ( 61 | FileInputStream fis = new FileInputStream(saveFile.toFile()); 62 | Scanner sc = new Scanner(fis) 63 | ) { 64 | while (sc.hasNextLine()) { 65 | String line = sc.nextLine(); 66 | String[] info = line.split(";"); 67 | if (info.length != 3) continue; 68 | String structureName = info[0]; 69 | for (RegionStructure idk : structureTypes) { 70 | if (structureName.equals(idk.getName())) { 71 | result.add(idk.at(Integer.parseInt(info[1]), Integer.parseInt(info[2]))); 72 | break; 73 | } 74 | } 75 | } 76 | } 77 | } catch (FileNotFoundException e) { 78 | logger.warn("seedcracker couldn't find the structures file", e); 79 | return result; 80 | } catch (IOException e) { 81 | logger.error("seedcracker couldn't load previous structures", e); 82 | } 83 | return result; 84 | } 85 | 86 | private static String getWorldName() { 87 | Minecraft minecraftClient = Minecraft.getInstance(); 88 | if (minecraftClient.getConnection() != null) { 89 | Connection connection = minecraftClient.getConnection().getConnection(); 90 | if (connection.isMemoryConnection()) { 91 | String address = minecraftClient.getSingleplayerServer().getWorldPath(LevelResource.ROOT).getParent().getFileName().toString(); 92 | return address.replace("/","_").replace(":", "_")+".txt"; 93 | } else { 94 | return connection.getRemoteAddress().toString().replace("/","_").replace(":","_")+".txt"; 95 | } 96 | } 97 | return "Invalid.txt"; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/OutpostFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import com.seedfinding.mcfeature.structure.RegionStructure; 4 | import kaptainwutax.seedcrackerX.Features; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.finder.Finder; 8 | import kaptainwutax.seedcrackerX.render.Color; 9 | import kaptainwutax.seedcrackerX.render.Cube; 10 | import kaptainwutax.seedcrackerX.render.Cuboid; 11 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 12 | import net.minecraft.core.BlockPos; 13 | import net.minecraft.core.Direction; 14 | import net.minecraft.core.Vec3i; 15 | import net.minecraft.world.level.ChunkPos; 16 | import net.minecraft.world.level.Level; 17 | import net.minecraft.world.level.biome.Biome; 18 | import net.minecraft.world.level.block.Blocks; 19 | import net.minecraft.world.level.block.state.BlockState; 20 | import net.minecraft.world.level.dimension.DimensionType; 21 | 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | public class OutpostFinder extends Finder { 28 | 29 | protected static Map> SEARCH_POSITIONS; 30 | protected static final Vec3i size = new Vec3i(15, 21, 15); 31 | protected List finders = new ArrayList<>(); 32 | 33 | public OutpostFinder(Level world, ChunkPos chunkPos) { 34 | super(world, chunkPos); 35 | 36 | Direction.Plane.HORIZONTAL.forEach(direction -> { 37 | JigsawFinder finder = new JigsawFinder(world, chunkPos, direction, size); 38 | 39 | finder.searchPositions = SEARCH_POSITIONS.get(direction); 40 | 41 | buildStructure(finder); 42 | this.finders.add(finder); 43 | }); 44 | } 45 | 46 | public static void reloadSearchPositions() { 47 | SEARCH_POSITIONS = JigsawFinder.getSearchPositions(0, 0,0,0, size); 48 | Map> additional = JigsawFinder.getSearchPositions(0, 0,1,0, size); 49 | for(Direction direction : Direction.Plane.HORIZONTAL) { 50 | SEARCH_POSITIONS.get(direction).addAll(additional.get(direction)); 51 | } 52 | 53 | } 54 | 55 | public static List create(Level world, ChunkPos chunkPos) { 56 | List finders = new ArrayList<>(); 57 | finders.add(new OutpostFinder(world, chunkPos)); 58 | finders.add(new OutpostFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1))); 59 | finders.add(new OutpostFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z))); 60 | finders.add(new OutpostFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1))); 61 | return finders; 62 | } 63 | 64 | private void buildStructure(JigsawFinder finder) { 65 | BlockState chest = Blocks.CHEST.defaultBlockState(); 66 | BlockState birchwood = Blocks.BIRCH_PLANKS.defaultBlockState(); 67 | 68 | finder.addBlock(chest, 9, 14, 10); 69 | 70 | finder.fillWithOutline(4, 0, 4, 10, 0, 10, birchwood, birchwood, false); 71 | } 72 | 73 | @Override 74 | public List findInChunk() { 75 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 64, (this.chunkPos.z << 2) + 2).value(); 76 | if (!Features.PILLAGER_OUTPOST.isValidBiome(BiomeFixer.swap(biome))) return new ArrayList<>(); 77 | 78 | Map> result = this.findInChunkPieces(); 79 | List combinedResult = new ArrayList<>(); 80 | 81 | result.forEach((pieceFinder, positions) -> { 82 | 83 | combinedResult.addAll(positions); 84 | 85 | positions.forEach(pos -> { 86 | RegionStructure.Data data = Features.PILLAGER_OUTPOST.at(this.chunkPos.x, this.chunkPos.z); 87 | 88 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_LIFTING)) { 89 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(170, 84, 3))); 90 | this.renderers.add(new Cube(chunkPos.getWorldPosition().offset(0, pos.getY(), 0), new Color(170, 84, 3))); 91 | } 92 | }); 93 | }); 94 | 95 | return combinedResult; 96 | } 97 | 98 | public Map> findInChunkPieces() { 99 | Map> result = new HashMap<>(); 100 | 101 | this.finders.forEach(pieceFinder -> { 102 | result.put(pieceFinder, pieceFinder.findInChunk()); 103 | }); 104 | 105 | return result; 106 | } 107 | 108 | @Override 109 | public boolean isValidDimension(DimensionType dimension) { 110 | return this.isOverworld(dimension); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/IglooFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import com.seedfinding.mcfeature.structure.RegionStructure; 4 | import kaptainwutax.seedcrackerX.Features; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.finder.Finder; 8 | import kaptainwutax.seedcrackerX.render.Color; 9 | import kaptainwutax.seedcrackerX.render.Cube; 10 | import kaptainwutax.seedcrackerX.render.Cuboid; 11 | import net.minecraft.core.BlockPos; 12 | import net.minecraft.core.Direction; 13 | import net.minecraft.core.Vec3i; 14 | import net.minecraft.world.level.ChunkPos; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraft.world.level.block.Blocks; 17 | import net.minecraft.world.level.block.state.BlockState; 18 | import net.minecraft.world.level.dimension.DimensionType; 19 | 20 | import java.util.ArrayList; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | public class IglooFinder extends Finder { 26 | 27 | protected static Map> SEARCH_POSITIONS; 28 | protected static final Vec3i size = new Vec3i(7, 5, 8); 29 | protected List finders = new ArrayList<>(); 30 | 31 | public IglooFinder(Level world, ChunkPos chunkPos) { 32 | super(world, chunkPos); 33 | 34 | Direction.Plane.HORIZONTAL.forEach(direction -> { 35 | JigsawFinder finder = new JigsawFinder(world, chunkPos, direction, size); 36 | 37 | finder.searchPositions = SEARCH_POSITIONS.get(direction); 38 | //finder.setDebug(); 39 | buildStructure(finder); 40 | this.finders.add(finder); 41 | }); 42 | } 43 | 44 | public static void reloadSearchPositions() { 45 | SEARCH_POSITIONS = JigsawFinder.getSearchPositions(3, 5,0,0, size); 46 | } 47 | 48 | 49 | @Override 50 | public List findInChunk() { 51 | Map> result = this.findInChunkPieces(); 52 | List combinedResult = new ArrayList<>(); 53 | 54 | result.forEach((pieceFinder, positions) -> { 55 | 56 | combinedResult.addAll(positions); 57 | 58 | positions.forEach(pos -> { 59 | RegionStructure.Data data = Features.IGLOO.at(this.chunkPos.x, this.chunkPos.z); 60 | 61 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_LIFTING)) { 62 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(176, 207, 252))); 63 | this.renderers.add(new Cube(chunkPos.getWorldPosition().offset(0, pos.getY(), 0), new Color(176, 207, 252))); 64 | } 65 | }); 66 | }); 67 | 68 | return combinedResult; 69 | } 70 | 71 | public Map> findInChunkPieces() { 72 | Map> result = new HashMap<>(); 73 | 74 | this.finders.forEach(pieceFinder -> { 75 | result.put(pieceFinder, pieceFinder.findInChunk()); 76 | }); 77 | 78 | return result; 79 | } 80 | 81 | public void buildStructure(JigsawFinder finder) { 82 | BlockState snow = Blocks.SNOW_BLOCK.defaultBlockState(); 83 | BlockState ice = Blocks.ICE.defaultBlockState(); 84 | BlockState workBench = Blocks.CRAFTING_TABLE.defaultBlockState(); 85 | 86 | finder.addBlock(workBench, 1, 1, 5); 87 | for(int y = 0; y < 3; y++) { 88 | finder.addBlock(snow, 2, y, 0); 89 | finder.addBlock(snow, 2, y, 1); 90 | finder.addBlock(snow, 1, y, 2); 91 | finder.addBlock(snow, 0, y, 3); 92 | finder.addBlock(snow, 0, y, 4); 93 | finder.addBlock(ice, 0, 1, 4); 94 | finder.addBlock(snow, 0, y, 5); 95 | finder.addBlock(snow, 1, y, 6); 96 | finder.addBlock(snow, 2, y, 7); 97 | 98 | finder.addBlock(snow, 3, y, 7); 99 | 100 | finder.addBlock(snow, 4, y, 0); 101 | finder.addBlock(snow, 4, y, 1); 102 | finder.addBlock(snow, 5, y, 2); 103 | finder.addBlock(snow, 6, y, 3); 104 | finder.addBlock(snow, 6, y, 4); 105 | finder.addBlock(ice, 6, 1, 4); 106 | finder.addBlock(snow, 6, y, 5); 107 | finder.addBlock(snow, 5, y, 6); 108 | finder.addBlock(snow, 4, y, 7); 109 | } 110 | } 111 | 112 | @Override 113 | public boolean isValidDimension(DimensionType dimension) { 114 | return this.isOverworld(dimension); 115 | } 116 | 117 | public static List create(Level world, ChunkPos chunkPos) { 118 | List finders = new ArrayList<>(); 119 | finders.add(new IglooFinder(world, chunkPos)); 120 | finders.add(new IglooFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z))); 121 | return finders; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/resources/assets/seedcrackerx/lang/hi_in.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Seed Cracker X", 3 | "settings": "सेटिंग्स", 4 | "settings.active": "सक्रिय", 5 | "settings.database": "10 से अधिक प्लेयर्स वाले सर्वेरों के सीड को डेटाबेस में भेजता है", 6 | "settings.hideNameDatabase": "सीड डेटाबेस में उपयोगकर्ता नाम छुपाएं", 7 | "settings.openDatabase": "डेटाबेस खोलें", 8 | "settings.version": "संस्करण", 9 | "settings.visuals": "दृश्य", 10 | "settings.outline": "रूपरेखाएँ दिखाएँ", 11 | "settings.finderToggles": "खोजक टॉगल", 12 | "settings.antiXrayMode": "एक्स-रे विरुद्ध मोड", 13 | "settings.antiAntiXrayExplained": "सर्वर को पैकेट भेजता है अगर डंजियन का फर्श कोब्बल या मॉसी कोब्बल से बना है जवाब में सर्वर क्लाइंट को असली ब्लॉक बता देता है। यह बहुत अधिक संवेदनशील एंटी चीट को उत्प्रेरित कर सकता है लेकिन अब तक किसी ने बैन/किक के बारे में शिकायत नहीं की है (संस्करण 2.9.0 में यह फीचर हमेशा सक्रिय रहता है और वर्तमान में इसके ~2000 डाउनलोड हैं)। यह प्रिक्रिया को अधिक सरल बना देता है इसलिए में इसे सक्रिय रखने कि सलाह देता हूँ", 14 | "finder.buriedTreasures": "दफ़न खजाना", 15 | "finder.desertTemples": "डेजर्ट टेम्पल", 16 | "finder.endCities": "एन्ड सिटी", 17 | "finder.jungleTemples": "जंगल टेम्पल", 18 | "finder.monuments": "ओसियन मोन्यूमेंट", 19 | "finder.swampHuts": "विच है", 20 | "finder.shipwrecks": "शिपरेक", 21 | "finder.outposts": "पिलेजर", 22 | "finder.igloo": "इग्लू", 23 | "finder.endPillars": "एन्ड पिलर", 24 | "finder.endGateways": "एन्ड गेटवे", 25 | "finder.dungeons": "डंजियन", 26 | "finder.emeraldOres": "एमराल्ड अयस्क", 27 | "finder.desertWells": "डेजर्ट कुएँ", 28 | "finder.warpedFungus": "वार्पड फंगस", 29 | "finder.biomes": "बायोम", 30 | "finder.isFinder": "खोजक %s सेट है", 31 | "finder.setFinder": "खोजक %s सेट कर दिया गया है", 32 | "info": "जानकारी", 33 | "info.clearData": "डेटा हटाएँ", 34 | "info.worldSeeds": "वर्ल्ड सीड", 35 | "info.noWorldSeeds": "कोई वर्ल्ड सीड नहीं मिले", 36 | "info.structureSeeds": "सरंचना सीड", 37 | "info.noStructureSeeds": "कोई सरंचना सीड नहीं मिले", 38 | "info.pillarSeeds": "पिलर सीड", 39 | "info.noPillarSeeds": "कोई पिलर सीड नहीं मिले", 40 | "info.hashedSeed": "हैश हुआ सीड", 41 | "info.noHashedSeed": "कोई हैश हुआ सीड नहीं मिला", 42 | "fetchedHashedSeed": "इस आयाम में वर्ल्ड सीड अलग है", 43 | "foundRestorableStructures": "पिछले सत्र से %s सरंचनाएँ मिली। /seedcracker data restore से उन्हें वापिस लाइए", 44 | "foundStructureSeed": "सरंचना सीड मिला ${SEED}.", 45 | "finishedSearchNoResult": "बिना कोई परिणामो के खोज पूरी हुई।", 46 | "crossCompare": "सीड की तुलना की और घटाए गए ${SEED}.", 47 | "data.clearData": "स्टोरेज डेटा हटाया गया", 48 | "data.collectedBits": "आपने वर्तमान में %s बिट संग्रहीत कर लिए हैं %s में से।", 49 | "data.collectedLiftingBits": "आपने वर्तमान में उठाने योग्य सरंचनाओं से %s बिट संग्रहीत कर लिए हैं %s में से।", 50 | "data.restoreStructures": "%s सरंचनाएँ वापिस लायी गयी", 51 | "data.restoreFailed": "पिछले सत्र से कोई सरंचनाएँ नहीं मिली", 52 | "cracker.successfully": "सफलतापूर्वक ", 53 | "cracker.already": "पहले से ही ", 54 | "cracker.enabled": "सक्षम", 55 | "cracker.disabled": "अक्षम", 56 | "render.getRenderMode": "वर्तमान रेंडर मोड सेट है", 57 | "render.setRenderMode": "रेंडर मोड में बदला गया", 58 | "version.setVersion": "संस्करण में बदला गया", 59 | "tmachine.lookingForPillarSeed": "पिलर सीड खोज रहा है...", 60 | "tmachine.foundPillarSeed": "पिलर सीड मिल गया ${SEED}.", 61 | "tmachine.pillarSeedSearchFinished": "पिलर सीड खोज समाप्त हुयी।", 62 | "tmachine.lookingForStructureSeeds": "पिलर सीड [%s] से सरंचना सीड खोज रहा है...", 63 | "tmachine.progress": "प्रगति", 64 | "tmachine.structureSeedSearchFinished": "सरंचना सीड खोज समाप्त हुयी।", 65 | "tmachine.decoratorWorldSeedSearch": "डेकोरेटर्स से वर्ल्ड सीड खोज रहा है...", 66 | "tmachine.hashedSeedWorldSeedSearch": "हैश हुए सीड से वर्ल्ड सीड खोज रहा है...", 67 | "tmachine.foundWorldSeed": "वर्ल्ड सीड मिल गया ${SEED}.", 68 | "tmachine.worldSeedSearchFinished": "वर्ल्ड सीड के लिए खोज समाप्त हुई।", 69 | "tmachine.noResultsRevertingToBiomes": "खोज बिना परिणामो के समाप्त हुई, बायोम में पूर्ववत किया जा रहा है।", 70 | "tmachine.moreBiomesNeeded": "आपको और अधिक बायोम जानकारी संग्रहित करनी होगी", 71 | "tmachine.biomeWorldSeedSearch": "%s बायोम से वर्ल्ड सीड खोज रहा है", 72 | "tmachine.fuzzyBiomeSearch": "फजी बायोम खोज से प्रयास कर रहा है", 73 | "tmachine.deepBiomeSearch": "डीप बायोम खोज से प्रयास कर रहा है", 74 | "tmachine.printSeedsInConsole": "[स्पैम सुरक्षा] कंसोल में अन्य सभी सीड को प्रिंट कर रहा है", 75 | "tmachine.deleteBiomeInformation": "बायोम जानकारी हटा रहा है चूँकि कोई सीड नहीं मिला", 76 | "tmachine.randomSeedSearch": "उन वर्ल्ड सीड को खोज रहा है जो संभव हैं अगर वर्ल्ड एक यादृच्छिक सीड उपयोग करता है", 77 | "tmachine.startLifting": "%s सरंचनाओँ से उठा रहा है। यह कुछ मिनट ले सकता है", 78 | "tmachine.reduceSeeds": "%s सरंचना सीड घटाया जा रहा है", 79 | "tmachine.succeedReducing": "सीड घटने में असफल", 80 | "tmachine.failedReducing": "सीड घटने में असफल। आपको संभवतया अधिक सरंचनाओं की जरुरत है या आपका देता गलत है", 81 | "dungeon.start": "डंजियन से शॉर्ट कट कर रहा है...", 82 | "dungeon.structureSeedSearchFailed": "बिना कोई सीड के डंजियन खोज पूरी हुई।", 83 | "dungeon.finishedNeedAnotherOne": "सरंचना सीड खोज समाप्त हुई। आपको एक और डंजियन की आवश्यकता है", 84 | "fungus.start": "%s %s पर क्रैकर चला रहा है", 85 | "fungus.fungusSeed": "फंगस सीड: ${SEED}.", 86 | "fungus.wrongData": "कोई फंगस सीड नहीं, फंगस संशोधित हुआ था (जनरेशन के दौरान बदलाव भी सम्मिलित)", 87 | "fungus.noStructureSeedsFound": "इस फंगस के लिए कोई सीड नहीं मिला।", 88 | "fungus.gotStructureSeeds": "सरंचना सीड मिला:", 89 | "fungus.usableAsWorldSeed": "यह सरंचना सीड वर्ल्ड सीड की तरह भी उपयोग किया जा सकता है", 90 | "database.success": "सीड को डेटाबेस में सफलतापूर्वक भेजा गया", 91 | "database.fail": "सीड को डेटाबेस में भेजने में असफल रहा" 92 | } 93 | -------------------------------------------------------------------------------- /src/main/resources/assets/seedcrackerx/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Seed Cracker X", 3 | "settings": "Settings", 4 | "settings.active": "Active", 5 | "settings.database": "Send 10+ player server seeds to the database", 6 | "settings.hideNameDatabase": "Scramble username in seed database", 7 | "settings.openDatabase": "Open the database", 8 | "settings.version": "Version", 9 | "settings.visuals": "Visuals", 10 | "settings.outline": "Render outlines", 11 | "settings.finderToggles": "Finder toggles", 12 | "settings.antiXrayMode": "Anti Xray Mode", 13 | "settings.antiAntiXrayExplained": "Sends packets to the server if a dungeon floor isn't only out of cobble and mossy cobble. In response the server tells the client the real blocks. This may trigger hyper sensitive anti cheats but nobody complained about bans/kicks yet (version 2.9.0 has this feature always on and has ~2000 downloads currently). It makes the process much smoother and therefore I highly recommend leaving it on", 14 | "finder.buriedTreasures": "Buried treasures", 15 | "finder.desertTemples": "Desert temples", 16 | "finder.endCities": "End cities", 17 | "finder.jungleTemples": "Jungle temples", 18 | "finder.monuments": "Ocean monuments", 19 | "finder.swampHuts": "Witch huts", 20 | "finder.shipwrecks": "Shipwrecks", 21 | "finder.outposts": "Pillager Outposts", 22 | "finder.igloo": "Igloos", 23 | "finder.endPillars": "End pillars", 24 | "finder.endGateways": "End gateways", 25 | "finder.dungeons": "Dungeons", 26 | "finder.emeraldOres": "Emerald ores", 27 | "finder.desertWells": "Desert wells", 28 | "finder.warpedFungus": "Warped fungus", 29 | "finder.biomes": "Biomes", 30 | "finder.isFinder": "Finder %s is set to", 31 | "finder.setFinder": "Finder %s has been set to", 32 | "info": "Info", 33 | "info.clearData": "Clear data", 34 | "info.worldSeeds": "World seeds", 35 | "info.noWorldSeeds": "No world seeds found", 36 | "info.structureSeeds": "Structure seeds", 37 | "info.noStructureSeeds": "No structure seeds found", 38 | "info.pillarSeeds": "Pillar seeds", 39 | "info.noPillarSeeds": "No pillar seeds found", 40 | "info.hashedSeed": "Hashed seed", 41 | "info.noHashedSeed": "No hashed seed found", 42 | "fetchedHashedSeed": "The world seed in this dimension is different", 43 | "foundRestorableStructures": "Found %s structure/s from the previous session. Restore them with /seedcracker data restore", 44 | "foundStructureSeed": "Found structure seed ${SEED}.", 45 | "finishedSearchNoResult": "Finished search with no results.", 46 | "crossCompare": "Cross-compared seeds and reduced to ${SEED}.", 47 | "data.clearData": "Cleared data storage", 48 | "data.collectedBits": "You currently have collected %s bits out of %s.", 49 | "data.collectedLiftingBits": "You currently have collected %s bits from liftable structures out of %s.", 50 | "data.restoreStructures": "Restored %s structure/s", 51 | "data.restoreFailed": "no structures from the previous session found", 52 | "cracker.successfully": "Successfully ", 53 | "cracker.already": "already ", 54 | "cracker.enabled": "enabled", 55 | "cracker.disabled": "disabled", 56 | "render.getRenderMode": "Current render mode is set to", 57 | "render.setRenderMode": "Changed render mode to", 58 | "version.setVersion": "Changed version to", 59 | "tmachine.lookingForPillarSeed": "Looking for pillar seeds...", 60 | "tmachine.foundPillarSeed": "Found pillar seed ${SEED}.", 61 | "tmachine.pillarSeedSearchFinished": "Finished searching for pillar seeds.", 62 | "tmachine.lookingForStructureSeeds": "Looking for structure seeds with pillar seed [%s]...", 63 | "tmachine.progress": "Progress", 64 | "tmachine.structureSeedSearchFinished": "Finished searching for structure seeds.", 65 | "tmachine.decoratorWorldSeedSearch": "Looking for world seeds with decorators...", 66 | "tmachine.hashedSeedWorldSeedSearch": "Looking for world seeds with hashed seed...", 67 | "tmachine.foundWorldSeed": "Found world seed ${SEED}.", 68 | "tmachine.worldSeedSearchFinished": "Finished searching for world seeds.", 69 | "tmachine.noResultsRevertingToBiomes": "Finished search with no results, reverting back to biomes.", 70 | "tmachine.moreBiomesNeeded": "You need to collect more biome information", 71 | "tmachine.biomeWorldSeedSearch": "Looking for world seeds with %s biomes...", 72 | "tmachine.fuzzyBiomeSearch": "Trying fuzzy biome search", 73 | "tmachine.deepBiomeSearch": "trying deep biome search", 74 | "tmachine.printSeedsInConsole": "[Spam protection] printing all other seeds in console", 75 | "tmachine.deleteBiomeInformation": "Deleting biome information since no matching seed was found", 76 | "tmachine.randomSeedSearch": "Looking for world seeds that are possible if the world uses a random seed", 77 | "tmachine.startLifting": "Started lifting with %s structures. This takes a few minutes", 78 | "tmachine.reduceSeeds": "Reducing %s structure seeds", 79 | "tmachine.succeedReducing": "Reduced to %s structure seeds", 80 | "tmachine.failedReducing": "Failed to reduce seeds. You probably need more structures or your data is wrong", 81 | "dungeon.start": "Short-cutting to dungeons...", 82 | "dungeon.structureSeedSearchFailed": "Finished dungeon search with no seeds.", 83 | "dungeon.finishedNeedAnotherOne": "finished structure seed search. You'll need another dungeon", 84 | "fungus.start": "running cracker at %s %s", 85 | "fungus.fungusSeed": "fungus seed: ${SEED}.", 86 | "fungus.wrongData": "No Fungus seed, fungus was modified (also includes changes during generation)", 87 | "fungus.noStructureSeedsFound": "no seeds found for this Fungus.", 88 | "fungus.gotStructureSeeds": "got structure seeds:", 89 | "fungus.usableAsWorldSeed": "this structure seed is also usable as worldseed", 90 | "database.success": "sent seed to database successfully", 91 | "database.fail": "failed to send the seed to database" 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/resources/assets/seedcrackerx/lang/tr_tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Seed Cracker X", 3 | "settings": "Ayarlar", 4 | "settings.active": "Aktif", 5 | "settings.database": "10+ üstü oyuncu bulunan sunucu seed'lerini veri tabanına gönder", 6 | "settings.hideNameDatabase": "Veri tabanında kullanıcı adlarını gizle", 7 | "settings.openDatabase": "Veri tabanı'nı aç", 8 | "settings.version": "Sürüm", 9 | "settings.visuals": "Görseller", 10 | "settings.outline": "Dış çizgileri göster", 11 | "settings.finderToggles": "Arayıcı ayarları", 12 | "settings.antiXrayMode": "Anti Xray Modu", 13 | "settings.antiAntiXrayExplained": "Eğer Tapınak tabanı sadece kırıktaş ve yosunlu kırıktaş değilse sunucuya paket gönderir. Cevap olarak sunucu, gerçek blokları söyler. Bu işlem hassas hile korumalarını tetikleyebilir fakat şu ana kadar kimse ban/kick şikayeti iletmedi (2.9.0 sürümünde bu özellik hep açık ve ~2000 indirmeye sahip). Bu ayar, işlemi çok daha hafif hale getirir bu yüzden açık tutmanızı öneririm.", 14 | "finder.buriedTreasures": "Gömülü hazineler", 15 | "finder.desertTemples": "Çöl tapınakları", 16 | "finder.endCities": "End şehirleri", 17 | "finder.jungleTemples": "Orman tapınakları", 18 | "finder.monuments": "Okyanus mabetleri", 19 | "finder.swampHuts": "Cadı kulübeleri", 20 | "finder.shipwrecks": "Gemi enkazları", 21 | "finder.outposts": "Pillager mıntıkaları", 22 | "finder.igloo": "İglolar", 23 | "finder.endPillars": "End kuleleri", 24 | "finder.endGateways": "End geçitleri", 25 | "finder.dungeons": "Zindanlar", 26 | "finder.emeraldOres": "Zümrüt cevherleri", 27 | "finder.desertWells": "Çöl kuyuları", 28 | "finder.warpedFungus": "Eğri mantar", 29 | "finder.biomes": "Biyomlar", 30 | "finder.isFinder": "Arayıcı %s şuna ayarlı", 31 | "finder.setFinder": "Arayıcı %s şuna ayarlandı", 32 | "info": "Bilgi", 33 | "info.clearData": "Verileri temizle", 34 | "info.worldSeeds": "Dünya seed'leri", 35 | "info.noWorldSeeds": "Hiç dünya seed'i bulunamadı", 36 | "info.structureSeeds": "Yapı seed'leri", 37 | "info.noStructureSeeds": "Hiç yapı seed'i bulunamadı", 38 | "info.pillarSeeds": "Kule seed'leri", 39 | "info.noPillarSeeds": "Hiç kule seed'i bulunamadı", 40 | "info.hashedSeed": "Hash'lanmış seed", 41 | "info.noHashedSeed": "Hiç hash'lanmış seed bulunamadı", 42 | "fetchedHashedSeed": "Bu boyutta dünya seed'i farklı", 43 | "foundRestorableStructures": "Önceki oturumdan %s yapı(lar) bulundu. Şu komut ile kurtarın: /seedcracker data restore", 44 | "foundStructureSeed": "Yapı seed'i bulundu: ${SEED}", 45 | "finishedSearchNoResult": "Arama sonuç bulunamadan tamamlandı.", 46 | "crossCompare": "Seed'ler çapraz-karşılaştırma ile karşılaştırıldı ve ${SEED}'a azaltıldı", 47 | "data.clearData": "Veri deposu temizlendi", 48 | "data.collectedBits": "Şu ana kadar %s bit veri topladın (%s bit içerisinden).", 49 | "data.collectedLiftingBits": "Şu an kaldırılabilir yapılardan %s bit topladın (%s bit içerisinden)", 50 | "data.restoreStructures": "%s adet yapı kurtarıldı", 51 | "data.restoreFailed": "Önceki oturumdan hiç yapı bulunamadı", 52 | "cracker.successfully": "Başarılı ", 53 | "cracker.already": "zaten ", 54 | "cracker.enabled": "etkin", 55 | "cracker.disabled": "etkin değil", 56 | "render.getRenderMode": "Render modu şuna ayarlı", 57 | "render.setRenderMode": "Render modu ayarlandı", 58 | "version.setVersion": "Sürüö şuna ayarlandı:", 59 | "tmachine.lookingForPillarSeed": "Kule seed'leri aranıyor...", 60 | "tmachine.foundPillarSeed": "Kule seedi bulundu: ${SEED}", 61 | "tmachine.pillarSeedSearchFinished": "Kule seed'i arama işlemi bitirildi.", 62 | "tmachine.lookingForStructureSeeds": "Kule seed'i [%s] ile yapı seedleri aranıyor...", 63 | "tmachine.progress": "İlerleme", 64 | "tmachine.structureSeedSearchFinished": "Yapı seed'leri arama işlemi bitti.", 65 | "tmachine.decoratorWorldSeedSearch": "Dekoratörler ile dünya seed'leri aranıyor...", 66 | "tmachine.hashedSeedWorldSeedSearch": "Hash'lanmış seed ile dünya seedleri aranıyor...", 67 | "tmachine.foundWorldSeed": "Dünya seedi bulundu: ${SEED}", 68 | "tmachine.worldSeedSearchFinished": "Dünya seed'leri arama işlemi bitti.", 69 | "tmachine.noResultsRevertingToBiomes": "Arama işleminde sonuç bulunamadı, Biyom'a geri dönülüyor.", 70 | "tmachine.moreBiomesNeeded": "Daha fazla biyom bilgisi toplaman lazım.", 71 | "tmachine.biomeWorldSeedSearch": "%s biyom ile dünya seed'leri aranıyor...", 72 | "tmachine.fuzzyBiomeSearch": "Basit biyom arama işlemi deneniyor", 73 | "tmachine.deepBiomeSearch": "Detaylı biyom arama işlemi deneniyor", 74 | "tmachine.printSeedsInConsole": "[Spam Koruması] Diğer tüm seed'ler konsola yazdırılıyor", 75 | "tmachine.deleteBiomeInformation": "Eşleşen seed bulunamadığı için biyom bilgisi siliniyor", 76 | "tmachine.randomSeedSearch": "Dünya rastgele seed kullanıyorsa oluşabilecek seed'ler aranıyor", 77 | "tmachine.startLifting": "%s yapı ile kaldırılmaya başlandı. Bu işlem bir kaç dakika sürer", 78 | "tmachine.reduceSeeds": "%s yapı seed'i azaltılıyor", 79 | "tmachine.succeedReducing": "%s yapı seed'ine azaltıldı", 80 | "tmachine.failedReducing": "Seed'ler azaltılamadı. Muhtemelen daha çok yapıya ihtiyacınız var yada veriniz yanlış", 81 | "dungeon.start": "Zindan'a kısayol oluşturuluyor...", 82 | "dungeon.structureSeedSearchFailed": "Zindan aramasından sonuç bulunamadı.", 83 | "dungeon.finishedNeedAnotherOne": "yapı seed'i araması bitirildi. Başka bir zindana ihtiyacın var", 84 | "fungus.start": "Arayıcı %s %s'da çalıştırılıyor", 85 | "fungus.fungusSeed": "mantar seed'i: ${SEED}.", 86 | "fungus.wrongData": "Mantar seed'i yok, mantar değiştirilmiş (Oluşum aşamasında değişimler de olabilir)", 87 | "fungus.noStructureSeedsFound": "Bu mantar için hiç seed bulunamadı", 88 | "fungus.gotStructureSeeds": "Yapı seed'leri bulundu:", 89 | "fungus.usableAsWorldSeed": "bu yapı seed'i dünya seed'i olarak da kullanılabilir", 90 | "database.success": "seed veri tabanına başarıyla iletildi", 91 | "database.fail": "seed veri tabanına iletilemedi" 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/MonumentFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import com.seedfinding.mcfeature.structure.RegionStructure; 4 | import kaptainwutax.seedcrackerX.Features; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.finder.Finder; 8 | import kaptainwutax.seedcrackerX.render.Color; 9 | import kaptainwutax.seedcrackerX.render.Cube; 10 | import kaptainwutax.seedcrackerX.render.Cuboid; 11 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 12 | import net.minecraft.core.BlockPos; 13 | import net.minecraft.core.Direction; 14 | import net.minecraft.core.Vec3i; 15 | import net.minecraft.world.level.ChunkPos; 16 | import net.minecraft.world.level.Level; 17 | import net.minecraft.world.level.biome.Biome; 18 | import net.minecraft.world.level.block.Blocks; 19 | import net.minecraft.world.level.block.state.BlockState; 20 | import net.minecraft.world.level.dimension.DimensionType; 21 | 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | public class MonumentFinder extends Finder { 28 | 29 | protected static List SEARCH_POSITIONS; 30 | protected final Vec3i size = new Vec3i(8, 5, 8); 31 | protected List finders = new ArrayList<>(); 32 | 33 | public MonumentFinder(Level world, ChunkPos chunkPos) { 34 | super(world, chunkPos); 35 | 36 | PieceFinder finder = new PieceFinder(world, chunkPos, Direction.NORTH, size); 37 | 38 | finder.searchPositions = SEARCH_POSITIONS; 39 | 40 | buildStructure(finder); 41 | this.finders.add(finder); 42 | } 43 | 44 | public static void reloadSearchPositions() { 45 | SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> pos.getY() != 56); 46 | } 47 | 48 | public static List create(Level world, ChunkPos chunkPos) { 49 | List finders = new ArrayList<>(); 50 | finders.add(new MonumentFinder(world, chunkPos)); 51 | finders.add(new MonumentFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 52 | finders.add(new MonumentFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 53 | finders.add(new MonumentFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 54 | return finders; 55 | } 56 | 57 | @Override 58 | public List findInChunk() { 59 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 64, (this.chunkPos.z << 2) + 2).value(); 60 | if (BiomeFixer.swap(biome).getCategory() != com.seedfinding.mcbiome.biome.Biome.Category.OCEAN) return new ArrayList<>(); 61 | Map> result = this.findInChunkPieces(); 62 | List combinedResult = new ArrayList<>(); 63 | 64 | result.forEach((pieceFinder, positions) -> { 65 | positions.removeIf(pos -> { 66 | //Figure this out, it's not a trivial task. 67 | return false; 68 | }); 69 | 70 | combinedResult.addAll(positions); 71 | 72 | positions.forEach(pos -> { 73 | ChunkPos monumentStart = new ChunkPos(this.chunkPos.x + 1, this.chunkPos.z + 1); 74 | RegionStructure.Data data = Features.MONUMENT.at(monumentStart.x, monumentStart.z); 75 | 76 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 77 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(0, 0, 255))); 78 | this.renderers.add(new Cube(monumentStart.getWorldPosition().offset(0, pos.getY(), 0), new Color(0, 0, 255))); 79 | } 80 | }); 81 | }); 82 | 83 | return combinedResult; 84 | } 85 | 86 | public Map> findInChunkPieces() { 87 | Map> result = new HashMap<>(); 88 | 89 | this.finders.forEach(pieceFinder -> { 90 | result.put(pieceFinder, pieceFinder.findInChunk()); 91 | }); 92 | 93 | return result; 94 | } 95 | 96 | @Override 97 | public boolean isValidDimension(DimensionType dimension) { 98 | return this.isOverworld(dimension); 99 | } 100 | 101 | public void buildStructure(PieceFinder finder) { 102 | BlockState prismarine = Blocks.PRISMARINE.defaultBlockState(); 103 | BlockState prismarineBricks = Blocks.PRISMARINE_BRICKS.defaultBlockState(); 104 | BlockState darkPrismarine = Blocks.DARK_PRISMARINE.defaultBlockState(); 105 | BlockState seaLantern = Blocks.SEA_LANTERN.defaultBlockState(); 106 | BlockState water = Blocks.WATER.defaultBlockState(); 107 | 108 | //4 bottom pillars. 109 | for (int i = 0; i < 4; i++) { 110 | int x = i >= 2 ? 7 : 0; 111 | int z = i % 2 == 0 ? 0 : 7; 112 | 113 | for (int y = 0; y < 3; y++) { 114 | finder.addBlock(prismarineBricks, x, y, z); 115 | } 116 | } 117 | 118 | //First bend. 119 | for (int i = 0; i < 4; i++) { 120 | int x = i >= 2 ? 6 : 1; 121 | int z = i % 2 == 0 ? 1 : 6; 122 | finder.addBlock(prismarineBricks, x, 3, z); 123 | } 124 | 125 | //Prismarine ring. 126 | for (int x = 2; x <= 5; x++) { 127 | for (int z = 2; z <= 5; z++) { 128 | if (x == 2 || x == 5 || z == 2 || z == 5) { 129 | finder.addBlock(prismarine, x, 4, z); 130 | } 131 | } 132 | } 133 | 134 | //Second bend. 135 | for (int i = 0; i < 4; i++) { 136 | int x = i >= 2 ? 5 : 2; 137 | int z = i % 2 == 0 ? 2 : 5; 138 | finder.addBlock(prismarineBricks, x, 4, z); 139 | finder.addBlock(seaLantern, x, 3, z); 140 | } 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/resources/assets/seedcrackerx/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Seed Cracker X", 3 | "settings": "Настройки", 4 | "settings.active": "Крякер включен?", 5 | "settings.database": "Отправить в базу данных? (Работает если больше 10 игроков на сервере)", 6 | "settings.hideNameDatabase": "Скрыть имя пользователя в базе данных?", 7 | "settings.openDatabase": "Открыть базу данных", 8 | "settings.version": "Версия", 9 | "settings.visuals": "Визуальное оформление", 10 | "settings.outline": "Выделение контуров", 11 | "settings.finderToggles": "Структуры которые будут использоваться для поиска", 12 | "settings.antiXrayMode": "Anti Xray режим", 13 | "settings.antiAntiXrayExplained": "Отправляет пакеты серверу если данж со спаунером состоит не только из обычного и замшелого булыжника. В ответ сервер отправляет реальные блоки. Это может быть замечено очень чувствительными анти-читами, но никто пока не жаловался (версия 2.9.0 имеет эту функцию всегда включенной ~2000 скачиваний). Это делает процесс куда более плавным, поэтому я рекомендую оставлять это включенным", 14 | "finder.buriedTreasures": "Зарытые сокровища", 15 | "finder.desertTemples": "Пустынные пирамиды", 16 | "finder.endCities": "Города края", 17 | "finder.jungleTemples": "Джунглиевые пирамиды", 18 | "finder.monuments": "Подводные монументы", 19 | "finder.swampHuts": "Домики ведьмы", 20 | "finder.shipwrecks": "Кораблекрушения", 21 | "finder.outposts": "Аванпосты разбойников", 22 | "finder.igloo": "Иглу", 23 | "finder.endPillars": "Столбы края (обсидиановые)", 24 | "finder.endGateways": "Шлюзы края", 25 | "finder.dungeons": "Комнаты со спаунерами", 26 | "finder.emeraldOres": "Изумрудная руда", 27 | "finder.desertWells": "Пустынные колодцы", 28 | "finder.warpedFungus": "Искаженные грибы", 29 | "finder.biomes": "Биомы", 30 | "finder.isFinder": "Состояние искателя %s", 31 | "finder.setFinder": "Состояние искателя %s было изменено на", 32 | "info": "Информация", 33 | "info.clearData": "Очистить данные", 34 | "info.worldSeeds": "Сид мира", 35 | "info.noWorldSeeds": "Сид не был найден", 36 | "info.structureSeeds": "Структурный сид", 37 | "info.noStructureSeeds": "Структурные сиды не были найдены", 38 | "info.pillarSeeds": "Сид столбов края (обсидиановых)", 39 | "info.noPillarSeeds": "Сид столбов края (обсидиановых) не был найден", 40 | "info.hashedSeed": "Хешированный сид", 41 | "info.noHashedSeed": "Хешированный сид не был найден", 42 | "fetchedHashedSeed": "Сид в данном измерении отличается от прошлого.", 43 | "foundRestorableStructures": "Найдено %s структур с прошлой сессии. Восстановите их с помощью /seedcracker data restore", 44 | "foundStructureSeed": "Найден структурный сид ${SEED}.", 45 | "finishedSearchNoResult": "Поиск окончен без результатов.", 46 | "crossCompare": "Перекрестно сравниваем сиды и скоращаем ${SEED}.", 47 | "data.clearData": "Очистить данные", 48 | "data.collectedBits": "В данный момент у вас %s битов из %s.", 49 | "data.collectedLiftingBits": "В данный момент у вас %s битов лифтабильных стуктур из %s.", 50 | "data.restoreStructures": "Восстановлено %s структур", 51 | "data.restoreFailed": "Структур с прошлой сессии не было найдено", 52 | "cracker.successfully": "Успешно", 53 | "cracker.already": "уже", 54 | "cracker.enabled": "Включено", 55 | "cracker.disabled": "Выключено", 56 | "render.getRenderMode": "Актуальный режим рендера", 57 | "render.setRenderMode": "Режим рендера сменен на", 58 | "version.setVersion": "Версия изменена на", 59 | "tmachine.lookingForPillarSeed": "Поиск сида столбов края...", 60 | "tmachine.foundPillarSeed": "Сид столбов края найден ${SEED}.", 61 | "tmachine.pillarSeedSearchFinished": "Поиск сида столбов края завершен.", 62 | "tmachine.lookingForStructureSeeds": "Поиск структурного сида используя сид стобов края [%s]...", 63 | "tmachine.progress": "Прогресс", 64 | "tmachine.structureSeedSearchFinished": "Поиск структурного сида завершен.", 65 | "tmachine.decoratorWorldSeedSearch": "Поиск сида по декораторам...", 66 | "tmachine.hashedSeedWorldSeedSearch": "Поиск сида по хешированному сиду......", 67 | "tmachine.foundWorldSeed": "Сид мира найден ${SEED}.", 68 | "tmachine.worldSeedSearchFinished": "Поиск сида завершен.", 69 | "tmachine.noResultsRevertingToBiomes": "Поиск сида завершен без результатов, возвращаемся к биомам.", 70 | "tmachine.moreBiomesNeeded": "Вам необходимо собрать больше данных о биомах", 71 | "tmachine.biomeWorldSeedSearch": "Поиск сида используя %s биомов...", 72 | "tmachine.fuzzyBiomeSearch": "Пытаюсь выполнить поиск по нечеткому биому", 73 | "tmachine.deepBiomeSearch": "Попытка глубокого поиска по биомам", 74 | "tmachine.printSeedsInConsole": "[Защита от спама] вывод всех других структурных сидов в консоль", 75 | "tmachine.deleteBiomeInformation": "Удаление информации по биомам т.к не один сид не был найден", 76 | "tmachine.randomSeedSearch": "Поиск сида мира если мир использует случайный сид", 77 | "tmachine.startLifting": "Начинаем лифтинг используя %s структур. Это займет несколько минут", 78 | "tmachine.reduceSeeds": "Сокращаем %s структурных сидов", 79 | "tmachine.succeedReducing": "Уменьшено до %s структурных сидов", 80 | "tmachine.failedReducing": "Не получилось уменьшить количество структурных сидов. Вам нужно найти больше структрур, или же ваши данные повреждены", 81 | "dungeon.start": "Сокращение подземелий...", 82 | "dungeon.structureSeedSearchFailed": "Поиск по подземельям неудачен.", 83 | "dungeon.finishedNeedAnotherOne": "Поиск сида подземелья завершен. Вам нужно другое подземелье", 84 | "fungus.start": "использование крекера на %s %s", 85 | "fungus.fungusSeed": "Сид искаженного гриба: ${SEED}.", 86 | "fungus.wrongData": "Сид искаженного гриба не найден, он был изменен (так-же включает в себя изменения при генерации)", 87 | "fungus.noStructureSeedsFound": "Сид для этого искаженного гриба не найден.", 88 | "fungus.gotStructureSeeds": "найден структурный сид:", 89 | "fungus.usableAsWorldSeed": "этот структурный сид используется как сид мира", 90 | "database.success": "успешная отправка сида в базу данных", 91 | "database.fail": "провальная отправка сида в базу данных" 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/SwampHutFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import com.seedfinding.mcfeature.structure.RegionStructure; 4 | import kaptainwutax.seedcrackerX.Features; 5 | import kaptainwutax.seedcrackerX.SeedCracker; 6 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 7 | import kaptainwutax.seedcrackerX.finder.Finder; 8 | import kaptainwutax.seedcrackerX.render.Color; 9 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 10 | import net.minecraft.core.BlockPos; 11 | import net.minecraft.core.Direction; 12 | import net.minecraft.core.Vec3i; 13 | import net.minecraft.world.level.ChunkPos; 14 | import net.minecraft.world.level.Level; 15 | import net.minecraft.world.level.biome.Biome; 16 | import net.minecraft.world.level.block.Blocks; 17 | import net.minecraft.world.level.block.StairBlock; 18 | import net.minecraft.world.level.block.state.BlockState; 19 | import net.minecraft.world.level.block.state.properties.StairsShape; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | public class SwampHutFinder extends AbstractTempleFinder { 26 | 27 | public SwampHutFinder(Level world, ChunkPos chunkPos) { 28 | super(world, chunkPos, new Vec3i(7, 7, 9)); 29 | } 30 | 31 | public static List create(Level world, ChunkPos chunkPos) { 32 | List finders = new ArrayList<>(); 33 | finders.add(new SwampHutFinder(world, chunkPos)); 34 | return finders; 35 | } 36 | 37 | @Override 38 | public List findInChunk() { 39 | Map> result = super.findInChunkPieces(); 40 | List combinedResult = new ArrayList<>(); 41 | 42 | result.forEach((pieceFinder, positions) -> { 43 | combinedResult.addAll(positions); 44 | 45 | positions.forEach(pos -> { 46 | RegionStructure.Data data = Features.SWAMP_HUT.at(this.chunkPos.x, this.chunkPos.z); 47 | 48 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_LIFTING)) { 49 | this.addRenderers(pieceFinder, pos, new Color(255, 0, 255)); 50 | } 51 | }); 52 | }); 53 | 54 | return combinedResult; 55 | } 56 | 57 | @Override 58 | protected boolean isValidBiome(Biome biome) { 59 | return Features.SWAMP_HUT.isValidBiome(BiomeFixer.swap(biome)); 60 | } 61 | 62 | @Override 63 | public void buildStructure(PieceFinder finder) { 64 | finder.fillWithOutline(1, 1, 1, 5, 1, 7, Blocks.SPRUCE_PLANKS.defaultBlockState(), Blocks.SPRUCE_PLANKS.defaultBlockState(), false); 65 | finder.fillWithOutline(1, 4, 2, 5, 4, 7, Blocks.SPRUCE_PLANKS.defaultBlockState(), Blocks.SPRUCE_PLANKS.defaultBlockState(), false); 66 | finder.fillWithOutline(2, 1, 0, 4, 1, 0, Blocks.SPRUCE_PLANKS.defaultBlockState(), Blocks.SPRUCE_PLANKS.defaultBlockState(), false); 67 | finder.fillWithOutline(2, 2, 2, 3, 3, 2, Blocks.SPRUCE_PLANKS.defaultBlockState(), Blocks.SPRUCE_PLANKS.defaultBlockState(), false); 68 | finder.fillWithOutline(1, 2, 3, 1, 3, 6, Blocks.SPRUCE_PLANKS.defaultBlockState(), Blocks.SPRUCE_PLANKS.defaultBlockState(), false); 69 | finder.fillWithOutline(5, 2, 3, 5, 3, 6, Blocks.SPRUCE_PLANKS.defaultBlockState(), Blocks.SPRUCE_PLANKS.defaultBlockState(), false); 70 | finder.fillWithOutline(2, 2, 7, 4, 3, 7, Blocks.SPRUCE_PLANKS.defaultBlockState(), Blocks.SPRUCE_PLANKS.defaultBlockState(), false); 71 | finder.fillWithOutline(1, 0, 2, 1, 3, 2, Blocks.OAK_LOG.defaultBlockState(), Blocks.OAK_LOG.defaultBlockState(), false); 72 | finder.fillWithOutline(5, 0, 2, 5, 3, 2, Blocks.OAK_LOG.defaultBlockState(), Blocks.OAK_LOG.defaultBlockState(), false); 73 | finder.fillWithOutline(1, 0, 7, 1, 3, 7, Blocks.OAK_LOG.defaultBlockState(), Blocks.OAK_LOG.defaultBlockState(), false); 74 | finder.fillWithOutline(5, 0, 7, 5, 3, 7, Blocks.OAK_LOG.defaultBlockState(), Blocks.OAK_LOG.defaultBlockState(), false); 75 | finder.addBlock(Blocks.OAK_FENCE.defaultBlockState(), 2, 3, 2); 76 | finder.addBlock(Blocks.OAK_FENCE.defaultBlockState(), 3, 3, 7); 77 | finder.addBlock(Blocks.AIR.defaultBlockState(), 1, 3, 4); 78 | finder.addBlock(Blocks.AIR.defaultBlockState(), 5, 3, 4); 79 | finder.addBlock(Blocks.AIR.defaultBlockState(), 5, 3, 5); 80 | finder.addBlock(Blocks.POTTED_RED_MUSHROOM.defaultBlockState(), 1, 3, 5); 81 | finder.addBlock(Blocks.CRAFTING_TABLE.defaultBlockState(), 3, 2, 6); 82 | finder.addBlock(Blocks.CAULDRON.defaultBlockState(), 4, 2, 6); 83 | finder.addBlock(Blocks.OAK_FENCE.defaultBlockState(), 1, 2, 1); 84 | finder.addBlock(Blocks.OAK_FENCE.defaultBlockState(), 5, 2, 1); 85 | BlockState northStairs = Blocks.SPRUCE_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.NORTH); 86 | BlockState eastStairs = Blocks.SPRUCE_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.EAST); 87 | BlockState westStairs = Blocks.SPRUCE_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.WEST); 88 | BlockState southStairs = Blocks.SPRUCE_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.SOUTH); 89 | finder.fillWithOutline(0, 4, 1, 6, 4, 1, northStairs, northStairs, false); 90 | finder.fillWithOutline(0, 4, 2, 0, 4, 7, eastStairs, eastStairs, false); 91 | finder.fillWithOutline(6, 4, 2, 6, 4, 7, westStairs, westStairs, false); 92 | finder.fillWithOutline(0, 4, 8, 6, 4, 8, southStairs, southStairs, false); 93 | finder.addBlock(northStairs.setValue(StairBlock.SHAPE, StairsShape.OUTER_RIGHT), 0, 4, 1); 94 | finder.addBlock(northStairs.setValue(StairBlock.SHAPE, StairsShape.OUTER_LEFT), 6, 4, 1); 95 | finder.addBlock(southStairs.setValue(StairBlock.SHAPE, StairsShape.OUTER_LEFT), 0, 4, 8); 96 | finder.addBlock(southStairs.setValue(StairBlock.SHAPE, StairsShape.OUTER_RIGHT), 6, 4, 8); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/decorator/FullFungusData.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker.decorator; 2 | 3 | import com.seedfinding.latticg.reversal.DynamicProgram; 4 | import com.seedfinding.latticg.reversal.calltype.java.JavaCalls; 5 | import com.seedfinding.latticg.util.LCG; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.stream.LongStream; 10 | 11 | public class FullFungusData { 12 | 13 | 14 | public final ArrayList layerSizes = new ArrayList<>(); 15 | public final int[][][] layers; 16 | public final ArrayList vines = new ArrayList<>(); 17 | public final ArrayList bigtrunkData = new ArrayList<>(); 18 | public final int estimatedData; 19 | public boolean big; 20 | public int height; 21 | public int vineLayerSize; 22 | 23 | public FullFungusData(List layerSizes, int[][][] layers, ArrayList vines, boolean big, int height, int vineLayerSize, ArrayList bigTrunkData, int estimatedData) { 24 | this.layerSizes.addAll(layerSizes); 25 | this.layers = layers.clone(); 26 | this.vines.addAll(vines); 27 | this.big = big; 28 | this.height = height; 29 | this.vineLayerSize = vineLayerSize; 30 | this.bigtrunkData.addAll(bigTrunkData); 31 | this.estimatedData = estimatedData; 32 | } 33 | 34 | 35 | public static FullFungusData getBestFungus(List fungusList) { 36 | int data = 0; 37 | FullFungusData out = null; 38 | 39 | for (FullFungusData fungus : fungusList) { 40 | int fungusData = fungus.estimatedData; 41 | if (fungusData > data) { 42 | data = fungusData; 43 | out = fungus; 44 | } 45 | } 46 | 47 | return out; 48 | } 49 | 50 | public LongStream crackSeed() { 51 | int doppelt = 0; 52 | if (height > 7 && height % 2 == 0) { 53 | doppelt = 1; 54 | if (height > 13) { 55 | doppelt = 2; 56 | } 57 | } 58 | 59 | DynamicProgram device = DynamicProgram.create(LCG.JAVA); 60 | if (doppelt < 2) { 61 | device.skip(2); 62 | } else { 63 | device.skip(1); 64 | device.add(JavaCalls.nextInt(12).equalTo(0)); 65 | } 66 | if (big) { 67 | device.add(JavaCalls.nextFloat().betweenII(0F, 0.06F)); 68 | } else { 69 | device.skip(1); 70 | } 71 | 72 | if (big) { 73 | for (int blockdata : bigtrunkData) { 74 | if (blockdata == 0) { 75 | device.skip(1); 76 | } else if (blockdata == 1) { 77 | device.add(JavaCalls.nextFloat().betweenII(0F, 0.1F)); 78 | } 79 | } 80 | } 81 | 82 | device.skip(2); 83 | 84 | ArrayList done = new ArrayList<>(); 85 | for (int j = 3; j > 0; j--) { 86 | 87 | for (int i = 0; i < vineLayerSize * 8; i++) { 88 | if (vines.get(i) == 0 && !done.contains(i)) { 89 | device.skip(1); 90 | 91 | } else if (vines.get(i) == j) { 92 | done.add(i); 93 | device.add(JavaCalls.nextFloat().betweenII(0F, 0.15F)); 94 | 95 | } else if (!done.contains(i)) { 96 | device.skip(1); 97 | 98 | } 99 | } 100 | 101 | device.skip(1); 102 | } 103 | int relativePos; 104 | int blockType; 105 | int layer = 0; 106 | 107 | for (int size : layerSizes) { 108 | size *= 2; 109 | 110 | for (int x = 0; x <= size; x++) { 111 | 112 | boolean siteX = x == 0 || x == size; 113 | for (int z = 0; z <= size; z++) { 114 | 115 | boolean siteZ = z == 0 || z == size; 116 | 117 | relativePos = (siteX ? 1 : 0) + (siteZ ? 1 : 0); 118 | 119 | blockType = layers[layer][x][z]; 120 | 121 | generateBlock(relativePos, blockType, device); 122 | } 123 | } 124 | 125 | device.skip(1); 126 | layer++; 127 | } 128 | return device.reverse(); 129 | } 130 | 131 | private void generateBlock(int relativePos, int blockType, DynamicProgram device) { 132 | 133 | if (blockType == 3) return; 134 | switch (relativePos) { 135 | case 0: 136 | //Inside 137 | switch (blockType) { 138 | case 0: 139 | device.skip(2); 140 | break; 141 | case 1: 142 | device.skip(3); 143 | break; 144 | case 2: 145 | device.add(JavaCalls.nextFloat().betweenII(0F, 0.1F)); 146 | } 147 | break; 148 | case 1: 149 | //Wall 150 | switch (blockType) { 151 | case 0: 152 | device.skip(1); 153 | device.add(JavaCalls.nextFloat().betweenII(0.98F, 1F)); 154 | break; 155 | case 1: 156 | device.skip(3); 157 | break; 158 | case 2: 159 | device.add(JavaCalls.nextFloat().betweenII(0F, 5.0E-4F)); 160 | } 161 | break; 162 | case 2: 163 | //Corner 164 | switch (blockType) { 165 | case 0: 166 | device.skip(2); 167 | break; 168 | case 1: 169 | device.skip(3); 170 | break; 171 | case 2: 172 | device.add(JavaCalls.nextFloat().betweenII(0F, 0.01F)); 173 | } 174 | break; 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/structure/EndCityFinder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder.structure; 2 | 3 | import com.seedfinding.mccore.util.pos.BPos; 4 | import com.seedfinding.mccore.version.MCVersion; 5 | import com.seedfinding.mcfeature.structure.RegionStructure; 6 | import kaptainwutax.seedcrackerX.Features; 7 | import kaptainwutax.seedcrackerX.SeedCracker; 8 | import kaptainwutax.seedcrackerX.config.Config; 9 | import kaptainwutax.seedcrackerX.cracker.DataAddedEvent; 10 | import kaptainwutax.seedcrackerX.finder.Finder; 11 | import kaptainwutax.seedcrackerX.render.Color; 12 | import kaptainwutax.seedcrackerX.render.Cube; 13 | import kaptainwutax.seedcrackerX.render.Cuboid; 14 | import kaptainwutax.seedcrackerX.util.BiomeFixer; 15 | import net.minecraft.core.BlockPos; 16 | import net.minecraft.core.Direction; 17 | import net.minecraft.core.Vec3i; 18 | import net.minecraft.world.level.ChunkPos; 19 | import net.minecraft.world.level.Level; 20 | import net.minecraft.world.level.biome.Biome; 21 | import net.minecraft.world.level.block.Blocks; 22 | import net.minecraft.world.level.block.state.BlockState; 23 | import net.minecraft.world.level.dimension.DimensionType; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | public class EndCityFinder extends Finder { 31 | 32 | protected static List SEARCH_POSITIONS; 33 | protected final Vec3i size = new Vec3i(8, 4, 8); 34 | protected List finders = new ArrayList<>(); 35 | 36 | public EndCityFinder(Level world, ChunkPos chunkPos) { 37 | super(world, chunkPos); 38 | 39 | Direction.Plane.HORIZONTAL.forEach(direction -> { 40 | PieceFinder finder = new PieceFinder(world, chunkPos, direction, size); 41 | 42 | finder.searchPositions = SEARCH_POSITIONS; 43 | 44 | buildStructure(finder); 45 | this.finders.add(finder); 46 | }); 47 | } 48 | 49 | public static void reloadSearchPositions() { 50 | SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> pos.getY() > 90 && pos.getY() < 40); 51 | } 52 | 53 | public static List create(Level world, ChunkPos chunkPos) { 54 | List finders = new ArrayList<>(); 55 | finders.add(new EndCityFinder(world, chunkPos)); 56 | finders.add(new EndCityFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z))); 57 | finders.add(new EndCityFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1))); 58 | finders.add(new EndCityFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1))); 59 | return finders; 60 | } 61 | 62 | private void buildStructure(PieceFinder finder) { 63 | BlockState air = Blocks.AIR.defaultBlockState(); 64 | BlockState endstoneBricks = Blocks.END_STONE_BRICKS.defaultBlockState(); 65 | BlockState purpur = Blocks.PURPUR_BLOCK.defaultBlockState(); 66 | BlockState purpurPillar = Blocks.PURPUR_PILLAR.defaultBlockState(); 67 | BlockState purpleGlass = Blocks.MAGENTA_STAINED_GLASS.defaultBlockState(); 68 | 69 | //Walls 70 | finder.fillWithOutline(0, 0, 0, 7, 4, 7, endstoneBricks, null, false); 71 | 72 | //Wall sides 73 | finder.fillWithOutline(0, 0, 0, 0, 3, 0, purpurPillar, purpurPillar, false); 74 | finder.fillWithOutline(7, 0, 0, 7, 3, 0, purpurPillar, purpurPillar, false); 75 | finder.fillWithOutline(0, 0, 7, 0, 3, 7, purpurPillar, purpurPillar, false); 76 | finder.fillWithOutline(7, 0, 7, 7, 3, 7, purpurPillar, purpurPillar, false); 77 | 78 | //Floor 79 | finder.fillWithOutline(0, 0, 0, 7, 0, 7, purpur, purpur, false); 80 | 81 | //Doorway 82 | finder.fillWithOutline(3, 1, 0, 4, 3, 0, air, air, false); 83 | 84 | //Windows 85 | finder.fillWithOutline(0, 2, 2, 0, 3, 2, purpleGlass, purpleGlass, false); 86 | finder.fillWithOutline(0, 2, 5, 0, 3, 5, purpleGlass, purpleGlass, false); 87 | finder.fillWithOutline(7, 2, 2, 7, 3, 2, purpleGlass, purpleGlass, false); 88 | finder.fillWithOutline(7, 2, 5, 7, 3, 5, purpleGlass, purpleGlass, false); 89 | } 90 | 91 | @Override 92 | public List findInChunk() { 93 | Biome biome = this.world.getNoiseBiome((this.chunkPos.x << 2) + 2, 64, (this.chunkPos.z << 2) + 2).value(); 94 | if (!Features.END_CITY.isValidBiome(BiomeFixer.swap(biome))) return new ArrayList<>(); 95 | 96 | Map> result = this.findInChunkPieces(); 97 | List combinedResult = new ArrayList<>(); 98 | 99 | result.forEach((pieceFinder, positions) -> { 100 | positions.removeIf(pos -> { 101 | //Figure this out, it's not a trivial task. 102 | return false; 103 | }); 104 | 105 | combinedResult.addAll(positions); 106 | 107 | positions.forEach(pos -> { 108 | //minecraft 1.19 moved end citys by 1 block reeeeeeeee 109 | if (Config.get().getVersion().isNewerOrEqualTo(MCVersion.v1_19)) { 110 | BlockPos posFix = pos.offset(1, 0, 1); 111 | RegionStructure.Data data = Features.END_CITY.at(posFix.getX()>>4, posFix.getZ()>>4); 112 | 113 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 114 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(153, 0, 153))); 115 | this.renderers.add(new Cube(posFix, new Color(153, 0, 153))); 116 | } 117 | } else { 118 | RegionStructure.Data data = Features.END_CITY.at(this.chunkPos.x, this.chunkPos.z); 119 | 120 | if (SeedCracker.get().getDataStorage().addBaseData(data, DataAddedEvent.POKE_STRUCTURES)) { 121 | this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Color(153, 0, 153))); 122 | this.renderers.add(new Cube(pos, new Color(153, 0, 153))); 123 | } 124 | } 125 | }); 126 | }); 127 | 128 | return combinedResult; 129 | } 130 | 131 | public Map> findInChunkPieces() { 132 | Map> result = new HashMap<>(); 133 | 134 | this.finders.forEach(pieceFinder -> { 135 | result.put(pieceFinder, pieceFinder.findInChunk()); 136 | }); 137 | 138 | return result; 139 | } 140 | 141 | @Override 142 | public boolean isValidDimension(DimensionType dimension) { 143 | return this.isEnd(dimension); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/finder/Finder.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.finder; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import com.mojang.blaze3d.vertex.VertexConsumer; 5 | import kaptainwutax.seedcrackerX.config.Config; 6 | import kaptainwutax.seedcrackerX.finder.decorator.*; 7 | import kaptainwutax.seedcrackerX.finder.decorator.ore.EmeraldOreFinder; 8 | import kaptainwutax.seedcrackerX.finder.structure.*; 9 | import kaptainwutax.seedcrackerX.render.Renderer; 10 | import kaptainwutax.seedcrackerX.util.FeatureToggle; 11 | import kaptainwutax.seedcrackerX.util.HeightContext; 12 | import net.minecraft.client.Minecraft; 13 | import net.minecraft.core.BlockPos; 14 | import net.minecraft.world.level.ChunkPos; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraft.world.level.dimension.DimensionType; 17 | import net.minecraft.world.phys.Vec3; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Arrays; 21 | import java.util.List; 22 | import java.util.function.Predicate; 23 | import java.util.stream.Collectors; 24 | 25 | public abstract class Finder { 26 | 27 | protected static final List CHUNK_POSITIONS = new ArrayList<>(); 28 | protected static final List SUB_CHUNK_POSITIONS = new ArrayList<>(); 29 | protected static HeightContext heightContext; 30 | 31 | static { 32 | for (int x = 0; x < 16; x++) { 33 | for (int z = 0; z < 16; z++) { 34 | for (int y = 0; y < 16; y++) { 35 | SUB_CHUNK_POSITIONS.add(new BlockPos(x, y, z)); 36 | } 37 | } 38 | } 39 | } 40 | 41 | protected Minecraft mc = Minecraft.getInstance(); 42 | protected List renderers = new ArrayList<>(); 43 | protected Level world; 44 | protected ChunkPos chunkPos; 45 | 46 | public Finder(Level world, ChunkPos chunkPos) { 47 | this.world = world; 48 | this.chunkPos = chunkPos; 49 | } 50 | 51 | public static List buildSearchPositions(List base, Predicate removeIf) { 52 | List newList = new ArrayList<>(); 53 | 54 | for (BlockPos pos : base) { 55 | if (!removeIf.test(pos)) { 56 | newList.add(pos); 57 | } 58 | } 59 | 60 | return newList; 61 | } 62 | 63 | public Level getWorld() { 64 | return this.world; 65 | } 66 | 67 | public ChunkPos getChunkPos() { 68 | return this.chunkPos; 69 | } 70 | 71 | public abstract List findInChunk(); 72 | 73 | public boolean shouldRender() { 74 | DimensionType finderDim = this.world.dimensionType(); 75 | DimensionType playerDim = mc.player.clientLevel.dimensionType(); 76 | 77 | if (finderDim != playerDim) return false; 78 | 79 | int renderDistance = mc.options.renderDistance().get() * 16 + 16; 80 | Vec3 playerPos = mc.player.position(); 81 | 82 | for (Renderer renderer : this.renderers) { 83 | BlockPos pos = renderer.getPos(); 84 | double distance = playerPos.distanceToSqr(pos.getX(), playerPos.y, pos.getZ()); 85 | if (distance <= renderDistance * renderDistance + 32) return true; 86 | } 87 | 88 | return false; 89 | } 90 | 91 | public void render(PoseStack matrixStack, VertexConsumer vertexConsumer, Vec3 cameraPos) { 92 | this.renderers.forEach(renderer -> renderer.render(matrixStack, vertexConsumer, cameraPos)); 93 | } 94 | 95 | public boolean isUseless() { 96 | return this.renderers.isEmpty(); 97 | } 98 | 99 | public abstract boolean isValidDimension(DimensionType dimension); 100 | 101 | public boolean isOverworld(DimensionType dimension) { 102 | return dimension.effectsLocation().getPath().equals("overworld"); 103 | } 104 | 105 | public boolean isNether(DimensionType dimension) { 106 | return dimension.effectsLocation().getPath().equals("the_nether"); 107 | } 108 | 109 | public boolean isEnd(DimensionType dimension) { 110 | return dimension.effectsLocation().getPath().equals("the_end"); 111 | } 112 | 113 | public enum Category { 114 | STRUCTURES, 115 | DECORATORS, 116 | BIOMES, 117 | } 118 | 119 | public enum Type { 120 | BURIED_TREASURE(BuriedTreasureFinder::create, Category.STRUCTURES, Config.get().buriedTreasure, "finder.buriedTreasures"), 121 | DESERT_TEMPLE(DesertPyramidFinder::create, Category.STRUCTURES, Config.get().desertTemple, "finder.desertTemples"), 122 | END_CITY(EndCityFinder::create, Category.STRUCTURES, Config.get().endCity, "finder.endCities"), 123 | JUNGLE_TEMPLE(JunglePyramidFinder::create, Category.STRUCTURES, Config.get().jungleTemple, "finder.jungleTemples"), 124 | MONUMENT(MonumentFinder::create, Category.STRUCTURES, Config.get().monument, "finder.monuments"), 125 | SWAMP_HUT(SwampHutFinder::create, Category.STRUCTURES, Config.get().swampHut, "finder.swampHuts"), 126 | SHIPWRECK(ShipwreckFinder::create, Category.STRUCTURES, Config.get().shipwreck, "finder.shipwrecks"), 127 | PILLAGER_OUTPOST(OutpostFinder::create, Category.STRUCTURES, Config.get().outpost, "finder.outposts"), 128 | IGLOO(IglooFinder::create, Category.STRUCTURES, Config.get().igloo, "finder.igloo"), 129 | 130 | END_PILLARS(EndPillarsFinder::create, Category.DECORATORS, Config.get().endPillars, "finder.endPillars"), 131 | END_GATEWAY(EndGatewayFinder::create, Category.DECORATORS, Config.get().endGateway, "finder.endGateways"), 132 | DUNGEON(DungeonFinder::create, Category.DECORATORS, Config.get().dungeon, "finder.dungeons"), 133 | EMERALD_ORE(EmeraldOreFinder::create, Category.DECORATORS, Config.get().emeraldOre, "finder.emeraldOres"), 134 | DESERT_WELL(DesertWellFinder::create, Category.DECORATORS, Config.get().desertWell, "finder.desertWells"), 135 | WARPED_FUNGUS(WarpedFungusFinder::create, Category.DECORATORS, Config.get().warpedFungus, "finder.warpedFungus"), 136 | 137 | BIOME(BiomeFinder::create, Category.BIOMES, Config.get().biome, "finder.biomes"); 138 | 139 | public final FinderBuilder finderBuilder; 140 | public final String nameKey; 141 | private final Category category; 142 | public FeatureToggle enabled; 143 | 144 | Type(FinderBuilder finderBuilder, Category category, FeatureToggle enabled, String nameKey) { 145 | this.finderBuilder = finderBuilder; 146 | this.category = category; 147 | this.enabled = enabled; 148 | this.nameKey = nameKey; 149 | } 150 | 151 | public static List getForCategory(Category category) { 152 | return Arrays.stream(values()).filter(type -> type.category == category).collect(Collectors.toList()); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/cracker/decorator/WarpedFungus.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.cracker.decorator; 2 | 3 | import com.seedfinding.mcbiome.biome.Biome; 4 | import com.seedfinding.mcbiome.biome.Biomes; 5 | import com.seedfinding.mccore.rand.ChunkRand; 6 | import com.seedfinding.mccore.state.Dimension; 7 | import com.seedfinding.mccore.version.MCVersion; 8 | import com.seedfinding.mccore.version.VersionMap; 9 | import com.seedfinding.mcreversal.PopulationReverser; 10 | import com.seedfinding.mcseed.lcg.LCG; 11 | import kaptainwutax.seedcrackerX.cracker.storage.DataStorage; 12 | import kaptainwutax.seedcrackerX.cracker.storage.TimeMachine; 13 | import kaptainwutax.seedcrackerX.util.Log; 14 | import net.minecraft.core.BlockPos; 15 | import net.minecraft.world.level.levelgen.WorldgenRandom; 16 | 17 | import java.util.*; 18 | 19 | public class WarpedFungus extends Decorator { 20 | public static final VersionMap CONFIGS = new VersionMap() 21 | .add(MCVersion.v1_16, new Decorator.Config(8, 3)); 22 | 23 | public WarpedFungus(MCVersion version) { 24 | super(CONFIGS.getAsOf(version), version); 25 | } 26 | 27 | public WarpedFungus.Data at(int blockX, int blockZ, Biome biome, List posList, FullFungusData fungusData) { 28 | return new WarpedFungus.Data(this, blockX, blockZ, biome, posList, fungusData); 29 | } 30 | 31 | @Override 32 | public String getName() { 33 | return "warped fungus"; 34 | } 35 | 36 | @Override 37 | public boolean canStart(WarpedFungus.Data data, long structureSeed, ChunkRand rand) { 38 | return true; 39 | } 40 | 41 | @Override 42 | public boolean canStart(WarpedFungus.Data data, long structureSeed, WorldgenRandom rand) { 43 | return true; 44 | } 45 | 46 | @Override 47 | public boolean isValidDimension(Dimension dimension) { 48 | return dimension == Dimension.NETHER; 49 | } 50 | 51 | @Override 52 | public Dimension getValidDimension() { 53 | return Dimension.NETHER; 54 | } 55 | 56 | @Override 57 | public boolean isValidBiome(Biome biome) { 58 | return biome == Biomes.WARPED_FOREST; 59 | } 60 | 61 | public static class Data extends Decorator.Data { 62 | 63 | public final FullFungusData fullFungi; 64 | public final List posList = new ArrayList<>(); 65 | private final int BlockX; 66 | private final int BlockZ; 67 | 68 | public Data(WarpedFungus feature, int blockX, int blockZ, Biome biome, List posList, FullFungusData fungusData) { 69 | super(feature, blockX, blockZ, biome); 70 | fullFungi = fungusData; 71 | BlockX = blockX; 72 | BlockZ = blockZ; 73 | for (BlockPos pos : posList) { 74 | this.posList.add(new BlockPos(((pos.getX() % 16) + 16) % 16, 0, ((pos.getZ() % 16) + 16) % 16)); 75 | } 76 | } 77 | 78 | public void onDataAdded(DataStorage dataStorage) { 79 | if (dataStorage.getTimeMachine().worldSeeds.size() == 1) return; 80 | if (dataStorage.getTimeMachine().structureSeeds.size() == 1) return; 81 | if (this.feature.getVersion().isNewerThan(MCVersion.v1_17_1)) return; 82 | 83 | Log.warn("fungus.start", BlockX, BlockZ); 84 | 85 | List fungusSeeds = fullFungi.crackSeed().boxed().toList(); 86 | 87 | Log.debug("===================================="); 88 | fungusSeeds.forEach(s -> Log.printSeed("fungus.fungusSeed", s)); 89 | 90 | if (fungusSeeds.isEmpty()) { 91 | Log.warn("fungus.wrongData"); 92 | Log.debug("===================================="); 93 | return; 94 | } 95 | Log.debug("===================================="); 96 | 97 | LinkedHashSet structureSeedList = new LinkedHashSet<>(); 98 | fungusSeeds.forEach(s -> structureSeedList.addAll(reverseToDecoratorSeed(s))); 99 | if (structureSeedList.isEmpty()) { 100 | Log.warn("fungus.noStructureSeedsFound"); 101 | return; 102 | } 103 | 104 | Set result = new HashSet<>(); 105 | 106 | Log.warn("fungus.gotStructureSeeds"); 107 | for (Long structureSeed : structureSeedList) { 108 | Log.printSeed("foundStructureSeed", structureSeed); 109 | if (!dataStorage.getTimeMachine().structureSeeds.add(structureSeed)) { 110 | result.add(structureSeed); 111 | } 112 | } 113 | 114 | if (result.size() == 1) { 115 | Log.debug("===================================="); 116 | result.forEach(seed -> Log.printSeed("crossCompare", seed)); 117 | Log.warn("fungus.usableAsWorldSeed"); 118 | dataStorage.getTimeMachine().structureSeeds = result; 119 | } 120 | dataStorage.getTimeMachine().poke(TimeMachine.Phase.BIOMES); 121 | } 122 | 123 | 124 | private LinkedHashSet reverseToDecoratorSeed(long fungusSeed) { 125 | LinkedHashSet structureSeedList = new LinkedHashSet<>(); 126 | ChunkRand rand = new ChunkRand(fungusSeed, false); 127 | ChunkRand rand2 = new ChunkRand(0); 128 | ChunkRand popReverseRand = new ChunkRand(0); 129 | rand.advance(-4000); 130 | int lastPos = -1; 131 | for (int i = 0; i < 4000; i++) { 132 | int pos = rand.nextInt(16); 133 | for (BlockPos fungusPos : posList) { 134 | if (fungusPos.getX() == lastPos && fungusPos.getZ() == pos) { 135 | rand.advance(-2); 136 | if (checkPoses(rand.getSeed())) { 137 | 138 | rand2.setSeed(rand.getSeed(), false); 139 | for (int j = 0; j < 8; j++) { 140 | long populationSeed = (rand2.getSeed() ^ LCG.JAVA.multiplier) - 80003; 141 | structureSeedList.addAll(PopulationReverser.reverse(populationSeed, BlockX, BlockZ, popReverseRand, MCVersion.v1_16_2)); 142 | rand2.advance(-2); 143 | } 144 | 145 | } 146 | rand.advance(2); 147 | break; 148 | } 149 | } 150 | lastPos = pos; 151 | } 152 | return structureSeedList; 153 | } 154 | 155 | private boolean checkPoses(long seed) { 156 | List posesClone = new ArrayList<>(posList); 157 | ChunkRand rand = new ChunkRand(seed, false); 158 | int counter = 0; 159 | for (int i = 0; i < 100; i++) { 160 | counter++; 161 | if (counter > 10) { 162 | return false; 163 | } 164 | int x = rand.nextInt(16); 165 | int z = rand.nextInt(16); 166 | for (int j = 0; j < posesClone.size(); j++) { 167 | if (posesClone.get(j).getX() == x && posesClone.get(j).getZ() == z) { 168 | counter = 0; 169 | posesClone.remove(j); 170 | break; 171 | } 172 | } 173 | if (posesClone.isEmpty()) return true; 174 | } 175 | return false; 176 | } 177 | } 178 | } 179 | 180 | -------------------------------------------------------------------------------- /src/main/java/kaptainwutax/seedcrackerX/config/ConfigScreen.java: -------------------------------------------------------------------------------- 1 | package kaptainwutax.seedcrackerX.config; 2 | 3 | import com.seedfinding.mccore.version.MCVersion; 4 | import kaptainwutax.seedcrackerX.SeedCracker; 5 | import kaptainwutax.seedcrackerX.command.DatabaseCommand; 6 | import kaptainwutax.seedcrackerX.cracker.HashedSeedData; 7 | import kaptainwutax.seedcrackerX.finder.Finder; 8 | import me.shedaniel.clothconfig2.api.ConfigBuilder; 9 | import me.shedaniel.clothconfig2.api.ConfigCategory; 10 | import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; 11 | import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder; 12 | import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder; 13 | import net.minecraft.ChatFormatting; 14 | import net.minecraft.client.gui.screens.Screen; 15 | import net.minecraft.network.chat.ClickEvent; 16 | import net.minecraft.network.chat.Component; 17 | import net.minecraft.network.chat.HoverEvent; 18 | import net.minecraft.resources.ResourceLocation; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | 25 | public class ConfigScreen { 26 | 27 | private static final Config config = Config.get(); 28 | 29 | private ArrayList getSupportedVersions() { 30 | ArrayList newerVersions = new ArrayList<>(); 31 | for (MCVersion version : MCVersion.values()) { 32 | if (version.isOlderThan(MCVersion.v1_8)) continue; 33 | newerVersions.add(version); 34 | } 35 | return newerVersions; 36 | } 37 | 38 | private MCVersion mcVersionFromString(String version) { 39 | MCVersion mcVersion = MCVersion.fromString(version); 40 | if (mcVersion == null) return MCVersion.latest(); 41 | return mcVersion; 42 | } 43 | 44 | public Screen getConfigScreenByCloth(Screen parent) { 45 | 46 | ConfigBuilder builder = ConfigBuilder.create() 47 | .setParentScreen(parent) 48 | .setTitle(Component.translatable("title")) 49 | .setDefaultBackgroundTexture(new ResourceLocation("minecraft:textures/block/blackstone.png")) 50 | .setTransparentBackground(true); 51 | ConfigEntryBuilder eb = builder.entryBuilder(); 52 | 53 | //=============================CONFIG======================== 54 | ConfigCategory settings = builder.getOrCreateCategory(Component.translatable("settings")); 55 | 56 | settings.addEntry(eb.startBooleanToggle(Component.translatable("settings.active"), config.active).setSaveConsumer(val -> config.active = val).build()); 57 | settings.addEntry(eb.startBooleanToggle(Component.translatable("settings.database"), config.databaseSubmits) 58 | .setSaveConsumer(val -> config.databaseSubmits = val).build()); 59 | settings.addEntry(eb.startBooleanToggle(Component.translatable("settings.hideNameDatabase"), config.anonymusSubmits).setSaveConsumer(val -> config.anonymusSubmits = val).build()); 60 | settings.addEntry(eb.startTextDescription(Component.translatable("settings.openDatabase").withStyle(s -> s 61 | .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, DatabaseCommand.databaseURL)) 62 | .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal("google sheet"))) 63 | .withColor(ChatFormatting.BLUE) 64 | .withUnderlined(true) 65 | .withItalic(true))) 66 | .build()); 67 | settings.addEntry(eb.startDropdownMenu(Component.translatable("settings.version"), DropdownMenuBuilder.TopCellElementBuilder.of(config.getVersion(), this::mcVersionFromString)) 68 | .setSelections(getSupportedVersions()) 69 | .setSuggestionMode(false) 70 | .setDefaultValue(config.getVersion()) 71 | .setSaveConsumer(config::setVersion) 72 | .build()); 73 | 74 | settings.addEntry(eb.startTextDescription(Component.literal("==============")).build()); 75 | 76 | settings.addEntry(eb.startTextDescription(Component.translatable("settings.visuals")).build()); 77 | settings.addEntry(eb.startEnumSelector(Component.translatable("settings.outline"), Config.RenderType.class, config.render).setSaveConsumer(val -> config.render = val).build()); 78 | 79 | settings.addEntry(eb.startTextDescription(Component.literal("==============")).build()); 80 | 81 | settings.addEntry(eb.startTextDescription((Component.translatable("settings.finderToggles"))).build()); 82 | for (Finder.Type finder : Finder.Type.values()) { 83 | settings.addEntry(eb.startBooleanToggle(Component.translatable(finder.nameKey), finder.enabled.get()).setSaveConsumer(val -> finder.enabled.set(val)).build()); 84 | } 85 | 86 | settings.addEntry(eb.startTextDescription(Component.literal("==============")).build()); 87 | 88 | settings.addEntry(eb.startBooleanToggle(Component.translatable("settings.antiXrayMode"), config.antiXrayBypass).setSaveConsumer(val -> config.antiXrayBypass = val).build()); 89 | settings.addEntry(eb.startTextDescription(Component.translatable("settings.antiAntiXrayExplained")).build()); 90 | 91 | //=============================INFO======================== 92 | ConfigCategory info = builder.getOrCreateCategory(Component.translatable("info")); 93 | //Clear data 94 | info.addEntry(eb.startBooleanToggle(Component.translatable("info.clearData"), false).setSaveConsumer(val -> { 95 | if (val) { 96 | SeedCracker.get().reset(); 97 | } 98 | }).build()); 99 | //List worldseeds 100 | Set worldSeeds = SeedCracker.get().getDataStorage().getTimeMachine().worldSeeds; 101 | if (!worldSeeds.isEmpty()) { 102 | SubCategoryBuilder world = eb.startSubCategory(Component.translatable("info.worldSeeds")); 103 | for (long worldSeed : worldSeeds) { 104 | world.add(eb.startTextField(Component.literal(""), String.valueOf(worldSeed)).build()); 105 | } 106 | info.addEntry(world.setExpanded(true).build()); 107 | } else { 108 | info.addEntry(eb.startTextDescription(Component.translatable("info.noWorldSeeds")).build()); 109 | } 110 | //List structureseeds 111 | Set structureSeeds = SeedCracker.get().getDataStorage().getTimeMachine().structureSeeds; 112 | if (!structureSeeds.isEmpty()) { 113 | SubCategoryBuilder struc = eb.startSubCategory(Component.translatable("info.structureSeeds")); 114 | for (long structureSeed : structureSeeds) { 115 | struc.add(eb.startTextField(Component.literal(""), String.valueOf(structureSeed)).build()); 116 | } 117 | info.addEntry(struc.setExpanded(true).build()); 118 | } else { 119 | info.addEntry(eb.startTextDescription(Component.translatable("info.noStructureSeeds")).build()); 120 | } 121 | 122 | if (config.debug) { 123 | //List pillarseeds 124 | List pillarSeeds = SeedCracker.get().getDataStorage().getTimeMachine().pillarSeeds; 125 | if (pillarSeeds != null) { 126 | SubCategoryBuilder pillar = eb.startSubCategory(Component.translatable("info.pillarSeeds")); 127 | for (long structureSeed : pillarSeeds) { 128 | pillar.add(eb.startTextField(Component.literal(""), String.valueOf(structureSeed)).build()); 129 | } 130 | info.addEntry(pillar.setExpanded(true).build()); 131 | } else { 132 | info.addEntry(eb.startTextDescription(Component.translatable("info.noPillarSeeds")).build()); 133 | } 134 | //Hashed seed 135 | HashedSeedData hashedSeed = SeedCracker.get().getDataStorage().hashedSeedData; 136 | if (hashedSeed != null) { 137 | info.addEntry(eb.startTextField(Component.translatable("info.hashedSeed"), String.valueOf(hashedSeed.getHashedSeed())).build()); 138 | } else { 139 | info.addEntry(eb.startTextDescription(Component.translatable("info.noHashedSeed")).build()); 140 | } 141 | } 142 | 143 | builder.setSavingRunnable(Config::save); 144 | 145 | return builder.build(); 146 | 147 | } 148 | } 149 | --------------------------------------------------------------------------------