-
Notifications
You must be signed in to change notification settings - Fork 9
/
minecraft_print.py
196 lines (164 loc) · 8.74 KB
/
minecraft_print.py
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import pymclevel.mclevel as mclevel
import sys
import os
from pymclevel.box import BoundingBox
import numpy
from numpy import zeros, bincount
import logging
import itertools
import traceback
import shlex
import operator
import codecs
from math import floor
try:
import readline
except:
pass
class UsageError(RuntimeError): pass
class BlockMatchError(RuntimeError): pass
class PlayerNotFound(RuntimeError): pass
class MinecraftPrint:
def __init__(self, level, output):
self.level_name = level
self.output_name = output + '.stl'
#The list of goodness and markers
#Format: [[chunk_x, chunk_z, block_x, block_z, block_y]]
self.markers = []
self.chunk_positions = []
self.num_chunks = 0
self.chunk_counter = 0
self.diamond_check = []
self.object_array = []
#Data value for each block type
self.diamond = 57
self.gold = 41
self.iron = 42
def generate(self):
self.find_marked_area()
self.copy_marked_area()
self.generate_stl()
def find_marked_area(self):
self.world = mclevel.loadWorld(self.level_name)
#Load chunks and determine minimize indexes
self.chunk_positions = list(self.world.allChunks)
self.num_chunks = len(self.chunk_positions)
#Just a little user feedback on the progress
print "Processing level: " + self.level_name
print "Scanning level for markers..."
self.chunk_counter = 1
self.find_markers()
print '100%'
def find_markers(self):
#Iterate through chunks, looking for block combination
for x_pos, z_pos in self.chunk_positions:
#User feedback
if self.chunk_counter % 10 == 0:
print str(self.chunk_counter/float(self.num_chunks)*100) + "%"
self.chunk_counter += 1
chunk = self.world.getChunk(x_pos, z_pos)
#Does this chunk have a diamond block?
diamond_check = numpy.where(chunk.Blocks == self.diamond)
if len(diamond_check[0]) > 0:
for dx, dz, dy in zip(diamond_check[0], diamond_check[1], diamond_check[2]):
#We found diamond, but is it a marker (diamond, gold, and iron in asc or desc vertical order)
#If so, define the diamond block coordinates as the marker and remove the marker from the map (along with everything above and below)
if dy > 1 and chunk.Blocks[dx, dz, dy - 1] == self.gold and chunk.Blocks[dx, dz, dy - 2] == self.iron:
self.markers.append([x_pos, z_pos, dx, dz, dy])
for y in range(256):
chunk.Blocks[dx, dz, y] = 0
elif dy < 126 and chunk.Blocks[dx, dz, dy + 1] == self.gold and chunk.Blocks[dx, dz, dy + 2] == self.iron:
self.markers.append([x_pos, z_pos, dx, dz, dy])
for y in range(256):
chunk.Blocks[dx, dz, y] = 0
def copy_marked_area(self):
#Now we have the markers. Time to get serious
if len(self.markers) == 2:
print "Congrats, looks like we have two markers"
print "..."
print "Capturing marked area... this may take a minute..."
#Calculate x_min and x_max
if self.markers[0][0] < self.markers[1][0]:
x_min = [self.markers[0][0], self.markers[0][2]]
x_max = [self.markers[1][0], self.markers[1][2]]
elif self.markers[0][0] > self.markers[1][0]:
x_min = [self.markers[1][0], self.markers[1][2]]
x_max = [self.markers[0][0], self.markers[0][2]]
else:
x_min = [self.markers[0][0], min(self.markers[0][2], self.markers[1][2])]
x_max = [self.markers[0][0], max(self.markers[0][2], self.markers[1][2])]
#Calculate z_min and z_max
if self.markers[0][1] < self.markers[1][1]:
z_min = [self.markers[0][1], self.markers[0][3]]
z_max = [self.markers[1][1], self.markers[1][3]]
elif self.markers[0][1] > self.markers[1][1]:
z_min = [self.markers[1][1], self.markers[1][3]]
z_max = [self.markers[0][1], self.markers[0][3]]
else:
z_min = [self.markers[0][1], min(self.markers[0][3], self.markers[1][3])]
z_max = [self.markers[0][1], max(self.markers[0][3], self.markers[1][3])]
#Calculate y_min and y_max
y_min = min(self.markers[0][4], self.markers[1][4])
y_max = max(self.markers[0][4], self.markers[1][4])
#Construct an array to fit the object
self.object_array = [[[0 for z in xrange((z_max[0] - z_min[0] + 1) * 16)] for y in xrange(y_max - y_min + 1)] for x in xrange((x_max[0] - x_min[0] + 1) * 16)]
#Copy marked blocks to object_array
for x_pos in range(x_min[0], x_max[0] + 1):
for z_pos in range(z_min[0], z_max[0] + 1):
chunk = self.world.getChunk(x_pos, z_pos)
for x in range(16):
for z in range(16):
for y in range(y_max - y_min + 1):
if (x_pos == x_min[0] and x < x_min[1]) or (x_pos == x_max[0] and x > x_max[1]):
block_type = 0
elif (z_pos == z_min[0] and z < z_min[1]) or (z_pos == z_max[0] and z > z_max[1]):
block_type = 0
else:
block_type = chunk.Blocks[x, z, y_min + y]
#print str((16 * (x_pos + offsetx)) + x) + ", " + str(y) + ", " + str((16 * (z_pos + offsetz)) + z)
self.object_array[(16 * (x_pos -x_min[0])) + x][y][(16 * (z_pos - z_min[0])) + z] = block_type
else:
print "Freak out! There are somehow more or less than 2 markers!"
def generate_stl(self):
"""Generate STL file"""
filename = self.output_name
width = len(self.object_array)
try:
height = len(self.object_array[0])
except:
print self.object_array
depth = len(self.object_array[0][0])
str_o = "solid Minecraft\n";
str_e = " endloop\n endfacet\n"
str_s = " facet normal %d %d %d\n outer loop\n"
str_v = " vertex %d %d %d\n"
print "start"
f=open(filename, 'w')
f.write(str_o)
for x in range(width):
print str(x/float(width)*100) + "%"
for y in range(height):
for z in range(depth):
if self.object_array[x][y][z] > 0:
if x==0 or self.object_array[x-1][y][z]<=0:
f.write("".join([str_s%(-1,0,0),str_v%(x,z+1,y), str_v%(x,z,y+1),str_v%(x,z+1,y+1),str_e]))
f.write("".join([str_s%(-1,0,0),str_v%(x,z+1,y), str_v%(x,z,y),str_v%(x,z,y+1),str_e]))
if x==width-1 or self.object_array[x+1][y][z]<=0:
f.write("".join([str_s%(1,0,0),str_v%(x+1,z+1,y), str_v%(x+1,z+1,y+1),str_v%(x+1,z,y+1),str_e]))
f.write("".join([str_s%(1,0,0),str_v%(x+1,z+1,y), str_v%(x+1,z,y+1),str_v%(x+1,z,y),str_e]))
if (z==0) or self.object_array[x][y][z-1]<=0:
f.write("".join([str_s%(0,0,-1),str_v%(x,z,y), str_v%(x+1,z,y+1),str_v%(x,z,y+1),str_e]))
f.write("".join([str_s%(0,0,-1),str_v%(x,z,y), str_v%(x+1,z,y),str_v%(x+1,z,y+1),str_e]))
if (z==depth-1) or self.object_array[x][y][z+1]<=0:
f.write("".join([str_s%(0,0,1),str_v%(x,z+1,y), str_v%(x,z+1,y+1),str_v%(x+1,z+1,y+1),str_e]))
f.write("".join([str_s%(0,0,1),str_v%(x,z+1,y), str_v%(x+1,z+1,y+1),str_v%(x+1,z+1,y),str_e]))
if (y==0) or self.object_array[x][y-1][z]<=0:
f.write("".join([str_s%(0,-1,0),str_v%(x+1,z,y), str_v%(x,z+1,y),str_v%(x+1,z+1,y),str_e]))
f.write("".join([str_s%(0,-1,0),str_v%(x+1,z,y), str_v%(x,z,y),str_v%(x,z+1,y),str_e]))
if (y==height-1) or self.object_array[x][y+1][z]<=0:
f.write("".join([str_s%(0,1,0),str_v%(x+1,z,y+1), str_v%(x+1,z+1,y+1),str_v%(x,z+1,y+1),str_e]))
f.write("".join([str_s%(0,1,0),str_v%(x+1,z,y+1), str_v%(x,z+1,y+1),str_v%(x,z,y+1),str_e]))
f.write("endsolid Minecraft\n")
print "100%"
f.close()
print "Done!"