mcworldlib


Namemcworldlib JSON
Version 2023.7.13 PyPI version JSON
download
home_pagehttps://github.com/MestreLion/mcworldlib
SummaryYet another python library to manipulate Minecraft save data
upload_time2023-07-13 05:40:22
maintainer
docs_urlNone
authorRodrigo Silva (MestreLion)
requires_python>=3.8
licenseGPLv3+
keywords minecraft save nbt chunk region world library
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # mcworldlib - Minecraft World Library

Yet another library to manipulate Minecraft data, inspired by the now-defunct
[pymclevel](https://github.com/mcedit/pymclevel), building on top of the amazing
[nbtlib](https://github.com/vberlier/nbtlib).

Focused on making the bridge between the on-disk save files and directory structure
and their NBT content, much like [NBTExplorer](https://github.com/jaquadro/NBTExplorer),
presenting all World data in a structured, convenient way so other tools can build
on top of it and add more _semantics_ to that data.

---
Features
--------
- Read and write `.dat` [NBT](https://minecraft.fandom.com/wiki/NBT_format)
  files, both uncompressed and gzip-compressed.
- Read and write `.mca`/`.mcr` [Anvil](https://minecraft.fandom.com/wiki/Anvil_file_format)
  region files, lazily loading their contents only when the data is actually
  requested, also monitoring content changes to efficiently save back to disk
  only the needed files.
- Read and write `.mcc` [external](https://www.reddit.com/r/technicalminecraft/comments/e4wxb6)
  chunk files, loading from there when indicated by the chunk header in the `.mca`
  region file, and automatically selecting the appropriate format on save:
  external `mcc` if the chunk data outgrows its previous maximum size (~1 MB),
  and back to the `mca` if it shrinks enough to fit there again.

---
Usage
-----

### Reading world data

You can open a Minecraft World by several ways:
- Path to a `level.dat` _**file**_, or its open file-like _**stream**_ object;
- Path to a world _**directory**_, containing the `level.dat` file at its root,
  as in the example below;
- World _**name**_, i.e, the directory basename of a world in the platform-dependent
  default Minecraft `saves/` path. By default, it is the in-game world name.

```pycon
>>> import mcworldlib as mc
>>> world = mc.load('data/New World')
>>> # Most classes have a pretty print. In many cases, their NBT data.
>>> mc.pretty(world.level)
{
    Data: {
        WanderingTraderSpawnChance: 25,
        BorderCenterZ: 0.0d,
        Difficulty: 2b,
        ...
        SpawnAngle: 0.0f,
        version: 19133,
        BorderSafeZone: 5.0d,
        LastPlayed: 1633981265600L,
        BorderWarningTime: 15.0d,
        ScheduledEvents: [],
        LevelName: "New World",
        BorderSize: 59999968.0d,
        DataVersion: 2730,
        DataPacks: {
            Enabled: ["vanilla"],
            Disabled: ["Fabric Mods"]
        }
    }
}

```

`World.dimensions` is a dictionary mapping each dimension to categorized Region files:
```pycon
>>> mc.pretty(world.dimensions)
{   <Dimension.OVERWORLD: 0>: {   'entities': <Regions(6 regions)>,
                                  'poi': <Regions(0 regions)>,
                                  'region': <Regions(6 regions)>},
    <Dimension.THE_NETHER: -1>: {   'entities': <Regions(0 regions)>,
                                    'poi': <Regions(0 regions)>,
                                    'region': <Regions(0 regions)>},
    <Dimension.THE_END: 1>: {   'entities': <Regions(0 regions)>,
                                'poi': <Regions(0 regions)>,
                                'region': <Regions(0 regions)>}}

```

And `World.regions` is handy view of that dictionary containing only the 'region'
category, similarly with `World.entities` and `World.poi`:
```pycon
>>> mc.pretty(world.regions)
{   <Dimension.OVERWORLD: 0>: <Regions(6 regions)>,
    <Dimension.THE_NETHER: -1>: <Regions(0 regions)>,
    <Dimension.THE_END: 1>: <Regions(0 regions)>}

>>> regions = world.regions[mc.OVERWORLD]
>>> regions is world.dimensions[mc.OVERWORLD]['region']
True

```

`Regions` is a dict-like collection of `.mca` Anvil region files, grouped in
"categories" that match their sub-folder in a given the dimension, such as
`/entities`, `/poi`, and of course `/region`.

The dictionary keys are region coordinate tuples, and the values represent Region
files. Files are lazily loaded, so initially the values contain only their path:

```pycon
>>> mc.pretty(regions)
{   ( -2, -1): PosixPath('data/New World/region/r.-2.-1.mca'),
    ( -2,  0): PosixPath('data/New World/region/r.-2.0.mca'),
    ( -1, -1): PosixPath('data/New World/region/r.-1.-1.mca'),
    ( -1,  0): PosixPath('data/New World/region/r.-1.0.mca'),
    (  0, -1): PosixPath('data/New World/region/r.0.-1.mca'),
    (  0,  0): PosixPath('data/New World/region/r.0.0.mca')}

```

They are automatically loaded when you first access them:
```pycon
>>> regions[0, 0]
<RegionFile(r.0.0.mca: 167 chunks)>

```

A `RegionFile` is a dictionary of chunks, and each `Chunk` contains its NBT data:

```pycon
>>> region = regions[-2, 0]
>>> mc.pretty(region)
{
    (  18,   0): <Chunk [18,  0] from Region ( -2,  0) in world at ( -46,   0) saved on 2021-10-11 16:39:17>,
    (  28,   0): <Chunk [28,  0] from Region ( -2,  0) in world at ( -36,   0) saved on 2021-10-11 16:40:50>,
    (  29,   0): <Chunk [29,  0] from Region ( -2,  0) in world at ( -35,   0) saved on 2021-10-11 16:40:50>,
    ...
    (  29,  31): <Chunk [29, 31] from Region ( -2,  0) in world at ( -35,  31) saved on 2021-10-11 16:40:14>,
    (  30,  31): <Chunk [30, 31] from Region ( -2,  0) in world at ( -34,  31) saved on 2021-10-11 16:40:14>,
    (  31,  31): <Chunk [31, 31] from Region ( -2,  0) in world at ( -33,  31) saved on 2021-10-11 16:40:14>
}

>>> chunk = region[30, 31]
>>> mc.pretty(chunk)  # alternatively, print(chunk.pretty())
{
    Level: {
        Status: "structure_starts",
        zPos: 31,
        LastUpdate: 4959L,
        InhabitedTime: 0L,
        xPos: -34,
        Heightmaps: {},
        TileEntities: [],
        Entities: [],
        ...
    },
    DataVersion: 2730
}

```

You can fetch a chunk by several means, using for example:
- Its key in their region dictionary, using relative coordinates, as the examples above.
- Their absolute _(cx, cz)_ chunk position: `world.get_chunk((cx, cz))`
- An absolute _(x, y, z)_ world position contained in it: `world.get_chunk_at((x, y, z))`
- The player current location: `world.player.get_chunk()`

```pycon
>>> for chunk in (
...     world.get_chunk((-34, 21)),
...     world.get_chunk_at((100, 60, 100)),
...     world.player.get_chunk(),
... ):
...     print(chunk)
...
<Chunk [30, 21] from Region ( -2,  0) in world at ( -34,  21) saved on 2021-10-11 16:40:50>
<Chunk [ 6,  6] from Region (  0,  0) in world at (   6,   6) saved on 2021-10-11 16:40:50>
<Chunk [18,  0] from Region ( -1,  0) in world at ( -14,   0) saved on 2021-10-11 16:40:48>

```

Get the block info at any coordinate:
```pycon
>>> block = world.get_block_at((100, 60, 100))
>>> print(block)
Compound({'Name': String('minecraft:stone')})

```

Remember the automatic, lazy-loading feature of `Regions`? In the above examples
a few chunks from distinct regions were accessed. So what is the state of the
`regions` dictionary now?

```pycon
>>> mc.pretty(regions)
  {   ( -2, -1): PosixPath('data/New World/region/r.-2.-1.mca'),
      ( -2,  0): <RegionFile(r.-2.0.mca: 133 chunks)>,
      ( -1, -1): PosixPath('data/New World/region/r.-1.-1.mca'),
      ( -1,  0): <RegionFile(r.-1.0.mca: 736 chunks)>,
      (  0, -1): PosixPath('data/New World/region/r.0.-1.mca'),
      (  0,  0): <RegionFile(r.0.0.mca: 167 chunks)>}

```

As promised, only the accessed region files were actually loaded, automatically.

### Editing world data

Reading and modifying the Player's inventory is quite easy:

```pycon
>>> inventory = world.player.inventory  # A handy shortcut
>>> inventory is world.level['Data']['Player']['Inventory']
True
>>> # Easily loop each item as if the inventory is a list. In fact, it *is*!
>>> for item in inventory:
...     print(f"Slot {item['Slot']:3}: {item['Count']:2} x {item['id']}")
Slot   0:  1 x minecraft:stone_axe
Slot   1:  1 x minecraft:stone_pickaxe
Slot   2:  1 x minecraft:wooden_axe
Slot   3:  1 x minecraft:stone_shovel
Slot   4:  1 x minecraft:crafting_table
Slot   5: 37 x minecraft:coal
Slot   6:  8 x minecraft:dirt
Slot  11:  2 x minecraft:oak_log
Slot  12:  5 x minecraft:cobblestone
Slot  13:  2 x minecraft:stick
Slot  28:  1 x minecraft:wooden_pickaxe

```

How about some **diamonds**?
Get 64 *blocks* of it in each one of your free inventory slots!

```pycon
>>> backup = mc.List[mc.Compound](inventory[:])  # soon just inventory.copy()
>>> free_slots = set(range(36)) - set(item['Slot'] for item in inventory)
>>> for slot in free_slots:
...     print(f"Adding 64 blocks of Diamond to inventory slot {slot}")
...     item = mc.Compound({
...         'Slot':  mc.Byte(slot),
...         'id':    mc.String('minecraft:diamond_block'),  # Sweet!
...         'Count': mc.Byte(64),  # Enough for you?
...     })
...     inventory.append(item)  # Yup, it's THAT simple!
...
Adding 64 blocks of Diamond to inventory slot 7
Adding 64 blocks of Diamond to inventory slot 8
Adding 64 blocks of Diamond to inventory slot 9
Adding 64 blocks of Diamond to inventory slot 10
Adding 64 blocks of Diamond to inventory slot 14
...
Adding 64 blocks of Diamond to inventory slot 35

>>> # Go on, we both know you want it. I won't judge you.
>>> world.save('data/tests/diamonds')

>>> # Revert it so it doesn't mess with other examples
>>> world.player.inventory = backup

```
Have fun, you millionaire!

More fun things to do:
```pycon
>>> chunks = world.entities[mc.OVERWORLD][0, 0]
>>> for chunk in chunks.values():
...     for entity in chunk.entities:
...         print(entity)
...
Chest Minecart at (  81,  18,  21)
Chest Minecart at (  80,  18,  37)
Chest Minecart at (   2,  38, 112)
Sheep at (  36,  70, 116)
Sheep at (  33,  69, 120)
Sheep at (  37,  70, 116)
Item: 3 String at (  14,  25, 152)
Item: 2 String at (  14,  25, 153)
Chicken at (  13,  64, 158)
Chicken at (  12,  64, 156)
Chicken at (   7,  64, 153)
Item: 1 String at (   0,  35, 167)
Cow at (   1,  65, 184)
Cow at (  11,  64, 186)
Chest Minecart at (  17,  32, 187)
Item: 3 String at (  39,  35, 195)
Donkey at (  56,  70, 202)
Donkey at (  57,  71, 203)
Donkey at (  56,  70, 201)
Chicken at (   6,  64, 217)

```

How about some NBT Explorer nostalgia?

```pycon
>>> mc.nbt_explorer(world.level)
⊟ Data: 42 entries
├──⊞ CustomBossEvents: 0 entries
├──⊟ DataPacks: 2 entries
│  ├──⊟ Disabled: 1 entry
│  │  ╰─── 0: Fabric Mods
│  ╰──⊟ Enabled: 1 entry
│     ╰─── 0: vanilla
...
├──⊟ Player: 37 entries
│  ├──⊟ abilities: 7 entries
│  │  ├─── flying: Byte(0)
...
│  │  ╰─── walkSpeed: Float(0.10000000149011612)
│  ├──⊟ Brain: 1 entry
│  │  ╰──⊞ memories: 0 entries
...
│  ├──⊟ Inventory: 11 entries
│  │  ├──⊟  0: 4 entries
│  │  │  ├──⊟ tag: 1 entry
│  │  │  │  ╰─── Damage: Int(0)
│  │  │  ├─── Count: Byte(1)
│  │  │  ├─── id: minecraft:stone_axe
│  │  │  ╰─── Slot: Byte(0)
...
│  │  ╰──⊟ 10: 4 entries
│  │     ├──⊟ tag: 1 entry
│  │     │  ╰─── Damage: Int(18)
│  │     ├─── Count: Byte(1)
│  │     ├─── id: minecraft:wooden_pickaxe
│  │     ╰─── Slot: Byte(28)
...
│  ├─── XpTotal: Int(37)
│  ╰──⊕ UUID: 4 entries
├──⊟ Version: 3 entries
│  ├─── Id: Int(2730)
│  ├─── Name: 1.17.1
│  ╰─── Snapshot: Byte(0)
...
├──⊞ ScheduledEvents: 0 entries
├──⊟ ServerBrands: 1 entry
│  ╰─── 0: fabric
├─── allowCommands: Byte(0)
...
├─── WanderingTraderSpawnDelay: Int(19200)
╰─── WasModded: Byte(1)

```
You want to click that tree, don't you? Sweet `Array` "icon" for `UUID`!

Test yourself all the examples in this document:

    python3 -m doctest -f -o ELLIPSIS -o NORMALIZE_WHITESPACE README.md
    git checkout data/

---
Contributing
------------

Patches are welcome! Fork, hack, request pull! Here is a succinct to-do list:

- **Better documentation**: Improve this `README`, document classes, methods and
  attributes, perhaps adding sphinx-like in-code documentation, possibly hosting
  at [Read the Docs](https://readthedocs.org/). Add more in-depth usage scenarios.

- **Installer**: Test and improve current `setup.cfg`, possibly uploading to Pypi.

- **Tests**: Expand [doctest](https://docs.python.org/3/library/doctest.html)
  usage, add at least [unittest](https://docs.python.org/3/library/unittest.html).

- **Semantics**: Give semantics to some NBT data, providing methods to manipulate
  blocks, entities and so on.

- **CLI**: Add a command-line interface for commonly used operations.

See the [To-Do List](./TODO.txt) for more updated technical information and
planned features.

If you find a bug or have any enhancement request, please open a
[new issue](https://github.com/MestreLion/mcworldlib/issues/new)


Author
------

Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>

License and Copyright
---------------------
```
Copyright (C) 2019 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/MestreLion/mcworldlib",
    "name": "mcworldlib",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "minecraft,save,nbt,chunk,region,world,library",
    "author": "Rodrigo Silva (MestreLion)",
    "author_email": "minecraft@rodrigosilva.com",
    "download_url": "https://files.pythonhosted.org/packages/a6/8d/af7c81d7ee72bc49172bd4cd12a75f0a450d2db3e884c3fc8a4506d95614/mcworldlib-2023.7.13.tar.gz",
    "platform": null,
    "description": "# mcworldlib - Minecraft World Library\n\nYet another library to manipulate Minecraft data, inspired by the now-defunct\n[pymclevel](https://github.com/mcedit/pymclevel), building on top of the amazing\n[nbtlib](https://github.com/vberlier/nbtlib).\n\nFocused on making the bridge between the on-disk save files and directory structure\nand their NBT content, much like [NBTExplorer](https://github.com/jaquadro/NBTExplorer),\npresenting all World data in a structured, convenient way so other tools can build\non top of it and add more _semantics_ to that data.\n\n---\nFeatures\n--------\n- Read and write `.dat` [NBT](https://minecraft.fandom.com/wiki/NBT_format)\n  files, both uncompressed and gzip-compressed.\n- Read and write `.mca`/`.mcr` [Anvil](https://minecraft.fandom.com/wiki/Anvil_file_format)\n  region files, lazily loading their contents only when the data is actually\n  requested, also monitoring content changes to efficiently save back to disk\n  only the needed files.\n- Read and write `.mcc` [external](https://www.reddit.com/r/technicalminecraft/comments/e4wxb6)\n  chunk files, loading from there when indicated by the chunk header in the `.mca`\n  region file, and automatically selecting the appropriate format on save:\n  external `mcc` if the chunk data outgrows its previous maximum size (~1\u00a0MB),\n  and back to the `mca` if it shrinks enough to fit there again.\n\n---\nUsage\n-----\n\n### Reading world data\n\nYou can open a Minecraft World by several ways:\n- Path to a `level.dat` _**file**_, or its open file-like _**stream**_ object;\n- Path to a world _**directory**_, containing the `level.dat` file at its root,\n  as in the example below;\n- World _**name**_, i.e, the directory basename of a world in the platform-dependent\n  default Minecraft `saves/` path. By default, it is the in-game world name.\n\n```pycon\n>>> import mcworldlib as mc\n>>> world = mc.load('data/New World')\n>>> # Most classes have a pretty print. In many cases, their NBT data.\n>>> mc.pretty(world.level)\n{\n    Data: {\n        WanderingTraderSpawnChance: 25,\n        BorderCenterZ: 0.0d,\n        Difficulty: 2b,\n        ...\n        SpawnAngle: 0.0f,\n        version: 19133,\n        BorderSafeZone: 5.0d,\n        LastPlayed: 1633981265600L,\n        BorderWarningTime: 15.0d,\n        ScheduledEvents: [],\n        LevelName: \"New World\",\n        BorderSize: 59999968.0d,\n        DataVersion: 2730,\n        DataPacks: {\n            Enabled: [\"vanilla\"],\n            Disabled: [\"Fabric Mods\"]\n        }\n    }\n}\n\n```\n\n`World.dimensions` is a dictionary mapping each dimension to categorized Region files:\n```pycon\n>>> mc.pretty(world.dimensions)\n{   <Dimension.OVERWORLD: 0>: {   'entities': <Regions(6 regions)>,\n                                  'poi': <Regions(0 regions)>,\n                                  'region': <Regions(6 regions)>},\n    <Dimension.THE_NETHER: -1>: {   'entities': <Regions(0 regions)>,\n                                    'poi': <Regions(0 regions)>,\n                                    'region': <Regions(0 regions)>},\n    <Dimension.THE_END: 1>: {   'entities': <Regions(0 regions)>,\n                                'poi': <Regions(0 regions)>,\n                                'region': <Regions(0 regions)>}}\n\n```\n\nAnd `World.regions` is handy view of that dictionary containing only the 'region'\ncategory, similarly with `World.entities` and `World.poi`:\n```pycon\n>>> mc.pretty(world.regions)\n{   <Dimension.OVERWORLD: 0>: <Regions(6 regions)>,\n    <Dimension.THE_NETHER: -1>: <Regions(0 regions)>,\n    <Dimension.THE_END: 1>: <Regions(0 regions)>}\n\n>>> regions = world.regions[mc.OVERWORLD]\n>>> regions is world.dimensions[mc.OVERWORLD]['region']\nTrue\n\n```\n\n`Regions` is a dict-like collection of `.mca` Anvil region files, grouped in\n\"categories\" that match their sub-folder in a given the dimension, such as\n`/entities`, `/poi`, and of course `/region`.\n\nThe dictionary keys are region coordinate tuples, and the values represent Region\nfiles. Files are lazily loaded, so initially the values contain only their path:\n\n```pycon\n>>> mc.pretty(regions)\n{   ( -2, -1): PosixPath('data/New World/region/r.-2.-1.mca'),\n    ( -2,  0): PosixPath('data/New World/region/r.-2.0.mca'),\n    ( -1, -1): PosixPath('data/New World/region/r.-1.-1.mca'),\n    ( -1,  0): PosixPath('data/New World/region/r.-1.0.mca'),\n    (  0, -1): PosixPath('data/New World/region/r.0.-1.mca'),\n    (  0,  0): PosixPath('data/New World/region/r.0.0.mca')}\n\n```\n\nThey are automatically loaded when you first access them:\n```pycon\n>>> regions[0, 0]\n<RegionFile(r.0.0.mca: 167 chunks)>\n\n```\n\nA `RegionFile` is a dictionary of chunks, and each `Chunk` contains its NBT data:\n\n```pycon\n>>> region = regions[-2, 0]\n>>> mc.pretty(region)\n{\n    (  18,   0): <Chunk [18,  0] from Region ( -2,  0) in world at ( -46,   0) saved on 2021-10-11 16:39:17>,\n    (  28,   0): <Chunk [28,  0] from Region ( -2,  0) in world at ( -36,   0) saved on 2021-10-11 16:40:50>,\n    (  29,   0): <Chunk [29,  0] from Region ( -2,  0) in world at ( -35,   0) saved on 2021-10-11 16:40:50>,\n    ...\n    (  29,  31): <Chunk [29, 31] from Region ( -2,  0) in world at ( -35,  31) saved on 2021-10-11 16:40:14>,\n    (  30,  31): <Chunk [30, 31] from Region ( -2,  0) in world at ( -34,  31) saved on 2021-10-11 16:40:14>,\n    (  31,  31): <Chunk [31, 31] from Region ( -2,  0) in world at ( -33,  31) saved on 2021-10-11 16:40:14>\n}\n\n>>> chunk = region[30, 31]\n>>> mc.pretty(chunk)  # alternatively, print(chunk.pretty())\n{\n    Level: {\n        Status: \"structure_starts\",\n        zPos: 31,\n        LastUpdate: 4959L,\n        InhabitedTime: 0L,\n        xPos: -34,\n        Heightmaps: {},\n        TileEntities: [],\n        Entities: [],\n        ...\n    },\n    DataVersion: 2730\n}\n\n```\n\nYou can fetch a chunk by several means, using for example:\n- Its key in their region dictionary, using relative coordinates, as the examples above.\n- Their absolute _(cx, cz)_ chunk position: `world.get_chunk((cx, cz))`\n- An absolute _(x, y, z)_ world position contained in it: `world.get_chunk_at((x, y, z))`\n- The player current location: `world.player.get_chunk()`\n\n```pycon\n>>> for chunk in (\n...     world.get_chunk((-34, 21)),\n...     world.get_chunk_at((100, 60, 100)),\n...     world.player.get_chunk(),\n... ):\n...     print(chunk)\n...\n<Chunk [30, 21] from Region ( -2,  0) in world at ( -34,  21) saved on 2021-10-11 16:40:50>\n<Chunk [ 6,  6] from Region (  0,  0) in world at (   6,   6) saved on 2021-10-11 16:40:50>\n<Chunk [18,  0] from Region ( -1,  0) in world at ( -14,   0) saved on 2021-10-11 16:40:48>\n\n```\n\nGet the block info at any coordinate:\n```pycon\n>>> block = world.get_block_at((100, 60, 100))\n>>> print(block)\nCompound({'Name': String('minecraft:stone')})\n\n```\n\nRemember the automatic, lazy-loading feature of `Regions`? In the above examples\na few chunks from distinct regions were accessed. So what is the state of the\n`regions` dictionary now?\n\n```pycon\n>>> mc.pretty(regions)\n  {   ( -2, -1): PosixPath('data/New World/region/r.-2.-1.mca'),\n      ( -2,  0): <RegionFile(r.-2.0.mca: 133 chunks)>,\n      ( -1, -1): PosixPath('data/New World/region/r.-1.-1.mca'),\n      ( -1,  0): <RegionFile(r.-1.0.mca: 736 chunks)>,\n      (  0, -1): PosixPath('data/New World/region/r.0.-1.mca'),\n      (  0,  0): <RegionFile(r.0.0.mca: 167 chunks)>}\n\n```\n\nAs promised, only the accessed region files were actually loaded, automatically.\n\n### Editing world data\n\nReading and modifying the Player's inventory is quite easy:\n\n```pycon\n>>> inventory = world.player.inventory  # A handy shortcut\n>>> inventory is world.level['Data']['Player']['Inventory']\nTrue\n>>> # Easily loop each item as if the inventory is a list. In fact, it *is*!\n>>> for item in inventory:\n...     print(f\"Slot {item['Slot']:3}: {item['Count']:2} x {item['id']}\")\nSlot   0:  1 x minecraft:stone_axe\nSlot   1:  1 x minecraft:stone_pickaxe\nSlot   2:  1 x minecraft:wooden_axe\nSlot   3:  1 x minecraft:stone_shovel\nSlot   4:  1 x minecraft:crafting_table\nSlot   5: 37 x minecraft:coal\nSlot   6:  8 x minecraft:dirt\nSlot  11:  2 x minecraft:oak_log\nSlot  12:  5 x minecraft:cobblestone\nSlot  13:  2 x minecraft:stick\nSlot  28:  1 x minecraft:wooden_pickaxe\n\n```\n\nHow about some **diamonds**?\nGet 64 *blocks* of it in each one of your free inventory slots!\n\n```pycon\n>>> backup = mc.List[mc.Compound](inventory[:])  # soon just inventory.copy()\n>>> free_slots = set(range(36)) - set(item['Slot'] for item in inventory)\n>>> for slot in free_slots:\n...     print(f\"Adding 64 blocks of Diamond to inventory slot {slot}\")\n...     item = mc.Compound({\n...         'Slot':  mc.Byte(slot),\n...         'id':    mc.String('minecraft:diamond_block'),  # Sweet!\n...         'Count': mc.Byte(64),  # Enough for you?\n...     })\n...     inventory.append(item)  # Yup, it's THAT simple!\n...\nAdding 64 blocks of Diamond to inventory slot 7\nAdding 64 blocks of Diamond to inventory slot 8\nAdding 64 blocks of Diamond to inventory slot 9\nAdding 64 blocks of Diamond to inventory slot 10\nAdding 64 blocks of Diamond to inventory slot 14\n...\nAdding 64 blocks of Diamond to inventory slot 35\n\n>>> # Go on, we both know you want it. I won't judge you.\n>>> world.save('data/tests/diamonds')\n\n>>> # Revert it so it doesn't mess with other examples\n>>> world.player.inventory = backup\n\n```\nHave fun, you millionaire!\n\nMore fun things to do:\n```pycon\n>>> chunks = world.entities[mc.OVERWORLD][0, 0]\n>>> for chunk in chunks.values():\n...     for entity in chunk.entities:\n...         print(entity)\n...\nChest Minecart at (  81,  18,  21)\nChest Minecart at (  80,  18,  37)\nChest Minecart at (   2,  38, 112)\nSheep at (  36,  70, 116)\nSheep at (  33,  69, 120)\nSheep at (  37,  70, 116)\nItem: 3 String at (  14,  25, 152)\nItem: 2 String at (  14,  25, 153)\nChicken at (  13,  64, 158)\nChicken at (  12,  64, 156)\nChicken at (   7,  64, 153)\nItem: 1 String at (   0,  35, 167)\nCow at (   1,  65, 184)\nCow at (  11,  64, 186)\nChest Minecart at (  17,  32, 187)\nItem: 3 String at (  39,  35, 195)\nDonkey at (  56,  70, 202)\nDonkey at (  57,  71, 203)\nDonkey at (  56,  70, 201)\nChicken at (   6,  64, 217)\n\n```\n\nHow about some NBT Explorer nostalgia?\n\n```pycon\n>>> mc.nbt_explorer(world.level)\n\u229f Data: 42 entries\n\u251c\u2500\u2500\u229e CustomBossEvents: 0 entries\n\u251c\u2500\u2500\u229f DataPacks: 2 entries\n\u2502  \u251c\u2500\u2500\u229f Disabled: 1 entry\n\u2502  \u2502  \u2570\u2500\u2500\u2500 0: Fabric Mods\n\u2502  \u2570\u2500\u2500\u229f Enabled: 1 entry\n\u2502     \u2570\u2500\u2500\u2500 0: vanilla\n...\n\u251c\u2500\u2500\u229f Player: 37 entries\n\u2502  \u251c\u2500\u2500\u229f abilities: 7 entries\n\u2502  \u2502  \u251c\u2500\u2500\u2500 flying: Byte(0)\n...\n\u2502  \u2502  \u2570\u2500\u2500\u2500 walkSpeed: Float(0.10000000149011612)\n\u2502  \u251c\u2500\u2500\u229f Brain: 1 entry\n\u2502  \u2502  \u2570\u2500\u2500\u229e memories: 0 entries\n...\n\u2502  \u251c\u2500\u2500\u229f Inventory: 11 entries\n\u2502  \u2502  \u251c\u2500\u2500\u229f  0: 4 entries\n\u2502  \u2502  \u2502  \u251c\u2500\u2500\u229f tag: 1 entry\n\u2502  \u2502  \u2502  \u2502  \u2570\u2500\u2500\u2500 Damage: Int(0)\n\u2502  \u2502  \u2502  \u251c\u2500\u2500\u2500 Count: Byte(1)\n\u2502  \u2502  \u2502  \u251c\u2500\u2500\u2500 id: minecraft:stone_axe\n\u2502  \u2502  \u2502  \u2570\u2500\u2500\u2500 Slot: Byte(0)\n...\n\u2502  \u2502  \u2570\u2500\u2500\u229f 10: 4 entries\n\u2502  \u2502     \u251c\u2500\u2500\u229f tag: 1 entry\n\u2502  \u2502     \u2502  \u2570\u2500\u2500\u2500 Damage: Int(18)\n\u2502  \u2502     \u251c\u2500\u2500\u2500 Count: Byte(1)\n\u2502  \u2502     \u251c\u2500\u2500\u2500 id: minecraft:wooden_pickaxe\n\u2502  \u2502     \u2570\u2500\u2500\u2500 Slot: Byte(28)\n...\n\u2502  \u251c\u2500\u2500\u2500 XpTotal: Int(37)\n\u2502  \u2570\u2500\u2500\u2295 UUID: 4 entries\n\u251c\u2500\u2500\u229f Version: 3 entries\n\u2502  \u251c\u2500\u2500\u2500 Id: Int(2730)\n\u2502  \u251c\u2500\u2500\u2500 Name: 1.17.1\n\u2502  \u2570\u2500\u2500\u2500 Snapshot: Byte(0)\n...\n\u251c\u2500\u2500\u229e ScheduledEvents: 0 entries\n\u251c\u2500\u2500\u229f ServerBrands: 1 entry\n\u2502  \u2570\u2500\u2500\u2500 0: fabric\n\u251c\u2500\u2500\u2500 allowCommands: Byte(0)\n...\n\u251c\u2500\u2500\u2500 WanderingTraderSpawnDelay: Int(19200)\n\u2570\u2500\u2500\u2500 WasModded: Byte(1)\n\n```\nYou want to click that tree, don't you? Sweet `Array` \"icon\" for `UUID`!\n\nTest yourself all the examples in this document:\n\n    python3 -m doctest -f -o ELLIPSIS -o NORMALIZE_WHITESPACE README.md\n    git checkout data/\n\n---\nContributing\n------------\n\nPatches are welcome! Fork, hack, request pull! Here is a succinct to-do list:\n\n- **Better documentation**: Improve this `README`, document classes, methods and\n  attributes, perhaps adding sphinx-like in-code documentation, possibly hosting\n  at [Read the Docs](https://readthedocs.org/). Add more in-depth usage scenarios.\n\n- **Installer**: Test and improve current `setup.cfg`, possibly uploading to Pypi.\n\n- **Tests**: Expand [doctest](https://docs.python.org/3/library/doctest.html)\n  usage, add at least [unittest](https://docs.python.org/3/library/unittest.html).\n\n- **Semantics**: Give semantics to some NBT data, providing methods to manipulate\n  blocks, entities and so on.\n\n- **CLI**: Add a command-line interface for commonly used operations.\n\nSee the [To-Do List](./TODO.txt) for more updated technical information and\nplanned features.\n\nIf you find a bug or have any enhancement request, please open a\n[new issue](https://github.com/MestreLion/mcworldlib/issues/new)\n\n\nAuthor\n------\n\nRodrigo Silva (MestreLion) <linux@rodrigosilva.com>\n\nLicense and Copyright\n---------------------\n```\nCopyright (C) 2019 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>.\n\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\nThis is free software: you are free to change and redistribute it.\n\nThere is NO WARRANTY, to the extent permitted by law.\n```\n",
    "bugtrack_url": null,
    "license": "GPLv3+",
    "summary": "Yet another python library to manipulate Minecraft save data",
    "version": "2023.7.13",
    "project_urls": {
        "Bug Tracker": "https://github.com/MestreLion/mcworldlib/issues",
        "Homepage": "https://github.com/MestreLion/mcworldlib",
        "Source Code": "https://github.com/MestreLion/mcworldlib"
    },
    "split_keywords": [
        "minecraft",
        "save",
        "nbt",
        "chunk",
        "region",
        "world",
        "library"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "eca55f0fd7bd18a625008a200c1b0b34d33353be7f63ab9d79cfdbad6531d964",
                "md5": "f1f92f14b738fb907fa511fc285f0c04",
                "sha256": "038f483a1bb2f962b84911502b0258e45c69a566efcbd30d5f90ffb123648ed0"
            },
            "downloads": -1,
            "filename": "mcworldlib-2023.7.13-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f1f92f14b738fb907fa511fc285f0c04",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 46887,
            "upload_time": "2023-07-13T05:40:57",
            "upload_time_iso_8601": "2023-07-13T05:40:57.085001Z",
            "url": "https://files.pythonhosted.org/packages/ec/a5/5f0fd7bd18a625008a200c1b0b34d33353be7f63ab9d79cfdbad6531d964/mcworldlib-2023.7.13-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a68daf7c81d7ee72bc49172bd4cd12a75f0a450d2db3e884c3fc8a4506d95614",
                "md5": "8a6f9fee38aed043deecb0e19af6ff46",
                "sha256": "801fb6c77ac209b2ca47ae6b99009c0fc87e0c1992d1bf375e2412d98f00718c"
            },
            "downloads": -1,
            "filename": "mcworldlib-2023.7.13.tar.gz",
            "has_sig": false,
            "md5_digest": "8a6f9fee38aed043deecb0e19af6ff46",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 48102,
            "upload_time": "2023-07-13T05:40:22",
            "upload_time_iso_8601": "2023-07-13T05:40:22.763131Z",
            "url": "https://files.pythonhosted.org/packages/a6/8d/af7c81d7ee72bc49172bd4cd12a75f0a450d2db3e884c3fc8a4506d95614/mcworldlib-2023.7.13.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-13 05:40:22",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "MestreLion",
    "github_project": "mcworldlib",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "mcworldlib"
}
        
Elapsed time: 0.10860s