package anticope.rejects.modules; import anticope.rejects.MeteorRejectsAddon; import anticope.rejects.events.ChunkPosDataEvent; import anticope.rejects.events.PlayerRespawnEvent; import anticope.rejects.events.SeedChangedEvent; import anticope.rejects.utils.Ore; import anticope.rejects.utils.seeds.Seed; import anticope.rejects.utils.seeds.Seeds; import baritone.api.BaritoneAPI; import meteordevelopment.meteorclient.events.render.Render3DEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.settings.BoolSetting; 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.orbit.EventHandler; 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.math.random.ChunkRandom; import net.minecraft.util.registry.Registry; import net.minecraft.world.Heightmap; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkStatus; //import net.minecraft.world.chunk.world.random.ChunkRandom; import com.seedfinding.mccore.version.MCVersion; import java.util.ArrayList; import java.util.BitSet; 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<>(); private Seed worldSeed = null; private List oreConfig; public ArrayList oreGoals = new ArrayList<>(); private ChunkPos prevOffset = new ChunkPos(0, 0); public enum AirCheck { ON_LOAD, RECHECK, OFF } private final SettingGroup sgGeneral = settings.getDefaultGroup(); private final SettingGroup sgOres = settings.createGroup("Ores"); 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 baritone = sgGeneral.add(new BoolSetting.Builder() .name("baritone") .description("Set baritone ore positions to the simulated ones.") .defaultValue(false) .build() ); public OreSim() { super(MeteorRejectsAddon.CATEGORY, "ore-sim", "Xray on crack."); Ore.oreSettings.forEach(sgOres::add); } public boolean baritone() { return isActive() && baritone.get(); } @EventHandler private void onRender(Render3DEvent event) { if (mc.player == null || oreConfig == 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 private void onTick(TickEvent.Pre event) { if (mc.player == null || mc.world == null || oreConfig == null) return; if (airCheck.get() == AirCheck.RECHECK) { long chunkX = mc.player.getChunkPos().x; long chunkZ = mc.player.getChunkPos().z; ClientWorld world = mc.world; int renderdistance = mc.options.getViewDistance().getValue(); //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); } } if (baritone.get() && BaritoneAPI.getProvider().getPrimaryBaritone().getMineProcess().isActive()) { oreGoals.clear(); var chunkPos = mc.player.getChunkPos(); int rangeVal = 4; for(int range = 0; range <= rangeVal; ++range) { for(int x = -range + chunkPos.x; x <= range + chunkPos.x; ++x) { oreGoals.addAll(addToBaritone(x, chunkPos.z + range - rangeVal)); } for(int x = -range + 1 + chunkPos.x; x < range + chunkPos.x; ++x) { oreGoals.addAll(this.addToBaritone(x, chunkPos.z - range + rangeVal + 1)); } } } } private ArrayList addToBaritone(int chunkX, int chunkZ) { ArrayList baritoneGoals = new ArrayList<>(); long chunkKey = (long)chunkX + ((long)chunkZ << 32); if (!this.chunkRenderers.containsKey(chunkKey)) { return baritoneGoals; } else { this.oreConfig.stream().filter((config) -> { return (Boolean)config.enabled.get(); }).forEach((ore) -> { chunkRenderers .get(chunkKey) .getOrDefault(ore, new HashSet<>()) .stream() .map((vec3d) -> new BlockPos(vec3d)) .forEach(baritoneGoals::add); }); return baritoneGoals; } } @Override public void onActivate() { if (Seeds.get().getSeed() == null) { error("No seed found. To set a seed do .seed "); this.toggle(); } reload(); } @EventHandler private void onSeedChanged(SeedChangedEvent event) { reload(); } @EventHandler private void onPlayerRespawn(PlayerRespawnEvent event) { reload(); } private void loadVisibleChunks() { int renderdistance = mc.options.getViewDistance().getValue(); 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); } } } private void reload() { Seed seed = Seeds.get().getSeed(); if (seed == null) return; worldSeed = seed; oreConfig = Ore.getConfig(Seeds.get().getSeed().version); if (oreConfig == null) { error("Ore Sim only works with seeds from version 1.14 or higher. (Current seed is from version " + Seeds.get().getSeed().version.toString() + ")"); this.toggle(); return; } chunkRenderers.clear(); if (mc.world != null && worldSeed != null) { loadVisibleChunks(); } } @EventHandler public void onChunkData(ChunkPosDataEvent event) { doMathOnChunk(event.chunkX, event.chunkZ); } private 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 (worldSeed.version.isNewerOrEqualTo(MCVersion.v1_18)) { //1.18 and above random = new ChunkRandom(ChunkRandom.RandomProvider.XOROSHIRO.create(0)); } HashMap> h = new HashMap<>(); long populationSeed = random.setPopulationSeed(worldSeed.seed, chunkX, chunkZ); var optional = world.getBiomeAccess().getBiomeForNoiseGen(new BlockPos(chunkX, 0, chunkZ)).getKeyOrValue(); Identifier id = (optional.right().isPresent()) ? world.getRegistryManager().get(Registry.BIOME_KEY).getId(optional.right().get()) : optional.left().get().getValue(); if (id == null) { error("Something went wrong, you may have some mods that mess with world generation"); toggle(); return; } String biomeName = id.getPath(); Identifier dimensionName = world.getDimension().effects(); for (Ore ore : oreConfig) { if (!dimensionName.getPath().equals(ore.dimension.getPath())) { 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 (worldSeed.version.isBetween(MCVersion.v1_14, MCVersion.v1_14_4)) { 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, 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 && (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, 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 (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(ChunkRandom random, int size) { return Math.round((random.nextFloat() - random.nextFloat()) * (float) size); } }