3 # This is an example script that generates some valid map data.
11 from pnoise import pnoise
13 # Old directory format:
14 # world/sectors/XXXXZZZZ/YYYY
15 # XXXX,YYYY,ZZZZ = coordinates in hexadecimal
21 # New directory format:
22 # world/sectors2/XXX/ZZZ/YYYY
23 # XXX,YYYY,ZZZ = coordinates in hexadecimal
33 # For more proper file format documentation, refer to mapformat.txt
34 # For node type documentation, refer to mapnode.h
35 # NodeMetadata documentation is not complete, refer to nodemeta.cpp
38 # Seed for generating terrain
48 s += '{0:1x}'.format((i>>12) & 0x000f)
49 s += '{0:1x}'.format((i>>8) & 0x000f)
50 s += '{0:1x}'.format((i>>4) & 0x000f)
51 s += '{0:1x}'.format((i>>0) & 0x000f)
56 s += '{0:1x}'.format((i>>8) & 0x000f)
57 s += '{0:1x}'.format((i>>4) & 0x000f)
58 s += '{0:1x}'.format((i>>0) & 0x000f)
61 def get_sector_dir(px, pz):
62 global SECTOR_DIR_FORMAT
63 if SECTOR_DIR_FORMAT == 0:
64 return "/sectors/"+to4h(px)+to4h(pz)
65 elif SECTOR_DIR_FORMAT == 1:
66 return "/sectors2/"+to3h(px)+"/"+to3h(pz)
70 def getrand_air_stone():
71 i = random.randrange(0,2)
76 # 3-dimensional vector (position)
78 def __init__(self, x=0, y=0, z=0):
84 def __init__(self, type_id, data):
85 self.type_id = type_id
94 return chr((i>>8)&0xff) + chr((i>>0)&0xff)
96 return (chr((i>>24)&0xff) + chr((i>>16)&0xff)
97 + chr((i>>8)&0xff) + chr((i>>0)&0xff))
99 # A 16x16x16 chunk of map
102 self.content = array.array('B')
103 self.param1 = array.array('B')
104 self.param2 = array.array('B')
105 for i in range(16*16*16):
107 self.content.append(254)
108 # Full light on sunlight, none when no sunlight
109 self.param1.append(15)
110 # No additional parameters
111 self.param2.append(0)
118 # value = StaticObject
119 self.static_objects = {}
121 def set_content(self, v3, b):
122 self.content[v3.Z*16*16+v3.Y*16+v3.X] = b
123 def set_param1(self, v3, b):
124 self.param1[v3.Z*16*16+v3.Y*16+v3.X] = b
125 def set_param2(self, v3, b):
126 self.param2[v3.Z*16*16+v3.Y*16+v3.X] = b
128 # Get data for serialization. Returns a string.
129 def serialize_data(self):
131 for i in range(16*16*16):
132 s += chr(self.content[i])
133 for i in range(16*16*16):
134 s += chr(self.param1[i])
135 for i in range(16*16*16):
136 s += chr(self.param2[i])
139 def serialize_nodemeta(self):
142 s += ser_u16(len(self.nodemeta))
143 for pos, meta in self.nodemeta.items():
144 pos_i = pos.Z*16*16 + pos.Y*16 + pos.X
146 s += ser_u16(meta.type_id)
147 s += ser_u16(len(meta.data))
151 def serialize_staticobj(self):
154 s += ser_u16(len(self.static_objects))
155 for pos, obj in self.static_objects.items():
156 pos_i = pos.Z*16*16 + pos.Y*16 + pos.X
157 s += ser_s32(pos.X*1000)
158 s += ser_s32(pos.Y*1000)
159 s += ser_s32(pos.Z*1000)
160 s += ser_u16(obj.type_id)
161 s += ser_u16(len(obj.data))
165 def writeblock(mapdir, px,py,pz, block):
167 sectordir = mapdir + get_sector_dir(px, pz);
170 os.makedirs(sectordir)
174 path = sectordir+"/"+to4h(py)
176 print("writing block file "+path)
178 f = open(sectordir+"/"+to4h(py), "wb")
185 f.write(struct.pack('B', version))
188 # 0x01=is_undg, 0x02=dn_diff, 0x04=lighting_expired
189 flags = 0 + 0x02 + 0x04
190 f.write(struct.pack('B', flags))
193 c_obj = zlib.compressobj()
194 c_obj.compress(block.serialize_data())
195 f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number
196 f.write(c_obj.flush())
199 c_obj = zlib.compressobj()
200 c_obj.compress(block.serialize_nodemeta())
201 f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number
202 f.write(c_obj.flush())
204 # mapblockobject count
208 f.write(block.serialize_staticobj())
211 f.write(ser_u32(0xffffffff))
215 for z0 in range(-1,3):
216 for x0 in range(-1,3):
217 for y0 in range(-1,3):
218 print("generating block "+str(x0)+","+str(y0)+","+str(z0))
219 #v3 blockp = v3(x0,y0,z0)
224 # Generate stuff in it
225 for z in range(0,16):
226 for x in range(0,16):
227 h = 20.0*pnoise((x0*16+x)/100.,(z0*16+z)/100.,SEED+0)
228 h += 5.0*pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+0)
229 if pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+92412) > 0.05:
232 # This enables comparison by ==
234 for y in range(0,16):
240 elif y1 <= h and y1 <= 0:
250 block.set_content(p, b)
252 # Place a sign at the center at surface level.
253 # Placing a sign means placing the sign node and
254 # adding node metadata to the mapblock.
255 if x == 8 and z == 8 and y0*16 <= h-1 and (y0+1)*16-1 > h:
256 p = v3(8,h+1-y0*16,8)
259 block.set_content(p, content_type)
260 # This places the sign to the bottom of the cube.
261 # Working values: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20
262 block.set_param2(p, 0x08)
263 # Then add metadata to hold the text of the sign
264 s = "Hello at sector ("+str(x0)+","+str(z0)+")"
265 meta = NodeMeta(content_type, ser_u16(len(s))+s)
266 block.nodemeta[p] = meta
269 writeblock(mapdir, x0,y0,z0, block)