+Banned IP addresses and usernames.
+Example content (added indentation):
+ 123.456.78.9|foo
+ 123.456.78.10|bar
+
+map_meta.txt
+-------------
+Simple global map variables.
+Example content (added indentation):
+ seed = 7980462765762429666
+ [end_of_params]
+
+map.sqlite
+-----------
+Map data.
+See Map File Format below.
+
+player1, Foo
+-------------
+Player data.
+Filename can be anything.
+See Player File Format below.
+
+world.mt
+---------
+World metadata.
+Example content (added indentation):
+ gameid = mesetint
+
+Player File Format
+===================
+
+- Should be pretty self-explanatory.
+- Note: position is in nodes * 10
+
+Example content (added indentation):
+ hp = 11
+ name = celeron55
+ pitch = 39.77
+ position = (-5231.97,15,1961.41)
+ version = 1
+ yaw = 101.37
+ PlayerArgsEnd
+ List main 32
+ Item default:torch 13
+ Item default:pick_steel 1 50112
+ Item experimental:tnt
+ Item default:cobble 99
+ Item default:pick_stone 1 13104
+ Item default:shovel_steel 1 51838
+ Item default:dirt 61
+ Item default:rail 78
+ Item default:coal_lump 3
+ Item default:cobble 99
+ Item default:leaves 22
+ Item default:gravel 52
+ Item default:axe_steel 1 2045
+ Item default:cobble 98
+ Item default:sand 61
+ Item default:water_source 94
+ Item default:glass 2
+ Item default:mossycobble
+ Item default:pick_steel 1 64428
+ Item animalmaterials:bone
+ Item default:sword_steel
+ Item default:sapling
+ Item default:sword_stone 1 10647
+ Item default:dirt 99
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ EndInventoryList
+ List craft 9
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ Empty
+ EndInventoryList
+ List craftpreview 1
+ Empty
+ EndInventoryList
+ List craftresult 1
+ Empty
+ EndInventoryList
+ EndInventory
+
+Map File Format
+================
+
+Minetest maps consist of MapBlocks, chunks of 16x16x16 nodes.
+
+In addition to the bulk node data, MapBlocks stored on disk also contain
+other things.
+
+History
+--------
+We need a bit of history in here. Initially Minetest stored maps in a
+format called the "sectors" format. It was a directory/file structure like
+this:
+ sectors2/XXX/ZZZ/YYYY
+For example, the MapBlock at (0,1,-2) was this file:
+ sectors2/000/ffd/0001
+
+Eventually Minetest outgrow this directory structure, as filesystems were
+struggling under the amount of files and directories.
+
+Large servers seriously needed a new format, and thus the base of the
+current format was invented, suggested by celeron55 and implemented by
+JacobF.
+
+SQLite3 was slammed in, and blocks files were directly inserted as blobs
+in a single table, indexed by integer primary keys, oddly mangled from
+coordinates.
+
+Today we know that SQLite3 allows multiple primary keys (which would allow
+storing coordinates separately), but the format has been kept unchanged for
+that part. So, this is where it has come.
+</history>
+
+So here goes
+-------------
+map.sqlite is an sqlite3 database, containg a single table, called
+"blocks". It looks like this:
+
+ CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY,`data` BLOB);
+
+The key
+--------
+"pos" is created from the three coordinates of a MapBlock using this
+algorithm, defined here in Python:
+
+ def getBlockAsInteger(p):
+ return int64(p[2]*16777216 + p[1]*4096 + p[0])
+
+ def int64(u):
+ while u >= 2**63:
+ u -= 2**64
+ while u <= -2**63:
+ u += 2**64
+ return u
+
+It can be converted the other way by using this code:
+
+ def getIntegerAsBlock(i):
+ x = unsignedToSigned(i % 4096, 2048)
+ i = int((i - x) / 4096)
+ y = unsignedToSigned(i % 4096, 2048)
+ i = int((i - y) / 4096)
+ z = unsignedToSigned(i % 4096, 2048)
+ return x,y,z
+
+ def unsignedToSigned(i, max_positive):
+ if i < max_positive:
+ return i
+ else:
+ return i - 2*max_positive
+
+The blob
+---------
+The blob is the data that would have otherwise gone into the file.
+
+See below for description.
+
+MapBlock serialization format
+==============================
+NOTE: Byte order is MSB first (big-endian).
+NOTE: Zlib data is in such a format that Python's zlib at least can
+ directly decompress.
+
+u8 version
+- map format version number, this one is version 22
+
+u8 flags
+- Flag bitmasks:
+ - 0x01: is_underground: Should be set to 0 if there will be no light
+ obstructions above the block. If/when sunlight of a block is updated
+ and there is no block above it, this value is checked for determining
+ whether sunlight comes from the top.
+ - 0x02: day_night_differs: Whether the lighting of the block is different
+ on day and night. Only blocks that have this bit set are updated when
+ day transforms to night.
+ - 0x04: lighting_expired: If true, lighting is invalid and should be
+ updated. If you can't calculate lighting in your generator properly,
+ you could try setting this 1 to everything and setting the uppermost
+ block in every sector as is_underground=0. I am quite sure it doesn't
+ work properly, though.
+ - 0x08: generated: True if the block has been generated. If false, block
+ is mostly filled with CONTENT_IGNORE and is likely to contain eg. parts
+ of trees of neighboring blocks.
+
+u8 content_width
+- Number of bytes in the content (param0) fields of nodes
+if map format version <= 23:
+ - Always 1
+if map format version >= 24:
+ - Always 2
+
+u8 params_width
+- Number of bytes used for parameters per node
+- Always 2
+
+zlib-compressed node data:
+if content_width == 1:
+ - content:
+ u8[4096]: param0 fields
+ u8[4096]: param1 fields
+ u8[4096]: param2 fields
+if content_width == 2:
+ - content:
+ u16[4096]: param0 fields
+ u8[4096]: param1 fields
+ u8[4096]: param2 fields
+- The location of a node in each of those arrays is (z*16*16 + y*16 + x).
+
+zlib-compressed node metadata list
+- content:
+ u16 version (=1)
+ u16 count of metadata
+ foreach count:
+ u16 position (p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)
+ u16 type_id
+ u16 content_size
+ u8[content_size] (content of metadata)
+
+- Node timers
+if map format version == 23:
+ u8 unused version (always 0)
+if map format version == 24: (NOTE: Not released as stable)
+ u8 nodetimer_version
+ if nodetimer_version == 0:
+ (nothing else)
+ if nodetimer_version == 1:
+ u16 num_of_timers
+ foreach num_of_timers:
+ u16 timer position (z*16*16 + y*16 + x)
+ s32 timeout*1000
+ s32 elapsed*1000