This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
mcedit2/tests/mceditlib/nbt_test.py

166 lines
5.5 KiB
Python

from os.path import join
import time
import zipfile
import numpy
from mceditlib import nbt
from templevel import TempFile
__author__ = 'Rio'
class TestNBT():
def testLoad(self):
"Load an indev level."
level = nbt.load(TempFile("indev.mclevel"))
# The root tag must have a name, and so must any tag within a TAG_Compound
print level.name
# Use the [] operator to look up subtags of a TAG_Compound.
print level["Environment"]["SurroundingGroundHeight"].value
# Numeric, string, and bytearray types have a value that can be accessed and changed.
print level["Map"]["Blocks"].value
return level
def testLoadUncompressed(self):
rootTag = nbt.load(TempFile("uncompressed.nbt"))
def testCreate(self):
"Create an indev level."
# The root of an NBT file is always a TAG_Compound.
level = nbt.TAG_Compound(name="MinecraftLevel")
# Subtags of a TAG_Compound are automatically named when you use the [] operator.
level["About"] = nbt.TAG_Compound()
level["About"]["Author"] = nbt.TAG_String("codewarrior")
level["About"]["CreatedOn"] = nbt.TAG_Long(time.time())
level["Environment"] = nbt.TAG_Compound()
level["Environment"]["SkyBrightness"] = nbt.TAG_Byte(16)
level["Environment"]["SurroundingWaterHeight"] = nbt.TAG_Short(32)
level["Environment"]["FogColor"] = nbt.TAG_Int(0xcccccc)
entity = nbt.TAG_Compound()
entity["id"] = nbt.TAG_String("Creeper")
entity["Pos"] = nbt.TAG_List([nbt.TAG_Float(d) for d in (32.5, 64.0, 33.3)])
level["Entities"] = nbt.TAG_List([entity])
spawn = nbt.TAG_List((nbt.TAG_Short(100), nbt.TAG_Short(45), nbt.TAG_Short(55)))
mapTag = nbt.TAG_Compound()
mapTag["Spawn"] = spawn
level["Map"] = mapTag
mapTag2 = nbt.TAG_Compound([spawn])
mapTag2.name = "Map"
# I think it looks more familiar with [] syntax.
l, w, h = 128, 128, 128
mapTag["Height"] = nbt.TAG_Short(h) # y dimension
mapTag["Length"] = nbt.TAG_Short(l) # z dimension
mapTag["Width"] = nbt.TAG_Short(w) # x dimension
# Byte arrays are stored as numpy.uint8 arrays.
mapTag["Blocks"] = nbt.TAG_Byte_Array()
mapTag["Blocks"].value = numpy.zeros(l * w * h, dtype=numpy.uint8) # create lots of air!
# The blocks array is indexed (y,z,x) for indev levels, so reshape the blocks
mapTag["Blocks"].value.shape = (h, l, w)
# Replace the bottom layer of the indev level with wood
mapTag["Blocks"].value[0, :, :] = 5
# This is a great way to learn the power of numpy array slicing and indexing.
mapTag["Data"] = nbt.TAG_Byte_Array()
mapTag["Data"].value = numpy.zeros(l * w * h, dtype=numpy.uint8)
# Save a few more tag types for completeness
level["ShortArray"] = nbt.TAG_Short_Array(numpy.zeros((16, 16), dtype='uint16'))
level["IntArray"] = nbt.TAG_Int_Array(numpy.zeros((16, 16), dtype='uint32'))
level["Float"] = nbt.TAG_Float(0.3)
return level
def testToStrings(self):
level = self.testCreate()
repr(level)
repr(level["Map"]["Blocks"])
repr(level["Entities"])
str(level)
def testModify(self):
level = self.testCreate()
# Most of the value types work as expected. Here, we replace the entire tag with a TAG_String
level["About"]["Author"] = nbt.TAG_String("YARRR~!")
# Because the tag type usually doesn't change,
# we can replace the string tag's value instead of replacing the entire tag.
level["About"]["Author"].value = "Stew Pickles"
# Remove members of a TAG_Compound using del, similar to a python dict.
del(level["About"])
# Replace all of the wood blocks with gold using a boolean index array
blocks = level["Map"]["Blocks"].value
blocks[blocks == 5] = 41
level["Entities"][0] = nbt.TAG_Compound([nbt.TAG_String("Creeper", "id"),
nbt.TAG_List([nbt.TAG_Double(d) for d in (1, 1, 1)], "Pos")])
def testMultipleCompound(self):
""" According to rumor, some TAG_Compounds store several tags with the same name. Once I find a chunk file
with such a compound, I need to test TAG_Compound.get_all()"""
pass
def testSave(self, tmpdir):
level = self.testCreate()
level["Environment"]["SurroundingWaterHeight"].value += 6
# Save the entire TAG structure to a different file.
level.save(str(tmpdir.join("testSave.mclevel")))
def testList(self):
tag = nbt.TAG_List()
tag.append(nbt.TAG_Int(258))
del tag[0]
def testErrors(self):
"""
attempt to name elements of a TAG_List
named list elements are not allowed by the NBT spec,
so we must discard any names when writing a list.
"""
level = self.testCreate()
level["Map"]["Spawn"][0].name = "Torg Potter"
data = level.save()
newlevel = nbt.load(buf=data)
n = newlevel["Map"]["Spawn"][0].name
if n:
print "Named list element failed: %s" % n
# attempt to delete non-existent TAG_Compound elements
# this generates a KeyError like a python dict does.
level = self.testCreate()
try:
del level["DEADBEEF"]
except KeyError:
pass
else:
assert False