/python-mtschem

Small Python library to read/write Minetest schematics

Primary LanguagePython

mtschem

Python Library providing Input/Output for Minetest Schematics (.mts), converting them into a Numpy array. Code by Gaël de Sailly, loosely based on python-minetest by LeMagnesium. License: GPLv2.

Installation

Download from GitHub:

  • using git: git clone https://github.com/Gael-de-Sailly/python-mtschem.git
  • or download directly the zip archive.

Then, using the command line, place yourself in python-mtschem directory. Install:

python3 setup.py install

You may need the administrator rights.

Basic use

Import the library

import mtschem

Load a schematic

my_schem = Schem("path/to/my_schem.mts")

data array

The data are stored in my_schem.data in the form of a X×Y×Z array of structured elements. To get the shape and the volume:

shape = my_schem.data.shape # 3-tuple
volume = my_schem.data.size

To get the element at position (3,5,7):

element = my_schem.data[3,5,7]

Each element has 4 fields:

node = element["node"] # node ID (rank on the node list, see below)
prob = element["prob"] # probability (0-127)
force = element["force"] # whether to force replacement of existing nodes when the schematic is placed (boolean)
param2 = element["param2"] # param2 of the node

To get an array of node IDs:

node_ids = my_schem.data["node"]

Also works for prob, force and param2.

The data array can be freely modified, as long as you keep the structure with the 4 named fields. Values and array size can be changed.

Y-Slice probabilities

They are stored in my_schem.yprobs in the form of a 1D list of size Y.

prob_at_6 = my_schem.yprobs[6] # is the probability to get slice at y=6 generated (0-127)

If you use specific values for yprobs, make sure the size of this array follows the Y size of the data schematic. If you always use 127, you can neglect this.

Node list

The node list is stored in myschem.nodes. Their order define the node ID. To get the node name of element:

node_name = my_schem.nodes[element["node"]]

To get the ID of a node:

c_lawn = my_schem.nodes.index("default:dirt_with_grass")

Keep the node name list up-to-date if you add new nodes to the data.

Saving

To export the modified schematic:

my_schem.save("path/to/output_schem.mts")

Useful tricks

Replacing a node

To replace every occurence of a node, you don't need to modify the data array, just tweak the node list.

def replace_dirt_by_stone(schem):
    c_dirt = schem.nodes.index("default:dirt")
    schem.nodes[c_dirt] = "default:stone"

Of course this may introduce a duplicate in the node list. Duplicates are automatically fixed on saving, so you generally don't need to bother with that. However if you want to fix them manually, add this:

    schem.cleanup_nodelist()

This removes duplicates and unused nodes in the node list, and updates the array if necessary.

Counting the quantity of a node

This needs to make use of Numpy's count_nonzero function.

import numpy as np
def count_node(schem, nodename):
    id = schem.nodes.index(nodename)
    return np.count_nonzero(schem.data["node"] == id)

Create a schematic from a given part of another schematic

Schem objects can be directly indexed by coordinates. This returns a new Schem object representing the given part of the initial schematic. This is useful for dividing a large schematic into reasonably sized parts, or to prune a schematic containing unnecessary blank margins.

import mtschem
schem = mtschem.Schem("thing.mts")

bottom = schem[:,:10,:] # Here we take the 10 bottom lines of thing.mts
bottom.save("thing_bottom.mts")

middle = schem[:,10:20,:] # Then the 10 lines above
middle.save("thing_middle.mts")

top = schem[:,20:,:] # And finally, from line 20 to the end
top.save("thing_top.mts")

Find the list of nodes present in a given part of the schematic

Using the Numpy function unique to give the list of existing values in an array.

import numpy as np
def list_nodes_in(schem, minp, maxp): # minp and maxp 3-tuples
    subschem = schem[
            minp[0]:maxp[0]+1,
            minp[1]:maxp[1]+1,
            minp[2]:maxp[2]+1,
    ]
    id_list = np.unique(subschem.data["node"])
    node_list = []
    for id in id_list:
        node_list.append(subschem.nodes[id])
    return node_list