123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609 |
- =============================
- Minetest World Format 22...25
- =============================
- This applies to a world format carrying the block serialization version
- 22...25, used at least in
- - 0.4.dev-20120322 ... 0.4.dev-20120606 (22...23)
- - 0.4.0 (23)
- - 24 was never released as stable and existed for ~2 days
- The block serialization version does not fully specify every aspect of this
- format; if compliance with this format is to be checked, it needs to be
- done by detecting if the files and data indeed follows it.
- Legacy stuff
- =============
- Data can, in theory, be contained in the flat file directory structure
- described below in Version 17, but it is not officially supported. Also you
- may stumble upon all kinds of oddities in not-so-recent formats.
- Files
- ======
- Everything is contained in a directory, the name of which is freeform, but
- often serves as the name of the world.
- Currently the authentication and ban data is stored on a per-world basis.
- It can be copied over from an old world to a newly created world.
- World
- |-- auth.txt ----- Authentication data
- |-- env_meta.txt - Environment metadata
- |-- ipban.txt ---- Banned ips/users
- |-- map_meta.txt - Map metadata
- |-- map.sqlite --- Map data
- |-- players ------ Player directory
- | |-- player1 -- Player file
- | '-- Foo ------ Player file
- `-- world.mt ----- World metadata
- auth.txt
- ---------
- Contains authentication data, player per line.
- <name>:<password hash>:<privilege1,...>
- Legacy format (until 0.4.12) of password hash is <name><password> SHA1'd,
- in the base64 encoding.
- Format (since 0.4.13) of password hash is #1#<salt>#<verifier>, with the
- parts inside <> encoded in the base64 encoding.
- <verifier> is an RFC 2945 compatible SRP verifier,
- of the given salt, password, and the player's name lowercased,
- using the 2048-bit group specified in RFC 5054 and the SHA-256 hash function.
- Example lines:
- - Player "celeron55", no password, privileges "interact" and "shout":
- celeron55::interact,shout
- - Player "Foo", password "bar", privilege "shout", with a legacy password hash:
- foo:iEPX+SQWIR3p67lj/0zigSWTKHg:shout
- - Player "Foo", password "bar", privilege "shout", with a 0.4.13 pw hash:
- foo:#1#hPpy4O3IAn1hsNK00A6wNw#Kpu6rj7McsrPCt4euTb5RA5ltF7wdcWGoYMcRngwDi11cZhPuuR9i5Bo7o6A877TgcEwoc//HNrj9EjR/CGjdyTFmNhiermZOADvd8eu32FYK1kf7RMC0rXWxCenYuOQCG4WF9mMGiyTPxC63VAjAMuc1nCZzmy6D9zt0SIKxOmteI75pAEAIee2hx4OkSXRIiU4Zrxo1Xf7QFxkMY4x77vgaPcvfmuzom0y/fU1EdSnZeopGPvzMpFx80ODFx1P34R52nmVl0W8h4GNo0k8ZiWtRCdrJxs8xIg7z5P1h3Th/BJ0lwexpdK8sQZWng8xaO5ElthNuhO8UQx1l6FgEA:shout
- - Player "bar", no password, no privileges:
- bar::
- env_meta.txt
- -------------
- Simple global environment variables.
- Example content (added indentation):
- game_time = 73471
- time_of_day = 19118
- EnvArgsEnd
- ipban.txt
- ----------
- 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, containing 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, see serialisation.h for the latest number
- 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:
- if map format version <= 22:
- 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. Format depends on type_id, see below.
- if map format version >= 23:
- u8 version (=1) -- Note the type is u8, while for map format version <= 22 it's u16
- u16 count of metadata
- foreach count:
- u16 position (p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)
- u32 num_vars
- foreach num_vars:
- u16 key_len
- u8[key_len] key
- u32 val_len
- u8[val_len] value
- serialized inventory
- - 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
- if map format version >= 25:
- -- Nothing right here, node timers are serialized later
- u8 static object version:
- - Always 0
- u16 static_object_count
- foreach static_object_count:
- u8 type (object type-id)
- s32 pos_x_nodes * 10000
- s32 pos_y_nodes * 10000
- s32 pos_z_nodes * 10000
- u16 data_size
- u8[data_size] data
- u32 timestamp
- - Timestamp when last saved, as seconds from starting the game.
- - 0xffffffff = invalid/unknown timestamp, nothing should be done with the time
- difference when loaded
- u8 name-id-mapping version
- - Always 0
- u16 num_name_id_mappings
- foreach num_name_id_mappings
- u16 id
- u16 name_len
- u8[name_len] name
- - Node timers
- if map format version == 25:
- u8 length of the data of a single timer (always 2+4+4=10)
- u16 num_of_timers
- foreach num_of_timers:
- u16 timer position (z*16*16 + y*16 + x)
- s32 timeout*1000
- s32 elapsed*1000
- EOF.
- Format of nodes
- ----------------
- A node is composed of the u8 fields param0, param1 and param2.
- if map format version <= 23:
- The content id of a node is determined as so:
- - If param0 < 0x80,
- content_id = param0
- - Otherwise
- content_id = (param0<<4) + (param2>>4)
- if map format version >= 24:
- The content id of a node is param0.
- The purpose of param1 and param2 depend on the definition of the node.
- The name-id-mapping
- --------------------
- The mapping maps node content ids to node names.
- Node metadata format for map format versions <= 22
- ---------------------------------------------------
- The node metadata are serialized depending on the type_id field.
- 1: Generic metadata
- serialized inventory
- u32 len
- u8[len] text
- u16 len
- u8[len] owner
- u16 len
- u8[len] infotext
- u16 len
- u8[len] inventory drawspec
- u8 allow_text_input (bool)
- u8 removal_disabled (bool)
- u8 enforce_owner (bool)
- u32 num_vars
- foreach num_vars
- u16 len
- u8[len] name
- u32 len
- u8[len] value
- 14: Sign metadata
- u16 text_len
- u8[text_len] text
- 15: Chest metadata
- serialized inventory
- 16: Furnace metadata
- TBD
- 17: Locked Chest metadata
- u16 len
- u8[len] owner
- serialized inventory
- Static objects
- ---------------
- Static objects are persistent freely moving objects in the world.
- Object types:
- 1: Test object
- 2: Item
- 3: Rat (deprecated)
- 4: Oerkki (deprecated)
- 5: Firefly (deprecated)
- 6: MobV2 (deprecated)
- 7: LuaEntity
- 1: Item:
- u8 version
- version 0:
- u16 len
- u8[len] itemstring
- 7: LuaEntity:
- u8 version
- version 1:
- u16 len
- u8[len] entity name
- u32 len
- u8[len] static data
- s16 hp
- s32 velocity.x * 10000
- s32 velocity.y * 10000
- s32 velocity.z * 10000
- s32 yaw * 1000
- Itemstring format
- ------------------
- eg. 'default:dirt 5'
- eg. 'default:pick_wood 21323'
- eg. '"default:apple" 2'
- eg. 'default:apple'
- - The wear value in tools is 0...65535
- - There are also a number of older formats that you might stumble upon:
- eg. 'node "default:dirt" 5'
- eg. 'NodeItem default:dirt 5'
- eg. 'ToolItem WPick 21323'
- Inventory serialization format
- -------------------------------
- - The inventory serialization format is line-based
- - The newline character used is "\n"
- - The end condition of a serialized inventory is always "EndInventory\n"
- - All the slots in a list must always be serialized.
- Example (format does not include "---"):
- ---
- List foo 4
- Item default:sapling
- Item default:sword_stone 1 10647
- Item default:dirt 99
- Empty
- EndInventoryList
- List bar 9
- Empty
- Empty
- Empty
- Empty
- Empty
- Empty
- Empty
- Empty
- Empty
- EndInventoryList
- EndInventory
- ---
- ==============================================
- Minetest World Format used as of 2011-05 or so
- ==============================================
- Map data serialization format version 17.
- 0.3.1 does not use this format, but a more recent one. This exists here for
- historical reasons.
- Directory structure:
- sectors/XXXXZZZZ or sectors2/XXX/ZZZ
- XXXX, ZZZZ, XXX and ZZZ being the hexadecimal X and Z coordinates.
- Under these, the block files are stored, called YYYY.
- There also exists files map_meta.txt and chunk_meta, that are used by the
- generator. If they are not found or invalid, the generator will currently
- behave quite strangely.
- The MapBlock file format (sectors2/XXX/ZZZ/YYYY):
- -------------------------------------------------
- NOTE: Byte order is MSB first.
- u8 version
- - map format version number, this one is version 17
- 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.
- zlib-compressed map data:
- - content:
- u8[4096]: content types
- u8[4096]: param1 values
- u8[4096]: param2 values
- zlib-compressed node metadata
- - 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] misc. stuff contained in the metadata
- u16 mapblockobject_count
- - always write as 0.
- - if read != 0, just fail.
- foreach mapblockobject_count:
- - deprecated, should not be used. Length of this data can only be known by
- properly parsing it. Just hope not to run into any of this.
- u8 static object version:
- - currently 0
- u16 static_object_count
- foreach static_object_count:
- u8 type (object type-id)
- s32 pos_x * 1000
- s32 pos_y * 1000
- s32 pos_z * 1000
- u16 data_size
- u8[data_size] data
- u32 timestamp
- - Timestamp when last saved, as seconds from starting the game.
- - 0xffffffff = invalid/unknown timestamp, nothing will be done with the time
- difference when loaded (recommended)
- Node metadata format:
- ---------------------
- Sign metadata:
- u16 string_len
- u8[string_len] string
- Furnace metadata:
- TBD
- Chest metadata:
- TBD
- Locking Chest metadata:
- u16 string_len
- u8[string_len] string
- TBD
- // END
|