Source code for miney.nodes

import miney
from miney import Node, Point
from typing import Union, Iterable


[docs]class Nodes: """ Manipulate and get information's about node. **Nodes manipulation is currently tested for up to 25.000 node, more optimization will come later** """ def __init__(self, mt: miney.Minetest): self.mt = mt self._names_cache = self.mt.lua.run( """ local node = {} for name, def in pairs(minetest.registered_nodes) do table.insert(node, name) end return node """ ) self._types = NameIterable(self, self._names_cache) @property def name(self) -> 'NameIterable': """ In Minetest, the type of the node, something like "dirt", is the "name" of this node. This property returns all available node names in the game, sorted by categories. In the end it just returns the corresponding minetest name string, so `mt.node.types.default.dirt` returns the string 'default:dirt'. It's only a nice shortcut in REPL, cause with auto completion you have only pressed 2-4 keys to get to your type. :Examples: Directly access a type: >>> mt.node.name.default.dirt 'default:dirt' Iterate over all available types: >>> for node_type in mt.node.name: >>> print(node_type) default:pine_tree default:dry_grass_5 farming:desert_sand_soil ... (there should be over 400 different types) >>> print(len(mt.node.name)) 421 Get a list of all types: >>> list(mt.node.name) ['default:pine_tree', 'default:dry_grass_5', 'farming:desert_sand_soil', ... Add 99 dirt to player "IloveDirt"'s inventory: >>> mt.player.IloveDirt.inventory.add(mt.node.name.default.dirt, 99) :rtype: :class:`NameIterable` :return: :class:`TypeIterable` object with categories. Look at the examples above for usage. """ return self._types
[docs] def set(self, node: Union[Node, list]) -> None: """ Set a single or multiple nodes at given position to another node type (something like mt.nodes.type.default.apple). You can get a list of all available node types with :attr:`~miney.Minetest.node.type` **The nodes parameter can be a single Node object or a list of Node objects for bulk spawning.** :Examples: Replace the node under the first players feet with dirt: >>> from miney import Node >>> pos = Node(mt.player[0].position.x, mt.player[0].position.y - 1, mt.player[0].position.z, "default:dirt") >>> mt.nodes.set(mt.player[0].position) :param node: A dict or a list of dicts with node definitions """ # Set a single node if type(node) is Node: self.mt.lua.run( f"minetest.set_node({ self.mt.lua.dumps({'x': node.x, 'y': node.y, 'z': node.z}) }, " f"{{name=\"{ node.name }\"}})" ) # Set many nodes elif type(node) is list: lua = "" # Loop over node, modify name/type, position/offset and generate lua code for n in node: lua = lua + f"minetest.set_node(" \ f"{self.mt.lua.dumps({'x': n.x, 'y': n.y, 'z': n.z})}, " \ f"{{name=\"{n.name}\"}})\n" self.mt.lua.run(lua)
[docs] def get(self, point: Union[Point, Node, Iterable]) -> Union[Node, list]: """ Get the node at given position. It returns a node object. This contains the "x", "y", "z", "param1", "param2" and "name" attributes, where "name" is the node type like "default:dirt". If instead of a single point/node a list or tuple with 2 points/nodes is given, this function returns a list of nodes. This list contains a cuboid of nodes with the diagonal between the given points. Tip: You can get a list of all available node types with :attr:`~miney.Minetest.node.type`. :param point: A Point object :return: The node type on this position """ if isinstance(point, Point): # for a single node node = Node(point.x, point.y, point.z, **self.mt.lua.run( f"return minetest.get_node({self.mt.lua.dumps(point.__dict__)})")) return node elif isinstance(point, (list, tuple)): # Multiple nodes lnodes = self.mt.lua.run( # We sort them by the smallest coordinates and get them node per node f""" pos1 = {self.mt.lua.dumps(dict(point[0]))} pos2 = {self.mt.lua.dumps(dict(point[1]))} minetest.load_area(pos1, pos2) nodes = {{}} if pos1.x <= pos2.x then start_x = pos1.x end_x = pos2.x else start_x = pos2.x end_x = pos1.x end if pos1.y <= pos2.y then start_y = pos1.y end_y = pos2.y else start_y = pos2.y end_y = pos1.y end if pos1.z <= pos2.z then start_z = pos1.z end_z = pos2.z else start_z = pos2.z end_z = pos1.z end for x = start_x, end_x do for y = start_y, end_y do for z = start_z, end_z do node = minetest.get_node({{x = x, y = y, z = z}}) node["x"] = x node["y"] = y node["z"] = z nodes[#nodes+1] = node -- append node end end end return nodes""", timeout=60) nodes = [] for n in lnodes: nodes.append(Node(n["x"], n["y"], n["z"], n["name"], n["param1"], n["param2"])) return nodes
def __repr__(self): return '<minetest node functions>'
class NameIterable: """Node names, implemented as iterable for easy autocomplete in the interactive shell""" def __init__(self, parent, nodes_types=None): self._parent = parent if nodes_types: # get type categories list type_categories = {} for ntype in nodes_types: if ":" in ntype: type_categories[ntype.split(":")[0]] = ntype.split(":")[0] for tc in dict.fromkeys(type_categories): self.__setattr__(tc, NameIterable(parent)) # values to categories for ntype in nodes_types: if ":" in ntype: self.__getattribute__(ntype.split(":")[0]).__setattr__(ntype.split(":")[1], ntype) else: self.__setattr__(ntype, ntype) # for 'air' and 'ignore' def __iter__(self): # todo: list(mt.node.type.default) should return only default group return iter(self._parent._names_cache) def __getitem__(self, item_key): if type(self._parent) is not type(self): # if we don't have a category below return self.__getattribute__(item_key) if item_key in self._parent.node_types: return item_key else: if type(item_key) == int: return self._parent.node_types[item_key] raise IndexError("unknown node type") def __len__(self): return len(self._parent._names_cache)