import sys import struct from pprint import pprint from itertools import chain from collections import defaultdict import functools import os import mcregion import vec3 import vertex_buffer import data FAST = "FAST" in os.environ def wrap_n(nc, chunk_c): if nc < 0: nc = 15 chunk_c = chunk_c - 1 if nc > 15: nc = 0 chunk_c = chunk_c + 1 return nc, chunk_c # check vertex_buffer.py for model order custom_blocks = [ { # "tallgrass" model data.BlockID.TALL_GRASS, data.BlockID.MUSHROOM_1, data.BlockID.FLOWER, data.BlockID.ROSE, data.BlockID.SAPLING, }, { # "fence" model data.BlockID.FENCE, }, { # "torch" model data.BlockID.TORCH, }, { # "wheat" model data.BlockID.WHEAT, }, { # "custom-mushroom" model data.BlockID.MUSHROOM_2, }, ] non_solid_blocks = set(chain.from_iterable(custom_blocks)) hack_non_solid_blocks = set([ data.BlockID.LADDER, data.BlockID.WIRE, ]) def neighbor_exists(level_table, chunk_x, chunk_z, nx, ny, nz): if ny > 127 or ny < 0: return False nx, n_chunk_x = wrap_n(nx, chunk_x) nz, n_chunk_z = wrap_n(nz, chunk_z) assert nx <= 15 and nx >= 0 assert nz <= 15 and nz >= 0 key = (n_chunk_x, n_chunk_z) if key not in level_table: return True n_block_index = mcregion.block_index_from_xyz(nx, ny, nz) n_block_id = level_table[key].blocks[n_block_index] has_neighbor = (n_block_id != data.BlockID.AIR) and (n_block_id not in non_solid_blocks) and (n_block_id not in hack_non_solid_blocks) return has_neighbor def block_neighbors(level_table, chunk_x, chunk_z, block_index): block_id = level_table[(chunk_x, chunk_z)].blocks[block_index] if block_id == data.BlockID.AIR or block_id == data.BlockID.BEDROCK: return block_data = level_table[(chunk_x, chunk_z)].data[block_index // 2] block_data = (block_data >> (1 - (block_index % 2)) * 4) & 0xf xyz = mcregion.xyz_from_block_index(block_index) center_position = vec3.add(xyz, (chunk_x * 16, 0, chunk_z * 16)) def find_non_neighbors(): for i, normal in enumerate(vertex_buffer.normals): neighbor = vec3.add(normal, xyz) if not neighbor_exists(level_table, chunk_x, chunk_z, *neighbor): yield i normal_indices = list(find_non_neighbors()) if block_id in non_solid_blocks or block_id in hack_non_solid_blocks or normal_indices: yield center_position, block_id, block_data, normal_indices def devoxelize_region(level_table, level_table_keys): for chunk_x, chunk_z in level_table_keys: for block_index in range(128 * 16 * 16): yield from block_neighbors(level_table, chunk_x, chunk_z, block_index) if FAST: return def build_level_table(level_table, mem, locations): for location in locations: try: level = mcregion.parse_location(mem, location) except CountZeroException: continue x, z = level.x_pos, level.z_pos level_table[(x, z)] = level return level_table def normal_indices_as_block_configuration(normal_indices): acc = 0 for i in normal_indices: acc |= (1 << i) return acc def build_block_configuration_table(): for i in range(64): indices = [] for j in range(6): if ((i >> j) & 1) != 0: indices.extend(vertex_buffer.faces_by_normal[vertex_buffer.normals[j]]) yield indices def pack_instance_data(position, block_id, block_data): packed = struct.pack("= 512: x = -x + 511 if z >= 512: z = -z + 511 assert x < 512 and z < 512 return x, y, z def to_global_index(x,y,z): assert x >= -512 and x < 512, (x, y, z) assert y >= 0 and y < 128, (x, y, z) assert z >= -512 and z < 512, (x, y, z) original_coordinate = (x, y, z) if x < 0: x = -(x - 511) if z < 0: z = -(z - 511) assert z >= 0 and x >= 0 value = x + z * g_stride + y * g_stride * g_stride assert from_global_index(value) == original_coordinate, (original_coordinate, value) return value def dump_blocks(blocks): with open(f"{data_path}.dump", "wb") as f: for block in blocks: center_position, block_id, block_data, normal_indices = block global_index = to_global_index(*center_position) buf = struct.pack("