Merge remote branch 'carrus85/master'

This commit is contained in:
David Vierra 2010-10-06 18:14:52 -10:00
commit c7edbde037
5 changed files with 189 additions and 25 deletions

10
mce.py
View File

@ -11,6 +11,8 @@ class BlockMatchError(RuntimeError): pass
class PlayerNotFound(RuntimeError): pass class PlayerNotFound(RuntimeError): pass
class mce(object): class mce(object):
random_seed = os.getenv('MCE_RANDOM_SEED', None)
last_played = os.getenv("MCE_LAST_PLAYED", None)
""" """
Usage: Usage:
@ -195,6 +197,7 @@ class mce(object):
def _debug(self, command): def _debug(self, command):
self.debug = not self.debug self.debug = not self.debug
print "Debug", ("disabled", "enabled")[self.debug] print "Debug", ("disabled", "enabled")[self.debug]
def _log(self, command): def _log(self, command):
""" """
log [ <number> ] log [ <number> ]
@ -369,7 +372,7 @@ class mce(object):
filename = command.pop(0) filename = command.pop(0)
destPoint = self.readPoint(command) destPoint = self.readPoint(command)
importLevel = mclevel.fromFile(filename) importLevel = mclevel.fromFile(filename, last_played=self.last_played, random_seed=self.random_seed)
self.level.copyBlocksFrom(importLevel, importLevel.getWorldBounds(), destPoint); self.level.copyBlocksFrom(importLevel, importLevel.getWorldBounds(), destPoint);
@ -652,7 +655,7 @@ class mce(object):
self.loadWorld(command[0]) self.loadWorld(command[0])
def _reload(self, command): def _reload(self, command):
self.level = mclevel.fromFile(self.filename); self.level = mclevel.fromFile(self.filename, last_played=self.last_played, random_seed=self.random_seed);
def _help(self, command): def _help(self, command):
if len(command): if len(command):
@ -706,7 +709,7 @@ class mce(object):
try: try:
worldNum = int(world) worldNum = int(world)
except ValueError: except ValueError:
self.level = mclevel.fromFile(world) self.level = mclevel.fromFile(world, last_played=self.last_played, random_seed=self.random_seed)
self.filename = self.level.filename self.filename = self.level.filename
@ -814,6 +817,7 @@ try:
except Exception, e: except Exception, e:
traceback.print_exc() traceback.print_exc()
print e print e
raise SystemExit(1)
#editor.printUsage() #editor.printUsage()

View File

