Created
October 18, 2025 15:21
-
-
Save fipso/62816ad38be54e500d7a6d76c88a0d7b to your computer and use it in GitHub Desktop.
A python script to find blocks in minecraft world saves. Specialized to find suspicious clay in atm10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import amulet | |
| from amulet.api.block import Block | |
| from amulet.api.chunk.biomes import BiomesShape | |
| import numpy as np | |
| import logging | |
| import gc | |
| # Suppress PyMCTranslate warnings about modded blocks | |
| logging.getLogger("amulet").setLevel(logging.ERROR) | |
| logging.getLogger("PyMCTranslate").setLevel(logging.ERROR) | |
| def get_chunk_biomes(chunk): | |
| """ | |
| Get all unique biomes in a chunk. | |
| Args: | |
| chunk: The chunk to check | |
| Returns: | |
| set: Set of biome names found in the chunk | |
| """ | |
| try: | |
| biomes = chunk.biomes | |
| biome_palette = chunk.biome_palette | |
| unique_biome_indices = set() | |
| # Get unique biome indices based on format | |
| if biomes.dimension == BiomesShape.Shape2D: | |
| # 2D biome array (16x16) | |
| unique_biome_indices = set(np.unique(biomes._2d)) | |
| elif biomes.dimension == BiomesShape.Shape3D: | |
| # 3D biome array (4x4x4 sub-chunks) | |
| for cy in biomes._3d.sections: | |
| sub_chunk = biomes._3d.get_section(cy) | |
| unique_biome_indices.update(np.unique(sub_chunk)) | |
| # Convert indices to biome names | |
| biome_names = {biome_palette[int(idx)] for idx in unique_biome_indices} | |
| return biome_names | |
| except Exception as e: | |
| return set() | |
| def chunk_has_biome(chunk, biome_name): | |
| """ | |
| Check if a chunk contains a specific biome. | |
| Args: | |
| chunk: The chunk to check | |
| biome_name: The biome identifier (e.g., "minecraft:deep_dark") | |
| Returns: | |
| bool: True if the chunk contains the biome, False otherwise | |
| """ | |
| biomes = get_chunk_biomes(chunk) | |
| return biome_name in biomes | |
| def find_block_locations(world_path, block_id, namespace="allthemodium", filter_biome=None): | |
| """ | |
| Find all locations of a specific block in a Minecraft world. | |
| Args: | |
| world_path: Path to the Minecraft world folder | |
| block_id: Block ID (e.g., "suspicious_clay") | |
| namespace: Block namespace (default: "allthemodium") | |
| filter_biome: Optional biome filter (e.g., "minecraft:deep_dark" for ancient cities) | |
| Returns: | |
| List of tuples containing (x, y, z) coordinates | |
| """ | |
| print(f"Loading world from: {world_path}") | |
| level = amulet.load_level(world_path) | |
| # Create the block we're searching for | |
| target_block = Block(namespace, block_id) | |
| locations = [] | |
| chunks_skipped = 0 | |
| deep_dark_chunks = 0 | |
| deep_dark_block_counts = {} # Track all blocks found in deep_dark chunks | |
| try: | |
| # Get all chunk coordinates in the world | |
| print("Scanning chunks...") | |
| if filter_biome: | |
| print(f"Filtering chunks by biome: {filter_biome}") | |
| chunk_count = 0 | |
| for dimension in level.dimensions: | |
| print(f"\nScanning dimension: {dimension}") | |
| for cx, cz in level.all_chunk_coords(dimension): | |
| chunk_count += 1 | |
| if chunk_count % 100 == 0: | |
| print(f"\nProcessed {chunk_count} chunks, skipped {chunks_skipped}, deep_dark chunks: {deep_dark_chunks}, found {len(locations)} blocks so far...") | |
| # Print block counts from deep_dark chunks | |
| if deep_dark_block_counts: | |
| print("\nBlock counts in deep_dark chunks:") | |
| # Sort by count (descending) and show all blocks | |
| sorted_blocks = sorted(deep_dark_block_counts.items(), key=lambda x: x[1], reverse=True) | |
| for block_name, count in sorted_blocks: | |
| print(f" {block_name}: {count:,}") | |
| print(f"\nTotal unique block types: {len(sorted_blocks)}") | |
| print(f"Total blocks counted: {sum(deep_dark_block_counts.values()):,}") | |
| # Force garbage collection every 100 chunks to free memory | |
| gc.collect() | |
| try: | |
| # Get the chunk | |
| chunk = level.get_chunk(cx, cz, dimension) | |
| # Check if chunk has deep_dark biome (ancient cities) | |
| chunk_biomes = get_chunk_biomes(chunk) | |
| is_deep_dark = "universal_minecraft:deep_dark" in chunk_biomes | |
| if is_deep_dark: | |
| deep_dark_chunks += 1 | |
| # Filter by biome if specified | |
| if filter_biome and filter_biome not in chunk_biomes: | |
| chunks_skipped += 1 | |
| # Clean up references | |
| del chunk_biomes | |
| del chunk | |
| continue | |
| # Track unique non-minecraft blocks in this chunk | |
| non_minecraft_blocks = set() | |
| # Iterate through each sub-chunk (16-block tall sections) | |
| for cy in chunk.blocks.sub_chunks: | |
| # Calculate the y range for this sub-chunk | |
| min_y = cy * 16 | |
| max_y = (cy + 1) * 16 | |
| # Search through the sub-chunk | |
| for x in range(16): | |
| for z in range(16): | |
| for y in range(min_y, max_y): | |
| # Get block at this position | |
| block = chunk.get_block(x, y, z) | |
| block_name = block.namespaced_name | |
| # Count blocks in deep_dark chunks | |
| if is_deep_dark: | |
| if block_name not in deep_dark_block_counts: | |
| deep_dark_block_counts[block_name] = 0 | |
| deep_dark_block_counts[block_name] += 1 | |
| # Log non-minecraft blocks | |
| if not block_name.startswith("universal_minecraft:"): | |
| non_minecraft_blocks.add(block_name) | |
| # Check if it matches our target | |
| if block_name == f"{namespace}:{block_id}": | |
| # Convert chunk-relative coords to world coords | |
| world_x = cx * 16 + x | |
| world_z = cz * 16 + z | |
| locations.append((world_x, y, world_z)) | |
| # Clean up references to free memory | |
| del non_minecraft_blocks | |
| del chunk_biomes | |
| del chunk | |
| except Exception as e: | |
| # Skip chunks that can't be loaded | |
| print(e) | |
| continue | |
| print(f"\n\nScan complete! Processed {chunk_count} chunks.") | |
| print(f"Chunks with deep_dark biome (ancient cities): {deep_dark_chunks}") | |
| if filter_biome: | |
| print(f"Skipped {chunks_skipped} chunks (not matching biome: {filter_biome})") | |
| print(f"Found {len(locations)} blocks of {namespace}:{block_id}") | |
| # Print final block counts from deep_dark chunks | |
| if deep_dark_block_counts: | |
| print("\n" + "=" * 70) | |
| print("FINAL BLOCK COUNTS IN DEEP_DARK CHUNKS:") | |
| print("=" * 70) | |
| sorted_blocks = sorted(deep_dark_block_counts.items(), key=lambda x: x[1], reverse=True) | |
| for block_name, count in sorted_blocks: | |
| print(f" {block_name}: {count:,}") | |
| print(f"\nTotal unique block types: {len(sorted_blocks)}") | |
| print(f"Total blocks counted: {sum(deep_dark_block_counts.values()):,}") | |
| finally: | |
| level.close() | |
| return locations | |
| if __name__ == "__main__": | |
| # CONFIGURE THESE VALUES | |
| WORLD_PATH = "world/" # Change this to your world path | |
| BLOCK_NAME = "suspicious_clay" | |
| NAMESPACE = "allthemodium" | |
| # Set to "universal_minecraft:deep_dark" to only search ancient city chunks, or None to search all chunks | |
| BIOME_FILTER = "universal_minecraft:deep_dark" | |
| print(f"Searching for {NAMESPACE}:{BLOCK_NAME}") | |
| print("=" * 50) | |
| # Find all locations | |
| locations = find_block_locations(WORLD_PATH, BLOCK_NAME, NAMESPACE, filter_biome=BIOME_FILTER) | |
| # Display results | |
| if locations: | |
| print("\nBlock locations (X, Y, Z):") | |
| print("-" * 50) | |
| for x, y, z in sorted(locations): | |
| print(f"X: {x:6d}, Y: {y:4d}, Z: {z:6d}") | |
| # Save to file | |
| output_file = f"{NAMESPACE}_{BLOCK_NAME}_locations.txt" | |
| with open(output_file, 'w') as f: | |
| f.write(f"Locations of {NAMESPACE}:{BLOCK_NAME}\n") | |
| f.write("=" * 50 + "\n\n") | |
| for x, y, z in sorted(locations): | |
| f.write(f"X: {x:6d}, Y: {y:4d}, Z: {z:6d}\n") | |
| print(f"\nResults saved to: {output_file}") | |
| else: | |
| print("\nNo blocks found!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment