From a649d43fe7349e5cfa4c67de93377004902c1b07 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 5 Jun 2011 00:10:06 +0300 Subject: Messed around with genmap.py. Now supports format version 17. --- genmap.py | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 230 insertions(+), 50 deletions(-) (limited to 'genmap.py') diff --git a/genmap.py b/genmap.py index aaa35690f..a60509403 100755 --- a/genmap.py +++ b/genmap.py @@ -6,19 +6,42 @@ import struct import random import os import sys +import zlib +import array from pnoise import pnoise -""" -Map format: -map/sectors/XXXXZZZZ/YYYY +# Old directory format: +# world/sectors/XXXXZZZZ/YYYY +# XXXX,YYYY,ZZZZ = coordinates in hexadecimal +# fffe = -2 +# ffff = -1 +# 0000 = 0 +# 0001 = 1 +# +# New directory format: +# world/sectors2/XXX/ZZZ/YYYY +# XXX,YYYY,ZZZ = coordinates in hexadecimal +# fffe = -2 +# ffff = -1 +# 0000 = 0 +# 0001 = 1 +# ffe = -2 +# fff = -1 +# 000 = 0 +# 001 = 1 +# +# For more proper file format documentation, refer to mapformat.txt +# For node type documentation, refer to mapnode.h +# NodeMetadata documentation is not complete, refer to nodemeta.cpp +# -XXXX,YYYY,ZZZZ = coordinates in hexadecimal +# Seed for generating terrain +SEED = 0 -fffe = -2 -ffff = -1 -0000 = 0 -0001 = 1 -""" +# 0=old, 1=new +SECTOR_DIR_FORMAT = 1 + +mapdir = "world" def to4h(i): s = ""; @@ -28,64 +51,221 @@ def to4h(i): s += '{0:1x}'.format((i>>0) & 0x000f) return s -def getrand(): +def to3h(i): + s = ""; + s += '{0:1x}'.format((i>>8) & 0x000f) + s += '{0:1x}'.format((i>>4) & 0x000f) + s += '{0:1x}'.format((i>>0) & 0x000f) + return s + +def get_sector_dir(px, pz): + global SECTOR_DIR_FORMAT + if SECTOR_DIR_FORMAT == 0: + return "/sectors/"+to4h(px)+to4h(pz) + elif SECTOR_DIR_FORMAT == 1: + return "/sectors2/"+to3h(px)+"/"+to3h(pz) + else: + assert(0) + +def getrand_air_stone(): i = random.randrange(0,2) if i==0: return 0 return 254 -def writeblock(mapdir, px,py,pz, version): - sectordir = mapdir + "/sectors/" + to4h(px) + to4h(pz) +# 3-dimensional vector (position) +class v3: + def __init__(self, x=0, y=0, z=0): + self.X = x + self.Y = y + self.Z = z + +class NodeMeta: + def __init__(self, type_id, data): + self.type_id = type_id + self.data = data + +class StaticObject: + def __init__(self): + self.type_id = 0 + self.data = "" + +def ser_u16(i): + return chr((i>>8)&0xff) + chr((i>>0)&0xff) +def ser_u32(i): + return (chr((i>>24)&0xff) + chr((i>>16)&0xff) + + chr((i>>8)&0xff) + chr((i>>0)&0xff)) + +# A 16x16x16 chunk of map +class MapBlock: + def __init__(self): + self.content = array.array('B') + self.param1 = array.array('B') + self.param2 = array.array('B') + for i in range(16*16*16): + # Initialize to air + self.content.append(254) + # Full light on sunlight, none when no sunlight + self.param1.append(15) + # No additional parameters + self.param2.append(0) + + # key = v3 pos + # value = NodeMeta + self.nodemeta = {} + + # key = v3 pos + # value = StaticObject + self.static_objects = {} + + def set_content(self, v3, b): + self.content[v3.Z*16*16+v3.Y*16+v3.X] = b + def set_param1(self, v3, b): + self.param1[v3.Z*16*16+v3.Y*16+v3.X] = b + def set_param2(self, v3, b): + self.param2[v3.Z*16*16+v3.Y*16+v3.X] = b + + # Get data for serialization. Returns a string. + def serialize_data(self): + s = "" + for i in range(16*16*16): + s += chr(self.content[i]) + for i in range(16*16*16): + s += chr(self.param1[i]) + for i in range(16*16*16): + s += chr(self.param2[i]) + return s + + def serialize_nodemeta(self): + s = "" + s += ser_u16(1) + s += ser_u16(len(self.nodemeta)) + for pos, meta in self.nodemeta.items(): + pos_i = pos.Z*16*16 + pos.Y*16 + pos.X + s += ser_u16(pos_i) + s += ser_u16(meta.type_id) + s += ser_u16(len(meta.data)) + s += meta.data + return s + + def serialize_staticobj(self): + s = "" + s += chr(0) + s += ser_u16(len(self.static_objects)) + for pos, obj in self.static_objects.items(): + pos_i = pos.Z*16*16 + pos.Y*16 + pos.X + s += ser_s32(pos.X*1000) + s += ser_s32(pos.Y*1000) + s += ser_s32(pos.Z*1000) + s += ser_u16(obj.type_id) + s += ser_u16(len(obj.data)) + s += obj.data + return s + +def writeblock(mapdir, px,py,pz, block): + + sectordir = mapdir + get_sector_dir(px, pz); try: os.makedirs(sectordir) except OSError: pass + + path = sectordir+"/"+to4h(py) + + print("writing block file "+path) f = open(sectordir+"/"+to4h(py), "wb") - if version == 0: - # version - f.write(struct.pack('B', 0)) - # is_underground - f.write(struct.pack('B', 0)) - elif version == 2: - # version - f.write(struct.pack('B', 2)) - # is_underground - f.write(struct.pack('B', 0)) + if f == None: + return + + # version + version = 17 + f.write(struct.pack('B', version)) + + # flags + # 0x01=is_undg, 0x02=dn_diff, 0x04=lighting_expired + flags = 0 + 0x02 + 0x04 + f.write(struct.pack('B', flags)) - for z in range(0,16): - for y in range(0,16): - for x in range(0,16): - b = 254 - r = 20.0*pnoise((px*16+x)/100.,(pz*16+z)/100.,0) - r += 5.0*pnoise((px*16+x)/25.,(pz*16+z)/25.,0) - #print("r="+str(r)) - y1 = py*16+y - if y1 <= r-3: - b = 0 #stone - elif y1 <= r: - b = 1 #grass - elif y1 <= 1: - b = 9 #water - if version == 0: - # Material content - f.write(struct.pack('B', b)) - elif version == 2: - # Material content - f.write(struct.pack('B', b)) - # Brightness - f.write(struct.pack('B', 15)) + # data + c_obj = zlib.compressobj() + c_obj.compress(block.serialize_data()) + f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number + f.write(c_obj.flush()) + + # node metadata + c_obj = zlib.compressobj() + c_obj.compress(block.serialize_nodemeta()) + f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number + f.write(c_obj.flush()) + + # mapblockobject count + f.write(ser_u16(0)) + + # static objects + f.write(block.serialize_staticobj()) + + # timestamp + f.write(ser_u32(0xffffffff)) f.close() -mapdir = "map" +for z0 in range(-1,3): + for x0 in range(-1,3): + for y0 in range(-1,3): + print("generating block "+str(x0)+","+str(y0)+","+str(z0)) + #v3 blockp = v3(x0,y0,z0) + + # Create a MapBlock + block = MapBlock() + + # Generate stuff in it + for z in range(0,16): + for x in range(0,16): + h = 20.0*pnoise((x0*16+x)/100.,(z0*16+z)/100.,SEED+0) + h += 5.0*pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+0) + if pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+92412) > 0.05: + h += 10 + #print("r="+str(r)) + # This enables comparison by == + h = int(h) + for y in range(0,16): + p = v3(x,y,z) + b = 254 + y1 = y0*16+y + if y1 <= h-3: + b = 0 #stone + elif y1 <= h and y1 <= 0: + b = 8 #mud + elif y1 == h: + b = 1 #grass + elif y1 < h: + b = 8 #mud + elif y1 <= 1: + b = 9 #water + + # Material content + block.set_content(p, b) + + # Place a sign at the center at surface level. + # Placing a sign means placing the sign node and + # adding node metadata to the mapblock. + if x == 8 and z == 8 and y0*16 <= h-1 and (y0+1)*16-1 > h: + p = v3(8,h+1-y0*16,8) + # 14 = Sign + content_type = 14 + block.set_content(p, content_type) + # This places the sign to the bottom of the cube. + # Working values: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20 + block.set_param2(p, 0x08) + # Then add metadata to hold the text of the sign + s = "Hello at sector ("+str(x0)+","+str(z0)+")" + meta = NodeMeta(content_type, ser_u16(len(s))+s) + block.nodemeta[p] = meta -for z in range(-2,3): - for y in range(-1,2): - for x in range(-2,3): - print("generating block "+str(x)+","+str(y)+","+str(z)) - writeblock(mapdir, x,y,z, 0) + # Write it on disk + writeblock(mapdir, x0,y0,z0, block) #END -- cgit v1.2.3 From 47e4eda4bb87cd9dc20dddf81ca473b523eeb150 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 25 Jun 2011 04:23:21 +0300 Subject: Reorganizing stuff (import from temporary git repo) --- genmap.py | 271 -------------------------------------------------------------- 1 file changed, 271 deletions(-) delete mode 100755 genmap.py (limited to 'genmap.py') diff --git a/genmap.py b/genmap.py deleted file mode 100755 index a60509403..000000000 --- a/genmap.py +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/python2 - -# This is an example script that generates some valid map data. - -import struct -import random -import os -import sys -import zlib -import array -from pnoise import pnoise - -# Old directory format: -# world/sectors/XXXXZZZZ/YYYY -# XXXX,YYYY,ZZZZ = coordinates in hexadecimal -# fffe = -2 -# ffff = -1 -# 0000 = 0 -# 0001 = 1 -# -# New directory format: -# world/sectors2/XXX/ZZZ/YYYY -# XXX,YYYY,ZZZ = coordinates in hexadecimal -# fffe = -2 -# ffff = -1 -# 0000 = 0 -# 0001 = 1 -# ffe = -2 -# fff = -1 -# 000 = 0 -# 001 = 1 -# -# For more proper file format documentation, refer to mapformat.txt -# For node type documentation, refer to mapnode.h -# NodeMetadata documentation is not complete, refer to nodemeta.cpp -# - -# Seed for generating terrain -SEED = 0 - -# 0=old, 1=new -SECTOR_DIR_FORMAT = 1 - -mapdir = "world" - -def to4h(i): - s = ""; - s += '{0:1x}'.format((i>>12) & 0x000f) - s += '{0:1x}'.format((i>>8) & 0x000f) - s += '{0:1x}'.format((i>>4) & 0x000f) - s += '{0:1x}'.format((i>>0) & 0x000f) - return s - -def to3h(i): - s = ""; - s += '{0:1x}'.format((i>>8) & 0x000f) - s += '{0:1x}'.format((i>>4) & 0x000f) - s += '{0:1x}'.format((i>>0) & 0x000f) - return s - -def get_sector_dir(px, pz): - global SECTOR_DIR_FORMAT - if SECTOR_DIR_FORMAT == 0: - return "/sectors/"+to4h(px)+to4h(pz) - elif SECTOR_DIR_FORMAT == 1: - return "/sectors2/"+to3h(px)+"/"+to3h(pz) - else: - assert(0) - -def getrand_air_stone(): - i = random.randrange(0,2) - if i==0: - return 0 - return 254 - -# 3-dimensional vector (position) -class v3: - def __init__(self, x=0, y=0, z=0): - self.X = x - self.Y = y - self.Z = z - -class NodeMeta: - def __init__(self, type_id, data): - self.type_id = type_id - self.data = data - -class StaticObject: - def __init__(self): - self.type_id = 0 - self.data = "" - -def ser_u16(i): - return chr((i>>8)&0xff) + chr((i>>0)&0xff) -def ser_u32(i): - return (chr((i>>24)&0xff) + chr((i>>16)&0xff) - + chr((i>>8)&0xff) + chr((i>>0)&0xff)) - -# A 16x16x16 chunk of map -class MapBlock: - def __init__(self): - self.content = array.array('B') - self.param1 = array.array('B') - self.param2 = array.array('B') - for i in range(16*16*16): - # Initialize to air - self.content.append(254) - # Full light on sunlight, none when no sunlight - self.param1.append(15) - # No additional parameters - self.param2.append(0) - - # key = v3 pos - # value = NodeMeta - self.nodemeta = {} - - # key = v3 pos - # value = StaticObject - self.static_objects = {} - - def set_content(self, v3, b): - self.content[v3.Z*16*16+v3.Y*16+v3.X] = b - def set_param1(self, v3, b): - self.param1[v3.Z*16*16+v3.Y*16+v3.X] = b - def set_param2(self, v3, b): - self.param2[v3.Z*16*16+v3.Y*16+v3.X] = b - - # Get data for serialization. Returns a string. - def serialize_data(self): - s = "" - for i in range(16*16*16): - s += chr(self.content[i]) - for i in range(16*16*16): - s += chr(self.param1[i]) - for i in range(16*16*16): - s += chr(self.param2[i]) - return s - - def serialize_nodemeta(self): - s = "" - s += ser_u16(1) - s += ser_u16(len(self.nodemeta)) - for pos, meta in self.nodemeta.items(): - pos_i = pos.Z*16*16 + pos.Y*16 + pos.X - s += ser_u16(pos_i) - s += ser_u16(meta.type_id) - s += ser_u16(len(meta.data)) - s += meta.data - return s - - def serialize_staticobj(self): - s = "" - s += chr(0) - s += ser_u16(len(self.static_objects)) - for pos, obj in self.static_objects.items(): - pos_i = pos.Z*16*16 + pos.Y*16 + pos.X - s += ser_s32(pos.X*1000) - s += ser_s32(pos.Y*1000) - s += ser_s32(pos.Z*1000) - s += ser_u16(obj.type_id) - s += ser_u16(len(obj.data)) - s += obj.data - return s - -def writeblock(mapdir, px,py,pz, block): - - sectordir = mapdir + get_sector_dir(px, pz); - - try: - os.makedirs(sectordir) - except OSError: - pass - - path = sectordir+"/"+to4h(py) - - print("writing block file "+path) - - f = open(sectordir+"/"+to4h(py), "wb") - - if f == None: - return - - # version - version = 17 - f.write(struct.pack('B', version)) - - # flags - # 0x01=is_undg, 0x02=dn_diff, 0x04=lighting_expired - flags = 0 + 0x02 + 0x04 - f.write(struct.pack('B', flags)) - - # data - c_obj = zlib.compressobj() - c_obj.compress(block.serialize_data()) - f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number - f.write(c_obj.flush()) - - # node metadata - c_obj = zlib.compressobj() - c_obj.compress(block.serialize_nodemeta()) - f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number - f.write(c_obj.flush()) - - # mapblockobject count - f.write(ser_u16(0)) - - # static objects - f.write(block.serialize_staticobj()) - - # timestamp - f.write(ser_u32(0xffffffff)) - - f.close() - -for z0 in range(-1,3): - for x0 in range(-1,3): - for y0 in range(-1,3): - print("generating block "+str(x0)+","+str(y0)+","+str(z0)) - #v3 blockp = v3(x0,y0,z0) - - # Create a MapBlock - block = MapBlock() - - # Generate stuff in it - for z in range(0,16): - for x in range(0,16): - h = 20.0*pnoise((x0*16+x)/100.,(z0*16+z)/100.,SEED+0) - h += 5.0*pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+0) - if pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+92412) > 0.05: - h += 10 - #print("r="+str(r)) - # This enables comparison by == - h = int(h) - for y in range(0,16): - p = v3(x,y,z) - b = 254 - y1 = y0*16+y - if y1 <= h-3: - b = 0 #stone - elif y1 <= h and y1 <= 0: - b = 8 #mud - elif y1 == h: - b = 1 #grass - elif y1 < h: - b = 8 #mud - elif y1 <= 1: - b = 9 #water - - # Material content - block.set_content(p, b) - - # Place a sign at the center at surface level. - # Placing a sign means placing the sign node and - # adding node metadata to the mapblock. - if x == 8 and z == 8 and y0*16 <= h-1 and (y0+1)*16-1 > h: - p = v3(8,h+1-y0*16,8) - # 14 = Sign - content_type = 14 - block.set_content(p, content_type) - # This places the sign to the bottom of the cube. - # Working values: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20 - block.set_param2(p, 0x08) - # Then add metadata to hold the text of the sign - s = "Hello at sector ("+str(x0)+","+str(z0)+")" - meta = NodeMeta(content_type, ser_u16(len(s))+s) - block.nodemeta[p] = meta - - # Write it on disk - writeblock(mapdir, x0,y0,z0, block) - -#END -- cgit v1.2.3