- Unified indentation in the source code
     - MapInterfaces (`minetest.map.MapInterface`) can now import schematics as well
     - Some prints in MapVessel's (`minetest.map.MapVessel`) code were labeled "WARNING", the others commented

 - Utils :
     - A class called Vector (`minetest.utils.Vector`) is added to deal with vectors and Pos (`minetest.utils.Pos`) manipulation

 - Tests :
     - Tests are made more fancy with check lists (rather than big data dumps) and time tests. All tests were remade and organized to include assertations and prettier printing

 - Demo :
     - A new demo is available, it is called demo_schematics_manipulation and serves the purpose of exporting/importing schematics from/into a map database

 - Schematics :
     - The export method now writes position integers on the correct amount of bytes

 - Minetest :
     - All python source code files are imported into the single file minetest.py, later imported by any other source code file
This commit is contained in:
LeMagnesium 2016-02-26 00:13:08 +01:00
parent 9c1f363087
commit 724018376f
6 changed files with 739 additions and 586 deletions

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3.4
# -*- encoding: utf-8 -*-
############################
## Demo of Python-Minetest :
## Exports/Imports a schematic to a map
##
## args :
## ./demo_schematic_manipulation.py <import|export> <path to sqlite file> <path to schematic file>
##
#
import minetest
pos_import = minetest.utils.Pos({"x": -33, "y": 100, "z": 48})
pos1_export = minetest.utils.Pos({"x": -10, "y": -10, "z": -10})
pos2_export = minetest.utils.Pos({"x": 10, "y": 10, "z": 10})
if __name__ == "__main__":
import sys
if len(sys.argv) < 4:
if len(sys.argv) == 2 and sys.argv[1] == "help":
print("./demo_schematic_manipulation.py <import|export> <path to sqlite file> <path to schematic file>")
else:
print("See demo_schematic_manipulation.py help for help")
sys.exit(0)
mode, dbfile, schfile = sys.argv[1:4]
try:
open(dbfile)
except Exception as err:
print("Couldn't open db file {0} : {1}".format(dbfile, err))
sys.exit(0)
db = minetest.map.MapInterface(dbfile)
if mode.lower() == "import":
print("Importing schematic..")
db.import_schematic(pos_import, minetest.schematics.Schematic(schfile))
db.save()
print("Done")
elif mode.lower() == "export":
print("Exporting schematic..")
db.export_schematic(pos1_export, pos2_export).export_to_file(schfile)
print("Done")
else:
print("Unknown mode {0}".format(mode))
sys.exit(9)

1062
src/map.py

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,9 @@
#
import utils
from utils import Pos
from map import MapInterface
import map
from nodes import *
import schematics
import inventory
import errors
import metadata
import nodes

View File

