package net.wurstclient.hacks; import java.awt.Color; import java.util.ArrayList; import java.util.BitSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import org.lwjgl.opengl.GL11; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; import net.minecraft.registry.RegistryKeys; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import net.minecraft.util.math.random.ChunkRandom; import net.minecraft.world.Heightmap; import net.minecraft.world.chunk.ChunkStatus; import net.wurstclient.Category; import net.wurstclient.events.PacketInputListener; import net.wurstclient.events.RenderListener; import net.wurstclient.events.UpdateListener; import net.wurstclient.hack.Hack; import net.wurstclient.hacks.seedray.Ore; import net.wurstclient.settings.CheckboxSetting; import net.wurstclient.settings.SliderSetting; import net.wurstclient.settings.SliderSetting.ValueDisplay; import net.wurstclient.settings.TextFieldSetting; import net.wurstclient.util.ChatUtils; import net.wurstclient.util.OverlayRenderer; import net.wurstclient.util.RegionPos; import net.wurstclient.util.RenderUtils; public class SeedRayHack extends Hack implements UpdateListener, RenderListener { private final HashMap>> chunkRenderers = new HashMap<>(); public Long worldSeed = null; public List oreConfig; private ChunkPos prevOffset = new ChunkPos(0, 0); private final OverlayRenderer renderer = new OverlayRenderer(); private final TextFieldSetting Seed = new TextFieldSetting("world seed", ""); private final SliderSetting range = new SliderSetting("Range", "Chunks to simulate", 5, 1, 10, 1, ValueDisplay.INTEGER.withSuffix(" chunks")); public final CheckboxSetting debug = new CheckboxSetting("debug setting", "print all positions of ores", false); public final CheckboxSetting Coal = new CheckboxSetting("Coal", "show coal ore", true); public final CheckboxSetting Iron = new CheckboxSetting("Iron", "show iron ore", true); public final CheckboxSetting Gold = new CheckboxSetting("Gold", "show Gold ore", true); public final CheckboxSetting Redstone = new CheckboxSetting("Redstone", "show Redstone ore", true); public final CheckboxSetting Diamond = new CheckboxSetting("Diamond", "show Diamond ore", true); public final CheckboxSetting Lapis = new CheckboxSetting("Lapis", "show Lapis ore", true); public final CheckboxSetting Emerald = new CheckboxSetting("Emerald", "show Emerald ore", true); public final CheckboxSetting Copper = new CheckboxSetting("Copper", "show Copper ore", true); public final CheckboxSetting Quartz = new CheckboxSetting("Quartz", "show Quartz ore", true); public final CheckboxSetting Debris = new CheckboxSetting("Debris", "show Debris", true); public SeedRayHack() { super("Seed-Ray"); setCategory(Category.RENDER); addSetting(range); addSetting(Seed); addSetting(debug); addSetting(Coal); addSetting(Iron); addSetting(Gold); addSetting(Redstone); addSetting(Diamond); addSetting(Lapis); addSetting(Emerald); addSetting(Copper); addSetting(Quartz); addSetting(Debris); // super("SeedRay", "Attempts to simulate ore positions given a seed, use ,seedray to set seed", KEY_UNBOUND, Category.RENDER, // new CheckboxSetting("Coal", false), // 0 // new CheckboxSetting("Iron", false), // 1 // new CheckboxSetting("Gold", false), // 2 // new CheckboxSetting("Redstone", false), // 3 // new CheckboxSetting("Diamond", false), // 4 // new CheckboxSetting("Lapis", false), // 5 // new CheckboxSetting("Emerald", false), // 6 // new CheckboxSetting("Copper", false), // 7 // new CheckboxSetting("Quartz", false), // 8 // new CheckboxSetting("Debris", false), // 9 // new SliderSetting("Range", 1, 10, 5, 0).withDesc("Chunks to simulate")); EVENTS.add(UpdateListener.class, this); EVENTS.add(RenderListener.class, this); } @Override protected void onDisable() { EVENTS.remove(UpdateListener.class, this); EVENTS.remove(RenderListener.class, this); } @Override public void onRender(MatrixStack matrixStack, float partialTicks) { if (worldSeed != null) { // int chunkX = MC.player.getChunkPos().x; // int chunkZ = MC.player.getChunkPos().z; // GL settings GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glEnable(GL11.GL_CULL_FACE); GL11.glDisable(GL11.GL_DEPTH_TEST); matrixStack.push(); RegionPos region = RenderUtils.getCameraRegion(); RenderUtils.applyRegionalRenderOffset(matrixStack, region); int rangeVal = range.getValueI(); // for (int range = 0; range <= rangeVal; range++) { // for (int x = -range + chunkX; x <= range + chunkX; x++) { // renderChunk(x, chunkZ + range - rangeVal, matrixStack); // } // for (int x = (-range) + 1 + chunkX; x < range + chunkX; x++) { // renderChunk(x, chunkZ - range + rangeVal + 1, matrixStack); // } // } Vec3d p = MC.player.getPos(); for (long k : chunkRenderers.keySet()) { HashMap> e = chunkRenderers.get(k); for (Ore ko : e.keySet()) { HashSet ee = e.get(ko); for (Vec3d pos : ee) { // ChatUtils.message("CR: " + v.toString()); if (distance(p.x, p.y, p.z, pos.x, pos.y, pos.z, rangeVal * 15)) { if (debug.isChecked()) { ChatUtils.message("RENDER: " + pos.toString()); } Box box = new Box(new BlockPos(new Vec3i((int) pos.x, (int) pos.y, (int) pos.z))); Color color = ko.color; matrixStack.push(); matrixStack.translate(pos.x, pos.y, pos.z); //RenderSystem.setShader(GameRenderer::getPositionProgram); RenderSystem.setShaderColor(color.getRed() / 255, color.getGreen() / 255, color.getBlue() / 255, 0.5F); RenderUtils.drawSolidBox(box, matrixStack); matrixStack.pop(); } } } } matrixStack.pop(); // GL resets RenderSystem.setShaderColor(1, 1, 1, 1); GL11.glEnable(GL11.GL_DEPTH_TEST); GL11.glDisable(GL11.GL_BLEND); } } private boolean distance(double xa, double ya, double za, double xb, double yb, double zb, double r) { int x = (int) (xa - xb); int y = (int) (ya - yb); int z = (int) (za - zb); return Math.sqrt(x * x + y * y + z * z) < r; } private void renderChunk(int x, int z, MatrixStack ms) { long chunkKey = (long) x + ((long) z << 32); if (chunkRenderers.containsKey(chunkKey)) { for (Ore ore : oreConfig) { if (ore.enabled) { if (!chunkRenderers.get(chunkKey).containsKey(ore)) { continue; } for (Vec3d pos : chunkRenderers.get(chunkKey).get(ore)) { if (debug.isChecked()) { ChatUtils.message(pos.toString()); } Box box = new Box(new BlockPos(new Vec3i((int) pos.x, (int) pos.y, (int) pos.z))); Color color = ore.color; RenderSystem.setShaderColor(color.getRed(), color.getGreen(), color.getBlue(), 1); RenderUtils.drawOutlinedBox(box, ms); // RenderUtils.drawBoxOutline(box, QuadColor.single(color.getRed(), // color.getGreen(), color.getBlue(), color.getAlpha()), 1); } } } } } @Override public void onUpdate() { if (MC.player == null || MC.world == null) { return; } long chunkX = MC.player.getChunkPos().x; long chunkZ = MC.player.getChunkPos().z; ClientWorld world = MC.world; int renderdistance = MC.options.getViewDistance().getValue(); // int chunkCounter = 0; // loop: while (true) { for (long offsetX = prevOffset.x; offsetX <= renderdistance; offsetX++) { for (long offsetZ = prevOffset.z; offsetZ <= renderdistance; offsetZ++) { prevOffset = new ChunkPos((int) offsetX, (int) offsetZ); // if (chunkCounter >= 5) { // break loop; // } long chunkKey = (chunkX + offsetX) + ((chunkZ + offsetZ) << 32); // long chunkKey = (long) chunkX + ((long) chunkZ << 32); // if (chunkRenderers.containsKey(chunkKey)) { // if (debug.isChecked()) { // ChatUtils.message("chunkRenderers.containsKey(chunkKey) is TRUE"); // } try { chunkRenderers.get(chunkKey).values().forEach(oreSet -> oreSet.removeIf(ore -> !world .getBlockState(new BlockPos((int) ore.x, (int) ore.y, (int) ore.z)).isOpaque())); } catch (Exception e) { } // chunkCounter++; } prevOffset = new ChunkPos((int) offsetX, -renderdistance); } prevOffset = new ChunkPos(-renderdistance, -renderdistance); // } } @Override public void onEnable() { super.onEnable(); if (worldSeed == null) { try { worldSeed = Long.parseLong(Seed.getValue()); } catch (Exception e) { ChatUtils.warning("Please input the world seed"); this.setEnabled(false); return; } } oreConfig = Ore.getConfig(); reload(); if (debug.isChecked()) { ChatUtils.message("CR: " + chunkRenderers.size()); // for (long k : chunkRenderers.keySet()) { // HashMap> e = chunkRenderers.get(k); // for (Ore ko : e.keySet()) { // HashSet ee = e.get(ko); // for (Vec3d v : ee) { // ChatUtils.message("CR: " + v.toString()); // } // } // } } } public void reload() { chunkRenderers.clear(); if (MinecraftClient.getInstance().world != null) { loadVisibleChunks(); } } private void loadVisibleChunks() { int renderdistance = MinecraftClient.getInstance().options.getViewDistance().getValue(); if (debug.isChecked()) { ChatUtils.message("rd: " + renderdistance); } if (MC.player == null) { return; } int playerChunkX = MC.player.getChunkPos().x; int playerChunkZ = MC.player.getChunkPos().z; for (int i = playerChunkX - renderdistance; i < playerChunkX + renderdistance; i++) { for (int j = playerChunkZ - renderdistance; j < playerChunkZ + renderdistance; j++) { if (debug.isChecked()) { ChatUtils.message("doMathOnChunk(" + i + ", " + j + ");"); } doMathOnChunk(i, j); } } } public void doMathOnChunk(int chunkX, int chunkZ) { if (worldSeed == null || !this.isEnabled()) { this.setEnabled(false); return; } long chunkKey = (long) chunkX + ((long) chunkZ << 32); ClientWorld world = MC.world; if (chunkRenderers.containsKey(chunkKey) || world == null) { if (debug.isChecked()) { ChatUtils.message("earlyreturn: chunkRenderers.containsKey(chunkKey) || world == null"); } return; } if (world.getChunkManager().getChunk(chunkX, chunkZ, ChunkStatus.FULL, false) == null) { if (debug.isChecked()) { ChatUtils.message( "earlyreturn: world.getChunkManager().getChunk(chunkX, chunkZ, ChunkStatus.FULL, false) == null"); } return; } chunkX = chunkX << 4; chunkZ = chunkZ << 4; ChunkRandom random = new ChunkRandom(ChunkRandom.RandomProvider.XOROSHIRO.create(0)); HashMap> h = new HashMap<>(); long populationSeed = random.setPopulationSeed(worldSeed, chunkX, chunkZ); Identifier id = world.getRegistryManager().get(RegistryKeys.BIOME) .getId(world.getBiomeAccess().getBiomeForNoiseGen(new BlockPos(chunkX, 0, chunkZ)).value()); if (id == null) { MC.inGameHud.getChatHud().addMessage( Text.literal("Unable to calculate ore positions, there may be mods affecting world generation")); this.setEnabled(false); return; } String biomeName = id.getPath(); String dimensionName = world.getDimension().infiniburn().id().getPath(); for (Ore ore : oreConfig) { if (!dimensionName.endsWith(ore.dimension)) { if (debug.isChecked()) { ChatUtils.message("!dimensionName.endsWith(ore.dimension): " + dimensionName); } continue; } HashSet ores = new HashSet<>(); int index; if (ore.index.containsKey(biomeName)) { index = ore.index.get(biomeName); } else { index = ore.index.get("default"); } if (index < 0) { continue; } random.setDecoratorSeed(populationSeed, index, ore.step); int repeat = ore.count.get(random); for (int i = 0; i < repeat; i++) { if (ore.chance != 1F && random.nextFloat() >= ore.chance) { continue; } int x = random.nextInt(16) + chunkX; int z = random.nextInt(16) + chunkZ; int y = ore.depthAverage ? random.nextInt(ore.maxY) + random.nextInt(ore.maxY) - ore.maxY : random.nextInt(ore.maxY - ore.minY); y += ore.minY; switch (ore.generator) { case DEFAULT -> ores.addAll(generateNormal(world, random, new BlockPos(x, y, z), ore.size, ore.discardOnAir)); case NO_SURFACE -> ores.addAll(generateHidden(world, random, new BlockPos(x, y, z), ore.size)); default -> System.out.println("Fatal Error"); } } if (debug.isChecked()) { ChatUtils.message("oremap len:" + ores.size()); } if (!ores.isEmpty()) { h.put(ore, ores); } } chunkRenderers.put(chunkKey, h); } // ==================================== // Mojang code // ==================================== private ArrayList generateNormal(ClientWorld world, ChunkRandom random, BlockPos blockPos, int veinSize, float discardOnAir) { float f = random.nextFloat() * 3.1415927F; float g = (float) veinSize / 8.0F; int i = MathHelper.ceil(((float) veinSize / 16.0F * 2.0F + 1.0F) / 2.0F); double d = (double) blockPos.getX() + Math.sin(f) * (double) g; double e = (double) blockPos.getX() - Math.sin(f) * (double) g; double h = (double) blockPos.getZ() + Math.cos(f) * (double) g; double j = (double) blockPos.getZ() - Math.cos(f) * (double) g; double l = (blockPos.getY() + random.nextInt(3) - 2); double m = (blockPos.getY() + random.nextInt(3) - 2); int n = blockPos.getX() - MathHelper.ceil(g) - i; int o = blockPos.getY() - 2 - i; int p = blockPos.getZ() - MathHelper.ceil(g) - i; int q = 2 * (MathHelper.ceil(g) + i); int r = 2 * (2 + i); for (int s = n; s <= n + q; ++s) { for (int t = p; t <= p + q; ++t) { if (o <= world.getTopY(Heightmap.Type.MOTION_BLOCKING, s, t)) { return this.generateVeinPart(world, random, veinSize, d, e, h, j, l, m, n, o, p, q, r, discardOnAir); } } } return new ArrayList<>(); } private ArrayList generateVeinPart(ClientWorld world, ChunkRandom random, int veinSize, double startX, double endX, double startZ, double endZ, double startY, double endY, int x, int y, int z, int size, int i, float discardOnAir) { BitSet bitSet = new BitSet(size * i * size); BlockPos.Mutable mutable = new BlockPos.Mutable(); double[] ds = new double[veinSize * 4]; ArrayList poses = new ArrayList<>(); int n; double p; double q; double r; double s; for (n = 0; n < veinSize; ++n) { float f = (float) n / (float) veinSize; p = MathHelper.lerp(f, startX, endX); q = MathHelper.lerp(f, startY, endY); r = MathHelper.lerp(f, startZ, endZ); s = random.nextDouble() * (double) veinSize / 16.0D; double m = ((double) (MathHelper.sin(3.1415927F * f) + 1.0F) * s + 1.0D) / 2.0D; ds[n * 4] = p; ds[n * 4 + 1] = q; ds[n * 4 + 2] = r; ds[n * 4 + 3] = m; } for (n = 0; n < veinSize - 1; ++n) { if (!(ds[n * 4 + 3] <= 0.0D)) { for (int o = n + 1; o < veinSize; ++o) { if (!(ds[o * 4 + 3] <= 0.0D)) { p = ds[n * 4] - ds[o * 4]; q = ds[n * 4 + 1] - ds[o * 4 + 1]; r = ds[n * 4 + 2] - ds[o * 4 + 2]; s = ds[n * 4 + 3] - ds[o * 4 + 3]; if (s * s > p * p + q * q + r * r) { if (s > 0.0D) { ds[o * 4 + 3] = -1.0D; } else { ds[n * 4 + 3] = -1.0D; } } } } } } for (n = 0; n < veinSize; ++n) { double u = ds[n * 4 + 3]; if (!(u < 0.0D)) { double v = ds[n * 4]; double w = ds[n * 4 + 1]; double aa = ds[n * 4 + 2]; int ab = Math.max(MathHelper.floor(v - u), x); int ac = Math.max(MathHelper.floor(w - u), y); int ad = Math.max(MathHelper.floor(aa - u), z); int ae = Math.max(MathHelper.floor(v + u), ab); int af = Math.max(MathHelper.floor(w + u), ac); int ag = Math.max(MathHelper.floor(aa + u), ad); for (int ah = ab; ah <= ae; ++ah) { double ai = ((double) ah + 0.5D - v) / u; if (ai * ai < 1.0D) { for (int aj = ac; aj <= af; ++aj) { double ak = ((double) aj + 0.5D - w) / u; if (ai * ai + ak * ak < 1.0D) { for (int al = ad; al <= ag; ++al) { double am = ((double) al + 0.5D - aa) / u; if (ai * ai + ak * ak + am * am < 1.0D) { int an = ah - x + (aj - y) * size + (al - z) * size * i; if (!bitSet.get(an)) { bitSet.set(an); mutable.set(ah, aj, al); if (aj >= -64 && aj < 320 && (world.getBlockState(mutable).isOpaque())) { if (shouldPlace(world, mutable, discardOnAir, random)) { poses.add(new Vec3d(ah, aj, al)); } } } } } } } } } } } return poses; } private boolean shouldPlace(ClientWorld world, BlockPos orePos, float discardOnAir, ChunkRandom random) { if (discardOnAir == 0F || (discardOnAir != 1F && random.nextFloat() >= discardOnAir)) { return true; } for (Direction direction : Direction.values()) { if (!world.getBlockState(orePos.add(direction.getVector())).isOpaque() && discardOnAir != 1F) { return false; } } return true; } private ArrayList generateHidden(ClientWorld world, ChunkRandom random, BlockPos blockPos, int size) { ArrayList poses = new ArrayList<>(); int i = random.nextInt(size + 1); for (int j = 0; j < i; ++j) { size = Math.min(j, 7); int x = this.randomCoord(random, size) + blockPos.getX(); int y = this.randomCoord(random, size) + blockPos.getY(); int z = this.randomCoord(random, size) + blockPos.getZ(); if (world.getBlockState(new BlockPos(x, y, z)).isOpaque()) { if (shouldPlace(world, new BlockPos(x, y, z), 1F, random)) { poses.add(new Vec3d(x, y, z)); } } } return poses; } private int randomCoord(ChunkRandom random, int size) { return Math.round((random.nextFloat() - random.nextFloat()) * (float) size); } }