minecraft: mushrooms, flowers, saplings

This commit is contained in:
Zack Buhman 2026-03-07 18:59:48 -06:00
parent 8ce7ca035a
commit 3469ccacfd
13 changed files with 95 additions and 47 deletions

View File

@ -3,6 +3,7 @@ import struct
from pprint import pprint from pprint import pprint
from itertools import chain from itertools import chain
from collections import defaultdict from collections import defaultdict
import functools
import mcregion import mcregion
import vec3 import vec3
@ -22,52 +23,52 @@ non_solid_blocks = {
data.BlockID.TALL_GRASS, data.BlockID.TALL_GRASS,
data.BlockID.MUSHROOM_1, data.BlockID.MUSHROOM_1,
data.BlockID.MUSHROOM_2, data.BlockID.MUSHROOM_2,
data.BlockID.FLOWER,
data.BlockID.ROSE,
data.BlockID.SAPLING,
} }
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)
return has_neighbor
def block_neighbors(level_table, chunk_x, chunk_z, block_index): def block_neighbors(level_table, chunk_x, chunk_z, block_index):
block_id = level_table[(chunk_x, chunk_z)].blocks[block_index] block_id = level_table[(chunk_x, chunk_z)].blocks[block_index]
if block_id == data.BlockID.AIR: if block_id == data.BlockID.AIR:
return return
def neighbor_exists(nx, ny, nz): xyz = mcregion.xyz_from_block_index(block_index)
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]
has_neighbor = (n_block_id != data.BlockID.AIR) and (n_block_id not in non_solid_blocks) center_position = vec3.add(xyz, (chunk_x * 16, 0, chunk_z * 16))
return has_neighbor
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(): def find_non_neighbors():
for i, normal in enumerate(vertex_buffer.normals): for i, normal in enumerate(vertex_buffer.normals):
neighbor = vec3.add(normal, (x, y, z)) neighbor = vec3.add(normal, xyz)
if not neighbor_exists(*neighbor): if not neighbor_exists(level_table, chunk_x, chunk_z, *neighbor):
yield i yield i
normal_indices = list(find_non_neighbors()) normal_indices = list(find_non_neighbors())
if block_id in non_solid_blocks or normal_indices: if block_id in non_solid_blocks or normal_indices:
yield center_position, block_id, normal_indices yield center_position, block_id, normal_indices
def devoxelize_region(level_table): def devoxelize_region(level_table, level_table_keys):
for chunk_x, chunk_z in level_table.keys(): for chunk_x, chunk_z in level_table_keys:
for block_index in range(128 * 16 * 16): for block_index in range(128 * 16 * 16):
yield from block_neighbors(level_table, chunk_x, chunk_z, block_index) yield from block_neighbors(level_table, chunk_x, chunk_z, block_index)
def build_level_table(mem, locations): def build_level_table(level_table, mem, locations):
level_table = {}
for location in locations: for location in locations:
try: try:
level = mcregion.parse_location(mem, location) level = mcregion.parse_location(mem, location)
@ -93,6 +94,11 @@ def build_block_configuration_table():
non_cube_blocks = { non_cube_blocks = {
data.BlockID.TALL_GRASS, data.BlockID.TALL_GRASS,
data.BlockID.MUSHROOM_1,
data.BlockID.MUSHROOM_2,
data.BlockID.FLOWER,
data.BlockID.ROSE,
data.BlockID.SAPLING,
} }
def pack_instance_data(position, block_id): def pack_instance_data(position, block_id):
@ -148,11 +154,11 @@ def build_block_instances(blocks):
with open(f"{data_path}.instance.cfg", "wb") as f: with open(f"{data_path}.instance.cfg", "wb") as f:
for instance_count, offset in configuration_instance_count_offset: for instance_count, offset in configuration_instance_count_offset:
print(instance_count, offset) #print(instance_count, offset)
f.write(struct.pack("<ii", instance_count, offset)) f.write(struct.pack("<ii", instance_count, offset))
def main(mcr_path, data_path): def level_table_from_path(level_table, path):
with open(mcr_path, "rb") as f: with open(path, "rb") as f:
buf = f.read() buf = f.read()
mem = memoryview(buf) mem = memoryview(buf)
@ -161,13 +167,34 @@ def main(mcr_path, data_path):
offset, timestamps = mcregion.parse_timestamps(mem, offset) offset, timestamps = mcregion.parse_timestamps(mem, offset)
assert offset == 0x2000 assert offset == 0x2000
level_table = build_level_table(mem, locations) build_level_table(level_table, mem, locations)
blocks = devoxelize_region(level_table)
all_paths = [
"/home/bilbo/Love2DWorld/region/r.0.0.mcr",
"/home/bilbo/Love2DWorld/region/r.-1.-1.mcr",
"/home/bilbo/Love2DWorld/region/r.0.-1.mcr",
"/home/bilbo/Love2DWorld/region/r.-1.0.mcr",
]
def main2(level_table, level_table_keys):
blocks = devoxelize_region(level_table, level_table_keys)
build_block_instances(blocks) build_block_instances(blocks)
#pprint(list(build_block_configuration_table())) def main(mcr_path, data_path):
assert mcr_path in all_paths
level_table = {}
level_table_from_path(level_table, mcr_path)
level_table_keys = list(level_table.keys())
for path in all_paths:
if path == mcr_path:
continue
level_table_from_path(level_table, path)
main2(level_table, level_table_keys)
#import cProfile
#cProfile.runctx("main2(level_table, level_table_keys)", {},
# {"level_table_keys": level_table_keys, "level_table": level_table, "main2": main2})
mcr_path = sys.argv[1] mcr_path = sys.argv[1]
data_path = sys.argv[2] data_path = sys.argv[2]
main(mcr_path, data_path) main(mcr_path, data_path)