@ -20,7 +20,7 @@ from io import BytesIO
# Quick spec for ver4
"""
u32 signature (= b"MTSM")
u16 version?
u16 version
u16 size_x
u16 size_y
u16 size_z
@ -109,9 +109,9 @@ class Schematic:
data.write(b"MTSM")
writeU16(data, self.version)
writeU8(data, self.size["x"])
writeU8(data, self.size["y"])
writeU8(data, self.size["z"])
writeU16(data, self.size["x"])
writeU16(data, self.size["y"])
writeU16(data, self.size["z"])
for u in range(self.size["y"]):
p = self.y_slice_probs.get(u) or 127

View File

@ -6,93 +6,170 @@
import minetest
import random
from utils import readS8, readS16, Pos
import time
from io import BytesIO
from schematics import Schematic
def testSignedEndians():
print(readS16(BytesIO(b"\x9f\xff")))
def testMapBlockLoad():
file = minetest.map.MapVessel("./map.sqlite")
#i = 2+12*4096+(-9)*4096*4096
#i = 0
for i in range(-4096, 4096):
res, code = file.read(i)
if not res:
continue
else:
print("Read {0}: {1}".format(i, (res, code)))
file = minetest.map.MapVessel("./map.sqlite")
for i in range(-4096, 4096):
res, code = file.read(i)
if not res:
continue
else:
mapb = file.load(i)
print("Read and loaded {0}: {1}".format(i, mapb), end = " \r")
mapb = file.load(i)
print("Loaded {0}: {1}".format(i, mapb))
print(" -> There are in total {0} mapblocks in the map".format(len(file.get_all_mapblock_ids())), end = (' ' * 20) + '\n')
print(" --> Test successful")
def testEndians():
assert(minetest.utils.readS8(BytesIO(b"\xf8")) == -8)
print(" -> readS8: OK")
assert(minetest.utils.readS16(BytesIO(b"\x9f\xff")) == -24577)
print(" -> readS16: OK")
assert(minetest.utils.readS32(BytesIO(b"\xf0\x00\x00\x00")) == -268435456)
print(" -> readS32: OK")
assert(minetest.utils.readU8(BytesIO(b"\xf8")) == 248)
print(" -> readU8: OK")
assert(minetest.utils.readU16(BytesIO(b"\x9f\xff")) == 40959)
print(" -> readU16: OK")
assert(minetest.utils.readU32(BytesIO(b"\xf0\x00\x00\x00")) == 4026531840)
print(" -> readU32: OK")
print(" --> Test successful")
print(len(file.cache))
def testGetNode():
db = minetest.MapInterface("./map.sqlite")
for _ in range(1000):
pos = Pos({'x': random.randint(-300, 300), 'y': random.randint(-300, 300), 'z': random.randint(-300, 300)})
db = minetest.map.MapInterface("./map.sqlite")
u = random.randint(500, 2000)
k = random.randint(40,400)
db.set_maxcachesize(k)
print(" -> Maximum cache size set to {0} mapblocks".format(k))
s = time.time()
for i in range(u):
pos = minetest.utils.Pos({'x': random.randint(-300, 300), 'y': random.randint(-300, 300), 'z': random.randint(-300, 300)})
assert(db.get_node(pos).get_name() != "")
if len(db.interface.cache) == db.get_maxcachesize():
endstr = " (MAX)\r"
else:
endstr = " \r"
print("[{0}/{1}] Cache size: {2}".format(i, u, len(db.interface.cache)), end = endstr)
print("{0}: {1}".format(pos, db.get_node(pos).get_name()))
print("Cache size: {0}".format(len(db.interface.cache)), end = " \r")
assert(len(db.interface.cache) <= db.get_maxcachesize())
print(" -> ~{0:.4f}ms per call to get_node".format((time.time()-s)*1000/u), end = " \n")
print(" --> Test successful")
def testSetNode():
db = minetest.MapInterface("./map.sqlite")
db = minetest.map.MapInterface("./map.sqlite")
f = open("./dump.bin", "w")
dummy = minetest.Node("default:nyancat")
dummy = minetest.nodes.Node("default:nyancat")
s = time.time()
u = 100
for y in range(1, 10):
db.set_node(Pos({'x': 0, 'y': y, 'z': 0}), dummy)
for y in range(1, u+1):
db.set_node(minetest.utils.Pos({'x': 0, 'y': y, 'z': 0}), dummy)
print(" -> {0} nyan cats placed".format(u))
print(" -> {0}ms per call to set_node".format((time.time()-s)/u*1000))
s = time.time()
db.save()
print(" -> database saving took {0}s".format(time.time()-s))
print(" --> Test successful")
def invManip():
db = minetest.MapInterface("./map.sqlite")
chest = db.get_meta(Pos({'x': 0, 'y': 0, 'z': 0}))
#print(chest)
db = minetest.map.MapInterface("./map.sqlite")
pos = minetest.utils.Pos({'x': 0, 'y': 0, 'z': 0})
chest = db.get_meta(pos)
inv = chest.get_inventory()
#print(inv)
#print(chest.get_string("formspec"))
#chest.set_string("formspec", chest.get_string("formspec") + "button[0,0;1,0.5;moo;Moo]")
#print(chest.get_string("formspec"))
print(inv.is_empty("main"))
print(inv.get_size("main"))
db.save()
print(" -> Testing inventory in node at {0}".format(pos))
print(" ~~> Node's name is {0}".format(db.get_node(pos).get_name()))
if inv.is_empty("main"):
print(" ~~> Inventory is empty")
else:
print(" ~~> Inventory is not empty")
print(" ~~> Size of 'main' list is {0} slots".format(inv.get_size("main")))
print(" --> Test successful")
def testSchematics():
# Import from file
schem = Schematic("/home/lymkwi/.minetest/games/minetest_game/mods/default/schematics/apple_tree_from_sapling.mts")
schem = minetest.schematics.Schematic("/home/lymkwi/.minetest/games/minetest_game/mods/default/schematics/apple_tree_from_sapling.mts")
print(" -> Schematic : {0}".format(schem))
# Export to BytesStream & file
print(schem.export().read())
assert(schem.export().read())
print(" -> Export : OK")
s = time.time()
schem.export_to_file("test.mts")
print(" ~~> File export : {0}s".format(time.time()-s))
assert(open("test.mts"))
# Map export
db = minetest.MapInterface("./map.sqlite")
schem = db.export_schematic(Pos(), Pos({"x": -100, "y": 10, "z": 100}))
db = minetest.map.MapInterface("./map.sqlite")
s = time.time()
schem = db.export_schematic(minetest.utils.Pos(), minetest.utils.Pos({"x": -100, "y": 10, "z": 100}))
s = time.time() - s
assert(schem.export().read())
print(" -> Schematic exportation : OK")
print(" ~~> Exportation took {0}s".format(s))
schem.export_to_file("test.mts")
# Get node
print(schem.get_node(Pos({"x": 1, "y": 1, "z": 0})))
node = schem.get_node(minetest.utils.Pos({"x": 0, "y": 0, "z": 0})).get_name()
assert(node != "")
print(" -> Node in (0,0,0) is {0}".format(node))
# Import
s = time.time()
db.import_schematic(minetest.utils.Pos({"x": 100, "y": 100, "z": 100}), schem)
print(" -> Importation in map took {0}s".format(time.time() - s))
print(" -> {0} mapblock(s) to be saved".format(len(db.mod_cache)))
s = time.time()
db.save()
print(" -> Saving took {0}s".format(time.time() - s))
print(" --> Test successful")
if __name__ == "__main__":
print("=> MapBlockLoad")
print("=> MapBlockLoad Test")
s = time.time()
testMapBlockLoad()
print("=> signed endians")
testSignedEndians()
print("=> get_node")
print(" => Test took {0:.10f}s".format(time.time()-s))
print("=> Signed Endians")
s = time.time()
testEndians()
print(" => Test took {0:.10f}s".format(time.time()-s))
print("=> get_node Test")
s = time.time()
testGetNode()
print(" => Test took {0:.10f}s".format(time.time()-s))
print("=> set_node")
s = time.time()
testSetNode()
print(" => Test took {0:.10f}s".format(time.time()-s))
print("=> inventory manipulation (WIP)")
s = time.time()
invManip()
print(" => Test took {0:.10f}s".format(time.time()-s))
print("=> schematic manipulation (WIP)")
s = time.time()
testSchematics()
print(" => Test took {0:.10f}s".format(time.time()-s))

View File

@ -131,11 +131,27 @@ def writeU16(strm, val):
strm.write(bytes(vals))
def writeU32(strm, val):
vals = []
for _ in range(4):
k = val % 256
vals.insert(0, int(k))
val -= k
val /= 256
vals = []
for _ in range(4):
k = val % 256
vals.insert(0, int(k))
val -= k
val /= 256
strm.write(bytes(vals))
strm.write(bytes(vals))
class Vector:
def add(self, pos1, pos2):
return Pos({"x": pos1.x + pos2.x, "y": pos1.y + pos2.y, "z": pos1.z + pos2.z})
def sub(self, pos1, pos2):
return Pos({"x": pos1.x - pos2.x, "y": pos1.y - pos2.y, "z": pos1.z - pos2.z})
def mult(self, pos, lmbd):
return Pos({"x": pos.x * lmbd, "y": pos.y * lmbd, "z": pos.z * lmbd})
def div(self, pos, lmbd):
return self.mult(self, pos, 1/lmbd)
def round(self, pos):
return Pos({"x": round(pos.x), "y": round(pos.y), "z": round(pos.z)})