124 lines
3.5 KiB
Python
124 lines
3.5 KiB
Python
import sys
|
|
import struct
|
|
from pprint import pprint
|
|
from itertools import chain
|
|
|
|
import mcregion
|
|
import vec3
|
|
import vertex_buffer
|
|
|
|
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
|
|
|
|
normals = [
|
|
(-1.0, 0.0, 0.0),
|
|
(0.0, -1.0, 0.0),
|
|
(0.0, 0.0, -1.0),
|
|
(0.0, 0.0, 1.0),
|
|
(0.0, 1.0, 0.0),
|
|
(1.0, 0.0, 0.0),
|
|
]
|
|
|
|
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 == 0:
|
|
return
|
|
|
|
def neighbor_exists(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)
|
|
if nx > 15 or nx < 0:
|
|
return True
|
|
if nz > 15 or nz < 0:
|
|
return True
|
|
n_block_index = mcregion.block_index_from_xyz(nx, ny, nz)
|
|
key = (n_chunk_x, n_chunk_z)
|
|
if key not in level_table:
|
|
return True
|
|
n_block_id = level_table[key].blocks[n_block_index]
|
|
return n_block_id != 0
|
|
|
|
x, y, z = mcregion.xyz_from_block_index(block_index)
|
|
|
|
center_position = vec3.add((x, y, z), (chunk_x * 16, 0, chunk_z * 16))
|
|
|
|
def find_non_neighbors():
|
|
for i, normal in enumerate(normals):
|
|
neighbor = vec3.add(normal, (x, y, z))
|
|
if not neighbor_exists(*neighbor):
|
|
yield i
|
|
|
|
normal_indices = list(find_non_neighbors())
|
|
if normal_indices:
|
|
yield center_position, block_id, normal_indices
|
|
|
|
def devoxelize_region(level_table):
|
|
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)
|
|
|
|
def build_level_table(mem, locations):
|
|
level_table = {}
|
|
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[normals[j]])
|
|
yield indices
|
|
|
|
def build_block_instances(f, blocks):
|
|
for position, block_id, normal_indices in blocks:
|
|
block_configuration = normal_indices_as_block_configuration(normal_indices)
|
|
#print(position, block_id, block_configuration)
|
|
f.write(struct.pack("<hhhBB",
|
|
position[0], position[1], position[2],
|
|
block_id,
|
|
block_configuration))
|
|
|
|
def main(mcr_path, data_path):
|
|
with open(mcr_path, "rb") as f:
|
|
buf = f.read()
|
|
mem = memoryview(buf)
|
|
|
|
offset = 0
|
|
offset, locations = mcregion.parse_locations(mem, offset)
|
|
offset, timestamps = mcregion.parse_timestamps(mem, offset)
|
|
assert offset == 0x2000
|
|
|
|
level_table = build_level_table(mem, locations)
|
|
blocks = devoxelize_region(level_table)
|
|
|
|
with open(data_path + ".vtx", "wb") as f:
|
|
build_block_instances(f, blocks)
|
|
|
|
#pprint(list(build_block_configuration_table()))
|
|
|
|
mcr_path = sys.argv[1]
|
|
data_path = sys.argv[2]
|
|
|
|
main(mcr_path, data_path)
|