Merge remote branch 'carrus85/master'
This commit is contained in:
commit
c7edbde037
10
mce.py
10
mce.py
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
27
mclevel.py
27
mclevel.py
@ -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
23
nbt.py
@ -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;
|
||||||
|
|
||||||
|
BIN
regression_test/alpha.tar.gz
Normal file
BIN
regression_test/alpha.tar.gz
Normal file
Binary file not shown.
156
run_regression_test.py
Executable file
156
run_regression_test.py
Executable 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))
|
||||||
|
|
Reference in New Issue
Block a user