Set_node and mapblock implosion fixed, invref in development

* Inventory: Two functions added : is_empty(listname) and get_size(listname), both working in a similar fashion as their minetest API counterpart
 * Map:
  - Implosion fixed. The num_name_id_mappings variable is correctly set, all data are written to the correct byte streams. A function is added to check whether a position given to a function (list get/set_node) is correct and the mapblock is loaded.
  - Data storage type for static object data fixed
  - MapBlocks now have a get_meta(abspos) method. Abspos is the integer representing the position of the querried metadata inside the mapblock
  - MapVessels default to forcefully save a flagged mapblock before unloading it
  - A new method in MapInterface can flag a mapblock as modified. It is used in member methods to deal with the modification cache flags more easily
  - MapInterface has got another new function to check whether a mapblock is loaded or not and try to load it, all depending on a given position
  - MapInterface's save method is fixed
  - MapInterfaces can return a node's metadata using the get_meta(pos) method. It determines what mapblock contains the quierried node, and use the said mapblock's get_meta method to return a NodeMetaRef object
 * Metadata : Strings are stored as and decoded from arrays of integers, easier to convert from bytes without knowing what is float, what is int, and what is string
 * Nodes : The position argument in a Node object is now a key argument. The only mandatory parameter is the itemstring
 * Test : testSetNode now completly working. It doesn't change the node in (0,0,0) anymore. This node is a chest in the test map and is used to test metadata and inventory manipulation in the new invManip function called upon execution of test.py
This commit is contained in:
LeMagnesium 2016-02-14 21:21:06 +01:00
parent c64b27d1de
commit b8cbe3b75b
5 changed files with 96 additions and 37 deletions

View File

@ -129,3 +129,20 @@ class InvRef:
data.write("EndInventory\n")
return data.getvalue()
# Some stuff from MT
def is_empty(self, listname):
if not self.lists.get(listname):
return True
for stack in self.lists[listname].values():
if stack.get_name() != "":
return False
return True
def get_size(self, listname):
if not self.lists.get(listname):
return 0
else:
return len(self.lists[listname])

73
map.py
View File

