package anticope.rejects.modules; import anticope.rejects.MeteorRejectsAddon; 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.ChunkDataEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.settings.*; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.utils.player.PlayerUtils; import meteordevelopment.orbit.EventHandler; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.world.ClientWorld; import net.minecraft.registry.RegistryKey; import net.minecraft.util.math.*; import net.minecraft.util.math.random.ChunkRandom; import net.minecraft.world.Heightmap; import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkSection; import net.minecraft.world.chunk.ChunkStatus; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class OreSim extends Module { private final Map>> chunkRenderers = new ConcurrentHashMap<>(); private Seed worldSeed = null; private Map, List> oreConfig; public List 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 = ChunkPos.toLong(x,z); if (chunkRenderers.containsKey(chunkKey)) { Map> chunk = chunkRenderers.get(chunkKey); for (Map.Entry> oreRenders : chunk.entrySet()) { if (oreRenders.getKey().active.get()) { for (Vec3d pos : oreRenders.getValue()) { event.renderer.boxLines(pos.x, pos.y, pos.z, pos.x + 1, pos.y + 1, pos.z + 1, oreRenders.getKey().color, 0); } } } } } @EventHandler private void onTick(TickEvent.Pre event) { if (mc.player == null || mc.world == null || oreConfig == null) return; if (airCheck.get() == AirCheck.RECHECK) { int chunkX = mc.player.getChunkPos().x; int 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 (int offsetX = prevOffset.x; offsetX <= renderdistance; offsetX++) { for (int offsetZ = prevOffset.z; offsetZ <= renderdistance; offsetZ++) { prevOffset = new ChunkPos(offsetX, offsetZ); if (chunkCounter <= 0) { break loop; } long chunkKey = ChunkPos.toLong(chunkX + offsetX, chunkZ + offsetZ); Chunk chunk = world.getChunk(chunkX + offsetX, chunkZ + offsetZ, ChunkStatus.FULL, false); if (chunk != null && chunkRenderers.containsKey(chunkKey)) { chunkRenderers.get(chunkKey).values().forEach(oreSet -> oreSet.removeIf(ore -> { BlockState state = world.getBlockState(new BlockPos((int) ore.x, (int) ore.y, (int) ore.z)); return state.isOpaque() && !state.isOf(Blocks.VOID_AIR); }) ); } chunkCounter--; } prevOffset = new ChunkPos(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 = ChunkPos.toLong(chunkX, chunkZ); if (this.chunkRenderers.containsKey(chunkKey)) { this.chunkRenderers.get(chunkKey).entrySet().stream() .filter(entry -> entry.getKey().active.get()) .flatMap(entry -> entry.getValue().stream()) .map(BlockPos::ofFloored) .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(); } @Override public void onDeactivate() { this.chunkRenderers.clear(); this.oreConfig.clear(); } @EventHandler private void onSeedChanged(SeedChangedEvent event) { reload(); } @EventHandler private void onPlayerRespawn(PlayerRespawnEvent event) { reload(); } private void loadVisibleChunks() { int renderdistance = mc.options.getViewDistance().getValue()+2; 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.getRegistry(PlayerUtils.getDimension()); chunkRenderers.clear(); if (mc.world != null && worldSeed != null) { loadVisibleChunks(); } } @EventHandler public void onChunkData(ChunkDataEvent event) { doMathOnChunk(event.chunk.getPos().x, event.chunk.getPos().z); } private void doMathOnChunk(int chunkX, int chunkZ) { var chunkPos = new ChunkPos(chunkX, chunkZ); long chunkKey = chunkPos.toLong(); ClientWorld world = mc.world; if (chunkRenderers.containsKey(chunkKey) || world == null) { return; } Chunk chunk = world.getChunk(chunkX, chunkZ, ChunkStatus.FULL, false); if (chunk == null) { return; } Set> biomes = new HashSet<>(); ChunkPos.stream(chunkPos, 1).forEach(chunkPosx -> { Chunk chunkxx = world.getChunk(chunkPosx.x, chunkPosx.z, ChunkStatus.BIOMES, false); if (chunkxx == null) return; for(ChunkSection chunkSection : chunkxx.getSectionArray()) { chunkSection.getBiomeContainer().forEachValue(entry -> biomes.add(entry.getKey().get())); } }); Set oreSet = biomes.stream().flatMap(b -> getDefaultOres(b).stream()).collect(Collectors.toSet()); chunkX = chunkX << 4; chunkZ = chunkZ << 4; ChunkRandom random = new ChunkRandom(ChunkRandom.RandomProvider.XOROSHIRO.create(0)); long populationSeed = random.setPopulationSeed(worldSeed.seed, chunkX, chunkZ); HashMap> h = new HashMap<>(); for (Ore ore : oreSet) { HashSet ores = new HashSet<>(); random.setDecoratorSeed(populationSeed, ore.index, ore.step); int repeat = ore.count.get(random); for (int i = 0; i < repeat; i++) { if (ore.rarity != 1F && random.nextFloat() >= ore.rarity) { continue; } int x = random.nextInt(16) + chunkX; int z = random.nextInt(16) + chunkZ; int y = ore.heightProvider.get(random, ore.heightContext); BlockPos origin = new BlockPos(x,y,z); RegistryKey biome = chunk.getBiomeForNoiseGen(x,y,z).getKey().get(); if (!getDefaultOres(biome).contains(ore)) { continue; } if (ore.scattered) { ores.addAll(generateHidden(world, random, origin, ore.size)); } else { ores.addAll(generateNormal(world, random, origin, ore.size, ore.discardOnAirChance)); } } if (!ores.isEmpty()) { h.put(ore, ores); } } chunkRenderers.put(chunkKey, h); } private List getDefaultOres(RegistryKey biomeRegistryKey) { if (oreConfig.containsKey(biomeRegistryKey)) { return oreConfig.get(biomeRegistryKey); } else { return this.oreConfig.values().stream().findAny().get(); } } // ==================================== // 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); } }