]> git.lizzy.rs Git - minetest-m13.git/blob - util/genmap.py
Add Minetest-M13 source
[minetest-m13.git] / util / genmap.py
1 #!/usr/bin/python2
2
3 # This is an example script that generates some valid map data.
4
5 import struct
6 import random
7 import os
8 import sys
9 import zlib
10 import array
11 from pnoise import pnoise
12
13 # Old directory format:
14 # world/sectors/XXXXZZZZ/YYYY
15 # XXXX,YYYY,ZZZZ = coordinates in hexadecimal
16 # fffe = -2
17 # ffff = -1
18 # 0000 =  0
19 # 0001 =  1
20
21 # New directory format:
22 # world/sectors2/XXX/ZZZ/YYYY
23 # XXX,YYYY,ZZZ = coordinates in hexadecimal
24 # fffe = -2
25 # ffff = -1
26 # 0000 =  0
27 # 0001 =  1
28 # ffe = -2
29 # fff = -1
30 # 000 =  0
31 # 001 =  1
32 #
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
36 #
37
38 # Seed for generating terrain
39 SEED = 0
40
41 # 0=old, 1=new
42 SECTOR_DIR_FORMAT = 1
43
44 mapdir = "../world"
45
46 def to4h(i):
47         s = "";
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)
52         return s
53
54 def to3h(i):
55         s = "";
56         s += '{0:1x}'.format((i>>8) & 0x000f)
57         s += '{0:1x}'.format((i>>4) & 0x000f)
58         s += '{0:1x}'.format((i>>0) & 0x000f)
59         return s
60
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)
67         else:
68                 assert(0)
69
70 def getrand_air_stone():
71         i = random.randrange(0,2)
72         if i==0:
73                 return 0
74         return 254
75
76 # 3-dimensional vector (position)
77 class v3:
78         def __init__(self, x=0, y=0, z=0):
79                 self.X = x
80                 self.Y = y
81                 self.Z = z
82
83 class NodeMeta:
84         def __init__(self, type_id, data):
85                 self.type_id = type_id
86                 self.data = data
87
88 class StaticObject:
89         def __init__(self):
90                 self.type_id = 0
91                 self.data = ""
92
93 def ser_u16(i):
94         return chr((i>>8)&0xff) + chr((i>>0)&0xff)
95 def ser_u32(i):
96         return (chr((i>>24)&0xff) + chr((i>>16)&0xff)
97                         + chr((i>>8)&0xff) + chr((i>>0)&0xff))
98
99 # A 16x16x16 chunk of map
100 class MapBlock:
101         def __init__(self):
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):
106                         # Initialize to air
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)
112                 
113                 # key = v3 pos
114                 # value = NodeMeta
115                 self.nodemeta = {}
116         
117                 # key = v3 pos
118                 # value = StaticObject
119                 self.static_objects = {}
120         
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
127         
128         # Get data for serialization. Returns a string.
129         def serialize_data(self):
130                 s = ""
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])
137                 return s
138
139         def serialize_nodemeta(self):
140                 s = ""
141                 s += ser_u16(1)
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
145                         s += ser_u16(pos_i)
146                         s += ser_u16(meta.type_id)
147                         s += ser_u16(len(meta.data))
148                         s += meta.data
149                 return s
150
151         def serialize_staticobj(self):
152                 s = ""
153                 s += chr(0)
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))
162                         s += obj.data
163                 return s
164
165 def writeblock(mapdir, px,py,pz, block):
166
167         sectordir = mapdir + get_sector_dir(px, pz);
168         
169         try:
170                 os.makedirs(sectordir)
171         except OSError:
172                 pass
173         
174         path = sectordir+"/"+to4h(py)
175
176         print("writing block file "+path)
177
178         f = open(sectordir+"/"+to4h(py), "wb")
179
180         if f == None:
181                 return
182
183         # version
184         version = 17
185         f.write(struct.pack('B', version))
186
187         # flags
188         # 0x01=is_undg, 0x02=dn_diff, 0x04=lighting_expired
189         flags = 0 + 0x02 + 0x04
190         f.write(struct.pack('B', flags))
191         
192         # data
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())
197
198         # node metadata
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())
203
204         # mapblockobject count
205         f.write(ser_u16(0))
206
207         # static objects
208         f.write(block.serialize_staticobj())
209
210         # timestamp
211         f.write(ser_u32(0xffffffff))
212
213         f.close()
214
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)
220                         
221                         # Create a MapBlock
222                         block = MapBlock()
223                         
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:
230                                                 h += 10
231                                         #print("r="+str(r))
232                                         # This enables comparison by ==
233                                         h = int(h)
234                                         for y in range(0,16):
235                                                 p = v3(x,y,z)
236                                                 b = 254
237                                                 y1 = y0*16+y
238                                                 if y1 <= h-3:
239                                                         b = 0 #stone
240                                                 elif y1 <= h and y1 <= 0:
241                                                         b = 8 #mud
242                                                 elif y1 == h:
243                                                         b = 1 #grass
244                                                 elif y1 < h:
245                                                         b = 8 #mud
246                                                 elif y1 <= 1:
247                                                         b = 9 #water
248
249                                                 # Material content
250                                                 block.set_content(p, b)
251
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)
257                                                 # 14 = Sign
258                                                 content_type = 14
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
267
268                         # Write it on disk
269                         writeblock(mapdir, x0,y0,z0, block)
270
271 #END