6
minecraft/gen/mc.sh Normal file
View File

@ -0,0 +1,6 @@
set -eux
cd ./minecraft/gen
python mc.py ~/Love2DWorld/region/r.0.0.mcr ../region.0.0 &
python mc.py ~/Love2DWorld/region/r.-1.-1.mcr ../region.-1.-1 &
python mc.py ~/Love2DWorld/region/r.0.-1.mcr ../region.0.-1 &
python mc.py ~/Love2DWorld/region/r.-1.0.mcr ../region.-1.0 &

View File

@ -217,15 +217,30 @@ def parse_location(mem, location):
level = level_from_tag(tag) level = level_from_tag(tag)
return level return level
def xyz_from_block_index(block_index): def _xyz_from_block_index(block_index):
assert block_index >= 0 and block_index < (128 * 16 * 16) assert block_index >= 0 and block_index < (128 * 16 * 16)
x = int(block_index / (128 * 16)) x = block_index // (128 * 16)
y = int(block_index % 128) y = block_index % 128
z = int(int(block_index / 128) % 16) z = (block_index // 128) % 16
return x, y, z return x, y, z
def block_index_from_xyz(x, y, z): def _block_index_from_xyz(x, y, z):
assert x >= 0 and x < 16 assert x >= 0 and x < 16
assert y >= 0 and y < 128 assert y >= 0 and y < 128
assert z >= 0 and z < 16 assert z >= 0 and z < 16
return int(y + z * 128 + x * 128 * 16) return int(y + z * 128 + x * 128 * 16)
xyz_to_block_index = {}
block_index_to_xyz = {}
for i in range(128 * 16 * 16):
xyz = _xyz_from_block_index(i)
assert _block_index_from_xyz(*xyz) == i
xyz_to_block_index[xyz] = i
block_index_to_xyz[i] = xyz
def xyz_from_block_index(block_index):
return block_index_to_xyz[block_index]
def block_index_from_xyz(x, y, z):
return xyz_to_block_index[(x, y, z)]

View File

@ -1,14 +1,14 @@
# Blender 5.0.0 # Blender 5.0.0
# www.blender.org # www.blender.org
o TallGrass o TallGrass
v 0.800011 0.600021 0.800011 v 0.800000 0.600000 0.800000
v 0.800011 -1.000000 0.800011 v 0.800000 -1.000000 0.800000
v -0.800010 -1.000000 0.800011 v -0.800000 -1.000000 0.800000
v -0.800011 0.600021 0.800011 v -0.800000 0.600000 0.800000
v -0.800011 0.600021 -0.800011 v -0.800000 0.600000 -0.800000
v -0.800011 -1.000000 -0.800011 v -0.800000 -1.000000 -0.800000
v 0.800011 -1.000000 -0.800011 v 0.800000 -1.000000 -0.800000
v 0.800010 0.600022 -0.800011 v 0.800000 0.600000 -0.800000
vn 0.7071 -0.0000 0.7071 vn 0.7071 -0.0000 0.7071
vn 0.7071 -0.0000 -0.7071 vn 0.7071 -0.0000 -0.7071
vt 1.000000 1.000000 vt 1.000000 1.000000

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -51,7 +51,7 @@ void main()
if (diffuse_intensity < 0.1) if (diffuse_intensity < 0.1)
diffuse_intensity = 0.1; diffuse_intensity = 0.1;
if (fs_in.BlockID == 31) // tall_grass if (fs_in.BlockID == 31 || fs_in.BlockID == 39 || fs_in.BlockID == 40 || fs_in.BlockID == 37 || fs_in.BlockID == 38 || fs_in.BlockID == 6) // tall_grass
diffuse_intensity = 1.0; diffuse_intensity = 1.0;
FragColor = vec4(texture_color.xyz * vec3(diffuse_intensity), 1.0); FragColor = vec4(texture_color.xyz * vec3(diffuse_intensity), 1.0);