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 itertools import chain
from collections import defaultdict
import functools
import mcregion
import vec3
@ -22,52 +23,52 @@ non_solid_blocks = {
data.BlockID.TALL_GRASS,
data.BlockID.MUSHROOM_1,
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):
block_id = level_table[(chunk_x, chunk_z)].blocks[block_index]
if block_id == data.BlockID.AIR:
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]
xyz = mcregion.xyz_from_block_index(block_index)
has_neighbor = (n_block_id != data.BlockID.AIR) and (n_block_id not in non_solid_blocks)
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))
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, (x, y, z))
if not neighbor_exists(*neighbor):
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 normal_indices:
yield center_position, block_id, normal_indices
def devoxelize_region(level_table):
for chunk_x, chunk_z in level_table.keys():
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)
def build_level_table(mem, locations):
level_table = {}
def build_level_table(level_table, mem, locations):
for location in locations:
try:
level = mcregion.parse_location(mem, location)
@ -93,6 +94,11 @@ def build_block_configuration_table():
non_cube_blocks = {
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):
@ -148,11 +154,11 @@ def build_block_instances(blocks):
with open(f"{data_path}.instance.cfg", "wb") as f:
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))
def main(mcr_path, data_path):
with open(mcr_path, "rb") as f:
def level_table_from_path(level_table, path):
with open(path, "rb") as f:
buf = f.read()
mem = memoryview(buf)
@ -161,13 +167,34 @@ def main(mcr_path, data_path):
offset, timestamps = mcregion.parse_timestamps(mem, offset)
assert offset == 0x2000
level_table = build_level_table(mem, locations)
blocks = devoxelize_region(level_table)
build_level_table(level_table, mem, locations)
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)
#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]
data_path = sys.argv[2]
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)
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)
x = int(block_index / (128 * 16))
y = int(block_index % 128)
z = int(int(block_index / 128) % 16)
x = block_index // (128 * 16)
y = block_index % 128
z = (block_index // 128) % 16
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 y >= 0 and y < 128
assert z >= 0 and z < 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
# www.blender.org
o TallGrass
v 0.800011 0.600021 0.800011
v 0.800011 -1.000000 0.800011
v -0.800010 -1.000000 0.800011
v -0.800011 0.600021 0.800011
v -0.800011 0.600021 -0.800011
v -0.800011 -1.000000 -0.800011
v 0.800011 -1.000000 -0.800011
v 0.800010 0.600022 -0.800011
v 0.800000 0.600000 0.800000
v 0.800000 -1.000000 0.800000
v -0.800000 -1.000000 0.800000
v -0.800000 0.600000 0.800000
v -0.800000 0.600000 -0.800000
v -0.800000 -1.000000 -0.800000
v 0.800000 -1.000000 -0.800000
v 0.800000 0.600000 -0.800000
vn 0.7071 -0.0000 0.7071
vn 0.7071 -0.0000 -0.7071
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)
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;
FragColor = vec4(texture_color.xyz * vec3(diffuse_intensity), 1.0);