@ -587,7 +587,7 @@ class MCLevel(object):
def saveInPlace(self): def saveInPlace(self):
self.saveToFile(self.filename); self.saveToFile(self.filename);
@classmethod @classmethod
def fromFile(cls, filename, loadInfinite=True): def fromFile(cls, filename, loadInfinite=True, random_seed=None, last_played=None):
''' The preferred method for loading Minecraft levels of any type. ''' The preferred method for loading Minecraft levels of any type.
pass False to loadInfinite if you'd rather not load infdev levels.''' pass False to loadInfinite if you'd rather not load infdev levels.'''
info( "Identifying " + filename ) info( "Identifying " + filename )
@ -604,7 +604,7 @@ class MCLevel(object):
raise; raise;
try: try:
info( "Can't read, attempting to open directory" ) info( "Can't read, attempting to open directory" )
lev = MCInfdevOldLevel(filename=filename) lev = MCInfdevOldLevel(filename=filename, random_seed=random_seed, last_played=last_played)
info( "Detected Alpha world." ) info( "Detected Alpha world." )
return lev; return lev;
except Exception, ex: except Exception, ex:
@ -1494,7 +1494,7 @@ class MCInfdevOldLevel(MCLevel):
def __str__(self): def __str__(self):
return "MCInfdevOldLevel(" + os.path.split(self.worldDir)[1] + ")" return "MCInfdevOldLevel(" + os.path.split(self.worldDir)[1] + ")"
def __init__(self, filename = None, root_tag = None): def __init__(self, filename = None, root_tag = None, random_seed=None, last_played=None):
#pass level.dat's root tag and filename to read an existing level. #pass level.dat's root tag and filename to read an existing level.
#pass only filename to create a new one #pass only filename to create a new one
#filename should be the path to the world dir #filename should be the path to the world dir
@ -1521,8 +1521,13 @@ class MCInfdevOldLevel(MCLevel):
root_tag[Data][SpawnY] = TAG_Int(2) root_tag[Data][SpawnY] = TAG_Int(2)
root_tag[Data][SpawnZ] = TAG_Int(0) root_tag[Data][SpawnZ] = TAG_Int(0)
root_tag[Data]['LastPlayed'] = TAG_Long(long(time.time())) if last_played is None:
root_tag[Data]['RandomSeed'] = TAG_Long(int(random.random() * ((2<<31)))) last_played = time.time()
if random_seed is None:
random_seed = random.random() * ((2<<31))
root_tag[Data]['LastPlayed'] = TAG_Long(long(last_played))
root_tag[Data]['RandomSeed'] = TAG_Long(int(random_seed))
root_tag[Data]['SizeOnDisk'] = TAG_Long(long(1048576)) root_tag[Data]['SizeOnDisk'] = TAG_Long(long(1048576))
root_tag[Data]['Time'] = TAG_Long(1) root_tag[Data]['Time'] = TAG_Long(1)
root_tag[Data]['SnowCovered'] = TAG_Byte(0); root_tag[Data]['SnowCovered'] = TAG_Byte(0);
@ -1627,18 +1632,18 @@ class MCInfdevOldLevel(MCLevel):
def base36(self, n): def base36(self, n):
n = int(n); n = int(n);
if 0 == n: return '0' if 0 == n: return '0'
s = "";
neg = ""; neg = "";
if n < 0: if n < 0:
neg = "-" neg = "-"
n = -n; n = -n;
while(n): work = []
digit = n % 36;
n /= 36
s=self.base36alphabet[digit]+s
return neg + s; while(n):
n, digit = divmod(n, 36)
work.append(self.base36alphabet[digit])
return neg + ''.join(reversed(work))
def dirhashlookup(self, n): def dirhashlookup(self, n):
return self.dirhashes[n%64]; return self.dirhashes[n%64];

23
nbt.py
View File

@ -227,13 +227,8 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
assert_type(tag_type, data_cursor) assert_type(tag_type, data_cursor)
tag_name = TAG_String( data=data[data_cursor:] ) data_cursor, tag = load_named(data, data_cursor, tag_type)
data_cursor += tag_name.nbt_length()
tag_name = tag_name.value
tag = tag_handlers[tag_type]( data=data[data_cursor:], name=tag_name )
data_cursor += tag.nbt_length()
self.value.append(tag); self.value.append(tag);
@ -389,6 +384,15 @@ def loadFile(filename):
else: else:
return load(buf=fromstring(data, 'uint8')); return load(buf=fromstring(data, 'uint8'));
def load_named(data, data_cursor, tag_type):
tag_name = TAG_String( data=data[data_cursor:] )
data_cursor += tag_name.nbt_length()
tag_name = tag_name.value
tag = tag_handlers[tag_type]( data=data[data_cursor:], name=tag_name)
data_cursor += tag.nbt_length()
return data_cursor, tag
def load(filename="", buf = None): def load(filename="", buf = None):
"""Unserialize data from an entire NBT file and return the """Unserialize data from an entire NBT file and return the
root TAG_Compound object. Argument can be a string containing a root TAG_Compound object. Argument can be a string containing a
@ -408,12 +412,7 @@ def load(filename="", buf = None):
raise IOError, 'Not an NBT file with a root TAG_Compound (found {0})'.format(tag_type); raise IOError, 'Not an NBT file with a root TAG_Compound (found {0})'.format(tag_type);
data_cursor += 1; data_cursor += 1;
tag_name = TAG_String( data=data[data_cursor:] ) data_cursor, tag = load_named(data, data_cursor, tag_type)
data_cursor += tag_name.nbt_length()
tag_name = tag_name.value
tag = tag_handlers[tag_type]( data=data[data_cursor:])
tag.name = tag_name;
return tag; return tag;

Binary file not shown.

156
run_regression_test.py Executable file
View File