@ -72,6 +72,7 @@ class MapBlock:
# Node params
node_data = {"param0": [], "param1": [], "param2": []}
self.name_id_mappings = self.create_name_id_mappings()
self.num_name_id_mappings = len(self.name_id_mappings)
for node in self.nodes.values():
node_data["param0"].append(self.name_id_mappings.index(node.itemstring))
@ -109,7 +110,7 @@ class MapBlock:
writeU32(meta_data, len(meta.data[meta_key]))
for b in meta.data[meta_key]:
writeU8(data, b)
writeU8(meta_data, b)
for c in meta.get_inventory().to_string():
meta_data.write(c.encode("utf8"))
@ -134,9 +135,9 @@ class MapBlock:
# ID mappings starts here
writeU8(data, self.name_id_mapping_version)
self.num_id_mappings = len(self.name_id_mappings)
self.num_name_id_mappings = len(self.name_id_mappings)
writeU16(data, self.num_name_id_mappings)
for i in range(self.num_id_mappings):
for i in range(self.num_name_id_mappings):
writeU16(data, i)
writeU16(data, len(self.name_id_mappings[i]))
for b in self.name_id_mappings[i]:
@ -153,22 +154,20 @@ class MapBlock:
# EOF.
return data.getvalue()
def get_node(self, mapblockpos):
def check_pos(self, mapblockpos):
if not self.loaded:
raise EmptyMapBlockError
if mapblockpos < 0 or mapblockpos >= 4096:
raise OutOfBordersCoordinates
def get_node(self, mapblockpos):
self.check_pos(mapblockpos)
return self.nodes[mapblockpos]
def set_node(self, mapblockpos, node):
if not self.loaded:
raise EmptyMapBlockError
if mapblockpos < 0 or mapblockpos >= 4096:
raise OutOfBordersCoordinates
self.check_pos(mapblockpos)
if self.node_meta.get(mapblockpos):
del self.node_meta[mapblockpos]
@ -178,7 +177,7 @@ class MapBlock:
self.nodes[mapblockpos] = node
self.name_id_mappings = self.create_name_id_mappings()
self.num_id_mappings = len(self.name_id_mappings)
self.num_name_id_mappings = len(self.name_id_mappings)
return True
def explode(self, bytelist):
@ -375,7 +374,7 @@ class MapBlock:
self.static_objects.append({
"type": otype,
"pos": Pos({'x': pos_x_nodes, 'y': pos_y_nodes, 'z': pos_z_nodes}),
"data": odata,
"data": str(odata),
})
# u32 timestamp
@ -412,11 +411,16 @@ class MapBlock:
itemstring = self.name_id_mappings[node_data["param0"][id]]
param1 = node_data["param1"][id]
param2 = node_data["param2"][id]
self.nodes[id] = Node(posFromInt(id, self.mapblocksize), itemstring, param1 = param1, param2 = param2)
self.nodes[id] = Node(itemstring, param1 = param1, param2 = param2, pos = posFromInt(id, self.mapblocksize))
# EOF!
self.loaded = True
def get_meta(self, abspos):
self.check_pos(abspos)
return self.node_meta[abspos]
class MapVessel:
def __init__(self, mapfile, backend = "sqlite3"):
self.mapfile = mapfile
@ -515,7 +519,11 @@ class MapInterface:
self.cache_history = []
self.max_cache_size = 100
self.mod_cache = []
self.force_save_on_unload = False
self.force_save_on_unload = True
def modFlag(self, mapblockpos):
if not mapblockpos in self.mod_cache:
self.mod_cache.append(mapblockpos)
def unloadMapBlock(self, blockID):
self.mapblocks[blockID] = None
@ -554,34 +562,45 @@ class MapInterface:
del self.mod_cache[self.mod_cache.index(blockID)]
return True
def get_node(self, pos):
mapblock = determineMapBlock(pos)
mapblockpos = getMapBlockPos(mapblock)
def check_for_pos(self, mapblockpos):
if not self.mapblocks.get(mapblockpos):
self.loadMapBlock(mapblockpos)
if not self.mapblocks.get(mapblockpos):
self.unloadMapBlock(mapblockpos)
return Node(pos, "ignore")
return False
return True
def get_node(self, pos):
mapblock = determineMapBlock(pos)
mapblockpos = getMapBlockPos(mapblock)
if not self.check_for_pos(mapblockpos):
return Node("ignore", pos = pos)
return self.mapblocks[mapblockpos].get_node((pos.x % 16) + (pos.y % 16) * 16 + (pos.z % 16) * 16 * 16)
def set_node(self, pos, node):
mapblock = determineMapBlock(pos)
mapblockpos = getMapBlockPos(mapblock)
if not self.mapblocks.get(mapblockpos):
self.loadMapBlock(mapblockpos)
if not self.mapblocks.get(mapblockpos):
self.unloadMapBlock(mapblockpos)
if not self.check_for_pos(mapblockpos):
raise IgnoreContentReplacementError("Pos: " + pos)
node.pos = pos
if not mapblockpos in self.mod_cache:
self.mod_cache.append(mapblockpos)
self.modFlag(mapblockpos)
return self.mapblocks[mapblockpos].set_node((pos.x % 16) + (pos.y % 16) * 16 + (pos.z % 16) * 16 * 16, node)
def save(self):
for blockID in self.mod_cache:
self.saveMapBlock(blockID)
while len(self.mod_cache) > 0:
self.saveMapBlock(self.mod_cache[0])
self.mod_cache = []
def get_meta(self, pos):
mapblock = determineMapBlock(pos)
mapblockpos = getMapBlockPos(mapblock)
self.modFlag(mapblockpos)
if not self.check_for_pos(mapblockpos):
return NodeMetaRef()
return self.mapblocks[mapblockpos].get_meta(intFromPos(pos, 16))

View File

@ -23,10 +23,21 @@ class NodeMetaRef:
self.data[key] = val
def get_string(self, key):
return str(self.data.get(key))
# Gather the integers into a string
data = self.data.get(key)
if not data:
return None
res = ""
for c in data:
if c >= 256 or c < 0:
return data # IT IS A NUMBER AAAAAH
res += chr(c)
return res
def set_string(self, key, val):
self.data[key] = str(val)
self.data[key] = [ord(b) for b in val]
def get_int(self, key):
return int(self.data.get(key))

View File

@ -35,7 +35,7 @@ class NodeTimerRef:
return self.active
class Node:
def __init__(self, pos, itemstring, param1 = 0, param2 = 0):
def __init__(self, itemstring, param1 = 0, param2 = 0, pos = Pos()):
self.pos = pos
self.itemstring = itemstring
self.param1, self.param2 = param1, param2

26
test.py
View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python3.4
# -*- encoding: utf-8 -*-
############################
## Tests ran for Python-MT
@ -85,20 +85,32 @@ def testGetNode():
def testSetNode():
db = minetest.MapInterface("./map.sqlite")
db.force_save_on_unload = True
f = open("./dump.bin", "w")
dummy = minetest.Node(Pos(), "default:nyancat", 0, 0)
print(db.get_node(Pos()))
print(db.set_node(Pos(), dummy))
dummy = minetest.Node("default:nyancat")
for y in range(0, 256):
for y in range(1, 256):
db.set_node(Pos({'x': 0, 'y': y, 'z': 0}), dummy)
db.save()
def invManip():
db = minetest.MapInterface("./map.sqlite")
chest = db.get_meta(Pos({'x': 0, 'y': 0, 'z': 0}))
#print(chest)
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()
if __name__ == "__main__":
#findTheShelves()
#testMapBlockLoad()
#testSignedEndians()
#testGetNode()
testSetNode()
#testSetNode()
invManip()