package anticope.rejects.modules; import anticope.rejects.MeteorRejectsAddon; import anticope.rejects.events.ChunkPosDataEvent; import anticope.rejects.events.SeedChangedEvent; import anticope.rejects.utils.seeds.Seed; import anticope.rejects.utils.seeds.Seeds; import meteordevelopment.meteorclient.events.render.Render3DEvent; import meteordevelopment.meteorclient.events.world.ChunkDataEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.settings.EnumSetting; import meteordevelopment.meteorclient.settings.IntSetting; import meteordevelopment.meteorclient.settings.Setting; import meteordevelopment.meteorclient.settings.SettingGroup; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.movement.Scaffold; import meteordevelopment.meteorclient.systems.modules.world.Nuker; import meteordevelopment.meteorclient.utils.Utils; import meteordevelopment.orbit.EventHandler; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.BufferRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; 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.registry.Registry; import net.minecraft.world.Heightmap; import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.gen.random.ChunkRandom; import java.util.ArrayList; import java.util.BitSet; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Random; public class OreSim extends Module { private final HashMap>> chunkRenderers = new HashMap<>(); Long worldSeed = null; List oreConfig; private ChunkPos prevOffset = new ChunkPos(0, 0); public enum Version { V1_14, V1_15, V1_16, V1_17_0, V1_17_1, V1_18 } public enum AirCheck { ON_LOAD, RECHECK, OFF } private final SettingGroup sgGeneral = settings.getDefaultGroup(); private final Setting horizontalRadius = sgGeneral.add(new IntSetting.Builder() .name("chunk range") .description("taxi cap distance of chunks being shown") .defaultValue(5) .min(1) .sliderMax(10) .build() ); private final Setting airCheck = sgGeneral.add(new EnumSetting.Builder() .name("Air check mode") .description("checks if there is air at a calculated ore pos") .defaultValue(AirCheck.RECHECK) .build() ); private final Setting version = sgGeneral.add(new EnumSetting.Builder() .name("Air check mode") .description("checks if there is air at a calculated ore pos") .defaultValue(Version.V1_18) .onChanged(v -> versionChanged()) .build() ); public OreSim() { super(MeteorRejectsAddon.CATEGORY, "OreSim", "xray on crack"); oreConfig = Ore.getConfig(version.get()); Ore.oreSettings.forEach(sgGeneral::add); } @EventHandler private void onRender(Render3DEvent event) { if (mc.player == null) { return; } if (Seeds.get().getSeed() != null) { int chunkX = mc.player.getChunkPos().x; int chunkZ = mc.player.getChunkPos().z; int rangeVal = horizontalRadius.get(); for (int range = 0; range <= rangeVal; range++) { for (int x = -range + chunkX; x <= range + chunkX; x++) { renderChunk(x, chunkZ + range - rangeVal, event); } for (int x = (-range) + 1 + chunkX; x < range + chunkX; x++) { renderChunk(x, chunkZ - range + rangeVal + 1, event); } } } } private void renderChunk(int x, int z, Render3DEvent event) { long chunkKey = (long) x + ((long) z << 32); if (chunkRenderers.containsKey(chunkKey)) { for (Ore ore : oreConfig) { if (ore.enabled.get()) { if (!chunkRenderers.get(chunkKey).containsKey(ore)) { continue; } for (Vec3d pos : chunkRenderers.get(chunkKey).get(ore)) { event.renderer.boxLines(pos.x,pos.y,pos.z,pos.x+1,pos.y+1,pos.z+1, ore.color,0); } } } } } @EventHandler public void onTick(TickEvent.Pre event) { if (airCheck.get() == AirCheck.RECHECK) { 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 = MinecraftClient.getInstance().options.viewDistance; //maybe another config option? But its already crowded int chunkCounter = 5; 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 <= 0) { break loop; } long chunkKey = (chunkX + offsetX) + ((chunkZ + offsetZ) << 32); if (chunkRenderers.containsKey(chunkKey)) { chunkRenderers.get(chunkKey).values().forEach(oreSet -> oreSet.removeIf(ore -> !world.getBlockState(new BlockPos((int) ore.x, (int) ore.y, (int) ore.z)).isOpaque())); } chunkCounter--; } prevOffset = new ChunkPos((int) offsetX, -renderdistance); } prevOffset = new ChunkPos(-renderdistance, -renderdistance); } } } @Override public void onActivate() { if (Seeds.get().getSeed() == null) { error("input a world seed into the seed field in the oresim config"); this.toggle(); } reload(); } @EventHandler private void onSeedChanged(SeedChangedEvent event) { reload(); } private void versionChanged() { this.oreConfig = Ore.getConfig(version.get()); reload(); } private void loadVisibleChunks() { int renderdistance = MinecraftClient.getInstance().options.viewDistance; 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++) { doMathOnChunk(i, j); } } } public void reload() { Seed seed = Seeds.get().getSeed(); if (seed == null) return; worldSeed = seed.seed; chunkRenderers.clear(); if (MinecraftClient.getInstance().world != null && worldSeed != null) { loadVisibleChunks(); } } @EventHandler public void onChunkData(ChunkPosDataEvent event) { doMathOnChunk(event.chunkX, event.chunkZ); } public void doMathOnChunk(int chunkX, int chunkZ) { long chunkKey = (long) chunkX + ((long) chunkZ << 32); ClientWorld world = mc.world; if (chunkRenderers.containsKey(chunkKey) || world == null) { return; } if (world.getChunkManager().getChunk(chunkX, chunkZ, ChunkStatus.FULL, false) == null) { return; } chunkX = chunkX << 4; chunkZ = chunkZ << 4; ChunkRandom random = new ChunkRandom(ChunkRandom.RandomProvider.LEGACY.create(0)); if (version.get().ordinal() >= 5) { //1.18 and above random = new ChunkRandom(ChunkRandom.RandomProvider.XOROSHIRO.create(0)); } HashMap> h = new HashMap<>(); long populationSeed = random.setPopulationSeed(worldSeed, chunkX, chunkZ); Identifier id = world.getRegistryManager().get(Registry.BIOME_KEY).getId(world.getBiomeAccess().getBiomeForNoiseGen(new BlockPos(chunkX, 0, chunkZ))); if (id == null) { System.out.println("Something went wrong, you may have some mods that mess with world generation"); this.toggle(); return; } String biomeName = id.getPath(); Identifier dimensionName = world.getDimension().getEffects(); for (Ore ore : oreConfig) { if (dimensionName != ore.dimension) { 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; int y; if (version.get() == Version.V1_14) { y = ore.depthAverage ? random.nextInt(ore.maxY) + random.nextInt(ore.maxY) - ore.maxY : random.nextInt(ore.maxY - ore.minY); z = random.nextInt(16) + chunkZ; } else { z = random.nextInt(16) + chunkZ; 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 EMERALD -> { if (airCheck.get() == AirCheck.OFF || world.getBlockState(new BlockPos(x, y, z)).isOpaque()) { ores.add(new Vec3d(x, y, z)); } } case NO_SURFACE -> ores.addAll(generateHidden(world, random, new BlockPos(x, y, z), ore.size)); default -> System.out.println(ore.type + " has some unknown generator. Fix it!"); } } if (!ores.isEmpty()) { h.put(ore, ores); } } chunkRenderers.put(chunkKey, h); } // ==================================== // Mojang code // ==================================== private ArrayList generateNormal(ClientWorld world, Random 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, Random 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 && (airCheck.get() == AirCheck.OFF || 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, Random 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, Random 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 (airCheck.get() == AirCheck.OFF || 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(Random random, int size) { return Math.round((random.nextFloat() - random.nextFloat()) * (float) size); } }