-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathminecraft_solid_fill.py
More file actions
113 lines (90 loc) · 3.91 KB
/
minecraft_solid_fill.py
File metadata and controls
113 lines (90 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/env python3
"""
Solid fill export - No caves/underground visible
Only exports surface terrain as solid mass
"""
import amulet
import struct
import os
from tqdm import tqdm
def write_stl(filename, triangles):
with open(filename, 'wb') as f:
f.write(b'Minecraft Solid' + b'\x00' * 65)
f.write(struct.pack('<I', len(triangles)))
for tri in triangles:
f.write(struct.pack('<fff', 0, 0, 0))
for v in tri:
f.write(struct.pack('<fff', v[0], v[1], v[2]))
f.write(struct.pack('<H', 0))
def find_surface(level, dim, x, z, max_y=200):
"""Find highest non-air block"""
for y in range(max_y, 0, -1):
try:
block = str(level.get_block(x, y, z, dim).namespaced_name).lower()
if 'air' not in block:
return y
except:
pass
return 1
def export_solid(world_path, x_min, x_max, z_min, z_max, output, name):
print(f"\n{name.upper()}")
print("="*60)
level = amulet.load_level(world_path)
dim = level.dimensions[0]
# Build surface height map
print("Scanning surface heights...")
surface_map = {}
total_cols = (x_max - x_min) * (z_max - z_min)
with tqdm(total=total_cols, desc="Scanning", unit="column") as pbar:
for x in range(x_min, x_max):
for z in range(z_min, z_max):
surface_map[(x, z)] = find_surface(level, dim, x, z)
pbar.update(1)
# Generate solid blocks from base to surface
print("Building solid geometry...")
triangles = []
total_blocks = sum(surface_map.values())
with tqdm(total=total_blocks, desc="Building", unit="block") as pbar:
for x in range(x_min, x_max):
for z in range(z_min, z_max):
surface_y = surface_map.get((x, z), 1)
# Create solid column from Y=0 to surface
for y in range(0, surface_y + 1):
v = [
(x,y,z),(x+1,y,z),(x+1,y,z+1),(x,y,z+1),
(x,y+1,z),(x+1,y+1,z),(x+1,y+1,z+1),(x,y+1,z+1)
]
# Bottom face (at Y=0 only)
if y == 0:
triangles.extend([[v[0],v[1],v[2]],[v[0],v[2],v[3]]])
# Top face (at surface only)
if y == surface_y:
triangles.extend([[v[4],v[7],v[6]],[v[4],v[6],v[5]]])
# Side faces (if neighbor is shorter)
if surface_map.get((x,z-1), 0) < y:
triangles.extend([[v[0],v[4],v[5]],[v[0],v[5],v[1]]])
if surface_map.get((x,z+1), 0) < y:
triangles.extend([[v[2],v[6],v[7]],[v[2],v[7],v[3]]])
if surface_map.get((x-1,z), 0) < y:
triangles.extend([[v[0],v[3],v[7]],[v[0],v[7],v[4]]])
if surface_map.get((x+1,z), 0) < y:
triangles.extend([[v[1],v[5],v[6]],[v[1],v[6],v[2]]])
pbar.update(1)
level.close()
print(f"Writing {len(triangles):,} triangles...")
write_stl(output, triangles)
size = os.path.getsize(output) / (1024*1024)
print(f"✓ {size:.1f} MB\n")
if __name__ == "__main__":
from tqdm import tqdm
world = "TU69_Tutorial_World_2024-08-31@23-00-50"
output_dir = "minecraft_stl_solid_final"
os.makedirs(output_dir, exist_ok=True)
# Start with one section
print("\nSOLID FILL EXPORT - No caves visible")
print("="*60)
export_solid(world, -256, 0, -256, 0,
os.path.join(output_dir, "test_solid.stl"),
"Test Solid 256x256")
print("\n✓ Import test_solid.stl into Bambu Studio")
print("Should be: solid mass, no floating underground parts!")