@ -0,0 +1,156 @@
#!/usr/bin/env python
import tempfile
import sys
import subprocess
import shutil
import os
import mclevel
import hashlib
import contextlib
import gzip
import fnmatch
import tarfile
import zipfile
def generate_file_list(directory):
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
yield os.path.join(dirpath, filename)
def sha1_file(name, checksum=None):
CHUNKSIZE=1024
if checksum is None:
checksum = hashlib.sha1()
if fnmatch.fnmatch(name, "*.dat"):
opener = gzip.open
else:
opener = open
with contextlib.closing(opener(name, 'rb')) as data:
chunk = data.read(CHUNKSIZE)
while len(chunk) == CHUNKSIZE:
checksum.update(chunk)
chunk = data.read(CHUNKSIZE)
else:
checksum.update(chunk)
return checksum
def calculate_result(directory):
checksum = hashlib.sha1()
for filename in sorted(generate_file_list(directory)):
sha1_file(filename, checksum)
return checksum.hexdigest()
@contextlib.contextmanager
def temporary_directory(prefix='regr'):
name = tempfile.mkdtemp(prefix)
try:
yield name
finally:
shutil.rmtree(name)
@contextlib.contextmanager
def directory_clone(src):
with temporary_directory('regr') as name:
subdir = os.path.join(name, "subdir")
shutil.copytree(src, subdir)
yield subdir
@contextlib.contextmanager
def unzipped_content(src):
with temporary_directory() as dest:
f = zipfile.ZipFile.open(name)
f.extractall(dest)
yield dest
@contextlib.contextmanager
def untared_content(src):
with temporary_directory() as dest:
f = tarfile.TarFile.open(src)
f.extractall(dest)
yield dest
class RegressionError(Exception): pass
def do_test(test_data, result_check, arguments=[]):
"""Run a regression test on the given world.
result_check - sha1 of the recursive tree generated
arguments - arguments to give to mce.py on execution
"""
result_check = result_check.lower()
env = {
'MCE_RANDOM_SEED' : '42',
'MCE_LAST_PLAYED' : '42'
}
with directory_clone(test_data) as directory:
proc = subprocess.Popen([
"./mce.py",
directory] + arguments, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, env=env)
proc.stdin.close()
result = proc.wait()
if os.WIFEXITED(result) and os.WEXITSTATUS(result):
raise RegressionError("Program execution failed!")
checksum = calculate_result(directory).lower()
if checksum != result_check.lower():
raise RegressionError("Checksum mismatch: {0!r} != {1!r}".format(checksum, result_check))
print "[OK] (sha1sum of result is {0!r}, as expected)".format(result_check)
def do_test_match_output(test_data, result_check, arguments=[]):
result_check = result_check.lower()
env = {
'MCE_RANDOM_SEED' : '42',
'MCE_LAST_PLAYED' : '42'
}
with directory_clone(test_data) as directory:
proc = subprocess.Popen([
"./mce.py",
directory] + arguments, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=env)
proc.stdin.close()
output = proc.stdout.read()
result = proc.wait()
if os.WIFEXITED(result) and os.WEXITSTATUS(result):
raise RegressionError("Program execution failed!")
checksum = hashlib.sha1()
checksum.update(output)
checksum = checksum.hexdigest()
if checksum != result_check.lower():
raise RegressionError("Checksum mismatch: {0!r} != {1!r}".format(checksum, result_check))
print "[OK] (sha1sum of result is {0!r}, as expected)".format(result_check)
alpha_tests = [
(do_test, 'baseline', 'ca66277d8037fde5aea3a135dd186f91e4bf4bef', []),
(do_test, 'degrief', '6ae14eceab8e0c600799463a77113448b2d9ff8c', ['degrief']),
(do_test_match_output, 'analyze', 'f2938515596b88509b2e4c8d598951887d7e0f4c', ['analyze']),
(do_test, 'relight', '00bc507daa3c07fee065973da4b81a099124650f', ['relight']),
(do_test, 'replace', 'b26c3d3c05dd873fd8fd29b6b7a38e3ebd9a3e8e', ['replace', 'Water', 'with', 'Lava']),
(do_test, 'fill', 'f9dd5d49789b4c7363bf55eab03b05846e89f89f', ['fill', 'Water']),
]
def main(argv):
if len(argv) <= 1:
do_these_regressions = ['*']
else:
do_these_regressions = argv[1:]
with untared_content("regression_test/alpha.tar.gz") as directory:
test_data = os.path.join(directory, "alpha")
for func, name, sha, args in alpha_tests:
if any(fnmatch.fnmatch(name, x) for x in do_these_regressions):
func(test_data, sha, args)
print "Regression {0!r} complete.".format(name)
if __name__ == '__main__':
sys.exit(main(sys.argv))