Merge branch 'renamedAllChunks'

renamed presentChunks to loadedChunks for clarity, and allChunks will cause a chunk scan the first time it is called
This commit is contained in:
David Vierra 2010-11-29 22:38:03 -10:00
commit ef8432ee57
4 changed files with 155 additions and 108 deletions

2
box.py
View File

@ -91,7 +91,7 @@ class BoundingBox (object):
maximum = property(getMaximum, None, None, "The endpoint of the box; origin plus size.") maximum = property(getMaximum, None, None, "The endpoint of the box; origin plus size.")
def getVolume(self): return reduce(int.__mul__, self.size) def getVolume(self): return reduce(lambda a,b:a*b, self.size)
volume = property(getVolume, None, None, "The volume of the box in blocks") volume = property(getVolume, None, None, "The volume of the box in blocks")
@property @property

29
mce.py
View File

@ -438,9 +438,9 @@ class mce(object):
blockCounts = zeros( (256,), 'uint64') blockCounts = zeros( (256,), 'uint64')
sizeOnDisk = 0; sizeOnDisk = 0;
print "Analyzing {0} chunks...".format(len(self.level.presentChunks)) print "Analyzing {0} chunks...".format(len(self.level.allChunks))
for i, cPos in enumerate(self.level.presentChunks, 1): for i, cPos in enumerate(self.level.allChunks, 1):
ch = self.level.getChunk(*cPos); ch = self.level.getChunk(*cPos);
counts = bincount(ch.Blocks.ravel()) counts = bincount(ch.Blocks.ravel())
blockCounts[:counts.shape[0]] += counts blockCounts[:counts.shape[0]] += counts
@ -585,7 +585,7 @@ class mce(object):
print "Dumping signs..." print "Dumping signs..."
signCount = 0; signCount = 0;
for i, cPos in enumerate(self.level.presentChunks): for i, cPos in enumerate(self.level.allChunks):
try: try:
chunk = self.level.getChunk(*cPos); chunk = self.level.getChunk(*cPos);
except mclevel.ChunkMalformed: except mclevel.ChunkMalformed:
@ -649,7 +649,7 @@ class mce(object):
print "Removing all entities except Painting..." print "Removing all entities except Painting..."
def match(entityID): return entityID != "Painting"; def match(entityID): return entityID != "Painting";
for cx,cz in self.level.presentChunks: for cx,cz in self.level.allChunks:
chunk = self.level.getChunk(cx,cz) chunk = self.level.getChunk(cx,cz)
entitiesRemoved = 0; entitiesRemoved = 0;
@ -692,10 +692,9 @@ class mce(object):
box = self.readBox(command) box = self.readBox(command)
oldChunkCount = len(self.level.presentChunks) chunksCreated = self.level.createChunksInBox(box)
self.level.createChunksInBox(box)
print "Created {0} chunks." .format(len(self.level.presentChunks)-oldChunkCount) print "Created {0} chunks." .format(len(chunksCreated))
self.needsSave = True; self.needsSave = True;
@ -712,10 +711,9 @@ class mce(object):
box = self.readBox(command) box = self.readBox(command)
oldChunkCount = len(self.level.presentChunks) deletedChunks = self.level.deleteChunksInBox(box)
self.level.deleteChunksInBox(box)
print "Deleted {0} chunks." .format(oldChunkCount-len(self.level.presentChunks)) print "Deleted {0} chunks." .format(len(deletedChunks))
def _prune(self, command): def _prune(self, command):
""" """
@ -730,14 +728,13 @@ class mce(object):
box = self.readBox(command) box = self.readBox(command)
oldChunkCount = len(self.level.presentChunks) i=0;
for cx,cz in self.level.allChunks:
for cx,cz in self.level.presentChunks:
if cx < box.mincx or cx >= box.maxcx or cz < box.mincz or cz >= box.maxcz: if cx < box.mincx or cx >= box.maxcx or cz < box.mincz or cz >= box.maxcz:
self.level.deleteChunk(cx,cz) self.level.deleteChunk(cx,cz)
i+=1;
print "Pruned {0} chunks." .format(oldChunkCount-len(self.level.presentChunks)) print "Pruned {0} chunks." .format(i)
def _relight(self, command): def _relight(self, command):
""" """
@ -751,7 +748,7 @@ class mce(object):
chunks = itertools.product(range(box.mincx, box.maxcx),range(box.mincz, box.maxcz)) chunks = itertools.product(range(box.mincx, box.maxcx),range(box.mincz, box.maxcz))
else: else:
chunks = self.level.presentChunks chunks = self.level.allChunks
self.level.generateLights(chunks) self.level.generateLights(chunks)

View File

@ -41,10 +41,13 @@ ourworld = mclevel.fromFile("C:\\Minecraft\\OurWorld");
# Convenience method to load a numbered world from the saves folder. # Convenience method to load a numbered world from the saves folder.
world1 = mclevel.loadWorldNumber(1); world1 = mclevel.loadWorldNumber(1);
# Find out which chunks are present # Find out which chunks are present. Doing this will scan the chunk folders the
chunkPositions = world1.presentChunks # first time it is used. If you already know where you want to be, skip to
# world1.getChunk(xPos, zPos)
# presentChunks returns a list of tuples (xPos, zPos) chunkPositions = world1.allChunks
# allChunks returns a list of tuples (xPos, zPos)
xPos, zPos = chunkPositions[0]; xPos, zPos = chunkPositions[0];
# retrieve an InfdevChunk object. getChunk is a special method; # retrieve an InfdevChunk object. getChunk is a special method;
@ -315,7 +318,7 @@ def unpack_first(func):
class MCLevel(object): class MCLevel(object):
""" MCLevel is an abstract class providing many routines to the different level types, """ MCLevel is an abstract class providing many routines to the different level types,
including a common copyEntitiesFrom built on class-specific routines, and including a common copyEntitiesFrom built on class-specific routines, and
a dummy getChunk/getPresentChunks for the finite levels. a dummy getChunk/allChunks for the finite levels.
MCLevel subclasses must have Width, Length, and Height attributes. The first two are always zero for infinite levels. MCLevel subclasses must have Width, Length, and Height attributes. The first two are always zero for infinite levels.
Subclasses must also have Blocks, and optionally Data and BlockLight. Subclasses must also have Blocks, and optionally Data and BlockLight.
@ -337,6 +340,7 @@ class MCLevel(object):
players = ["Player"] players = ["Player"]
dimNo = 0; dimNo = 0;
parentWorld = None parentWorld = None
world = None
@classmethod @classmethod
def isLevel(cls, filename): def isLevel(cls, filename):
"""Tries to find out whether the given filename can be loaded """Tries to find out whether the given filename can be loaded
@ -422,14 +426,14 @@ class MCLevel(object):
self.root_tag = nbt.load(buf=fromstring(data, dtype='uint8')); self.root_tag = nbt.load(buf=fromstring(data, dtype='uint8'));
except Exception, e: except Exception, e:
error( u"Malformed NBT data in file: {0} ({1})".format(self.filename, e) ) error( u"Malformed NBT data in file: {0} ({1})".format(self.filename, e) )
self.world.malformedChunk(*self.chunkPosition); if self.world: self.world.malformedChunk(*self.chunkPosition);
raise ChunkMalformed, self.filename raise ChunkMalformed, self.filename
try: try:
self.shapeChunkData() self.shapeChunkData()
except KeyError: except KeyError:
error( u"Incorrect chunk format in file: " + self.filename ) error( u"Incorrect chunk format in file: " + self.filename )
self.world.malformedChunk(*self.chunkPosition); if self.world: self.world.malformedChunk(*self.chunkPosition);
raise ChunkMalformed, self.filename raise ChunkMalformed, self.filename
self.dataIsPacked = True; self.dataIsPacked = True;
@ -442,18 +446,22 @@ class MCLevel(object):
return None return None
def addEntity(self, *args): pass def addEntity(self, *args): pass
def addTileEntity(self, *args): pass def addTileEntity(self, *args): pass
def loadChunk(self, cx, cz ):
pass;
@property @property
def presentChunks(self): def loadedChunks(self):
return itertools.product(xrange(0, self.Width+15>>4), xrange(0, self.Length+15>>4)) return itertools.product(xrange(0, self.Width+15>>4), xrange(0, self.Length+15>>4))
@property
def presentChunks(self): return self.allChunks #backward compatibility
@property
def allChunks(self):
return self.loadedChunks
def getChunk(self, cx, cz): def getChunk(self, cx, cz):
#if not hasattr(self, 'whiteLight'): #if not hasattr(self, 'whiteLight'):
#self.whiteLight = array([[[15] * self.Height] * 16] * 16, uint8); #self.whiteLight = array([[[15] * self.Height] * 16] * 16, uint8);
class FakeChunk: class FakeChunk:
def load(self):pass def load(self):pass
def compress(self):pass def compress(self):pass
@ -696,6 +704,9 @@ class MCLevel(object):
''' '''
info( u"Identifying " + filename ) info( u"Identifying " + filename )
class LoadingError(RuntimeError): pass
if not filename: if not filename:
raise IOError, "File not found: "+filename raise IOError, "File not found: "+filename
if not os.path.exists(filename): if not os.path.exists(filename):
@ -761,10 +772,13 @@ class MCLevel(object):
except Exception, e: except Exception, e:
info( u"Error during NBT load: {0!r}".format(e) ) info( u"Error during NBT load: {0!r}".format(e) )
info( u"Fallback: Detected compressed flat block array, yzx ordered " ) info( u"Fallback: Detected compressed flat block array, yzx ordered " )
lev = MCJavaLevel(filename, data); try:
lev.compressed = compressed; lev = MCJavaLevel(filename, data);
return lev; lev.compressed = compressed;
return lev;
except Exception, e2:
raise LoadingError, ("Multiple errors encountered", e, e2)
else: else:
if(MCIndevLevel._isTagLevel(root_tag)): if(MCIndevLevel._isTagLevel(root_tag)):
info( u"Detected Indev .mclevel" ) info( u"Detected Indev .mclevel" )
@ -1456,7 +1470,10 @@ class InfdevChunk(MCLevel):
if create: if create:
self.create(); self.create();
else:
if not world.containsChunk(*chunkPosition):
raise ChunkNotPresent("File not found: {0}", self.filename)
def compress(self): def compress(self):
if not self.dirty: if not self.dirty:
@ -1804,14 +1821,14 @@ class MCInfdevOldLevel(MCLevel):
return False return False
def getWorldBounds(self): def getWorldBounds(self):
if len(self.presentChunks) == 0: if len(self.allChunks) == 0:
return BoundingBox( (0,0,0), (0,0,0) ) return BoundingBox( (0,0,0), (0,0,0) )
presentChunksArray = array(self.presentChunks) allChunksArray = array(list(self.allChunks), dtype='int32')
mincx = min(presentChunksArray[:,0]) mincx = min(allChunksArray[:,0])
maxcx = max(presentChunksArray[:,0]) maxcx = max(allChunksArray[:,0])
mincz = min(presentChunksArray[:,1]) mincz = min(allChunksArray[:,1])
maxcz = max(presentChunksArray[:,1]) maxcz = max(allChunksArray[:,1])
origin = (mincx << 4, 0, mincz << 4) origin = (mincx << 4, 0, mincz << 4)
size = ((maxcx-mincx+1) << 4, 128, (maxcz-mincz+1) << 4) size = ((maxcx-mincx+1) << 4, 128, (maxcz-mincz+1) << 4)
@ -1950,7 +1967,8 @@ class MCInfdevOldLevel(MCLevel):
self.filename = os.path.join(self.worldDir, "level.dat") self.filename = os.path.join(self.worldDir, "level.dat")
#maps (cx,cz) pairs to InfdevChunks #maps (cx,cz) pairs to InfdevChunks
self._presentChunksDict = None; self._loadedChunks = {}
self._allChunks = None
self.dimensions = {}; self.dimensions = {};
#used to limit memory usage #used to limit memory usage
@ -2008,7 +2026,7 @@ class MCInfdevOldLevel(MCLevel):
def preloadChunkPaths(self): def preloadChunkPaths(self):
info( u"Scanning for chunks..." ) info( u"Scanning for chunks..." )
worldDirs = os.listdir(self.worldDir); worldDirs = os.listdir(self.worldDir);
self._presentChunksDict = {}; self._allChunks = set()
for dirname in worldDirs: for dirname in worldDirs:
if(dirname in self.dirhashes): if(dirname in self.dirhashes):
@ -2030,25 +2048,20 @@ class MCInfdevOldLevel(MCLevel):
except Exception, e: except Exception, e:
info( 'Skipped file {0} ({1})'.format('.'.join(c), e) ) info( 'Skipped file {0} ({1})'.format('.'.join(c), e) )
continue continue
self._presentChunks[ (cx, cz) ] = InfdevChunk(self, (cx, cz));
info( u"Found {0} chunks.".format(len(self._presentChunks)) ) self._allChunks.add( (cx,cz) )
#self._presentChunks.update(dict(zip(chunks, fullpaths)));
## for filename, chunk in zip(fullpaths, chunks):
## chunkfh = file(filename, 'rb')
## self.compressedTags[chunk] = chunkfh.read();
## chunkfh.close();
#
info( u"Found {0} chunks.".format(len(self.allChunks)) )
def compressAllChunks(self): def compressAllChunks(self):
for ch in self._presentChunks.itervalues(): for ch in self._loadedChunks.itervalues():
ch.compress(); ch.compress();
def compressChunk(self, x, z): def compressChunk(self, x, z):
if not (x,z) in self._presentChunks: return; #not an error if not (x,z) in self._loadedChunks: return; #not an error
self._presentChunks[x,z].compress() self._loadedChunks[x,z].compress()
decompressedChunkLimit = 2048 # about 320 megabytes decompressedChunkLimit = 2048 # about 320 megabytes
loadedChunkLimit = 8192 # from 8mb to 800mb depending on chunk contents loadedChunkLimit = 8192 # from 8mb to 800mb depending on chunk contents
@ -2088,7 +2101,7 @@ class MCInfdevOldLevel(MCLevel):
def chunkFilenameAt(self, x, y, z): def chunkFilenameAt(self, x, y, z):
cx = x >> 4 cx = x >> 4
cz = z >> 4 cz = z >> 4
return self._presentChunks.get( (cx, cz) ).filename return self._loadedChunks.get( (cx, cz) ).filename
base36alphabet = "0123456789abcdefghijklmnopqrstuvwxyz" base36alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"
def decbase36(self, s): def decbase36(self, s):
@ -2253,51 +2266,64 @@ class MCInfdevOldLevel(MCLevel):
#the heightmap is ordered differently because in minecraft it is a flat array #the heightmap is ordered differently because in minecraft it is a flat array
@property @property
def presentChunks(self): def loadedChunks(self):
return self._presentChunks.keys(); return self._loadedChunks.keys();
@property @property
def _presentChunks(self): def allChunks(self):
if self._presentChunksDict is None: if self._allChunks is None:
self.preloadChunkPaths(); self.preloadChunkPaths()
return self._presentChunksDict return self._allChunks;
def getChunks(self, chunks = None): def getChunks(self, chunks = None):
""" pass a list of chunk coordinate tuples to get a list of InfdevChunks. """ pass a list of chunk coordinate tuples to get a list of InfdevChunks.
pass nothing for a list of every chunk in the level. pass nothing for a list of every chunk in the level.
the chunks are automatically loaded.""" the chunks are automatically loaded."""
if chunks is None: chunks = self.presentChunks; if chunks is None: chunks = self.allChunks;
return [self.getChunk(cx,cz) for (cx,cz) in chunks if (cx,cz) in self._presentChunks] return [self.getChunk(cx,cz) for (cx,cz) in chunks if self.containsChunk(cx,cz)]
def _makeChunk(self, cx,cz):
"""return the chunk object at the given position, creating it if necessary.
because loading the chunk is done later, accesses to chunk attributes may
raise ChunkMalformed"""
if not self.containsChunk(cx,cz):
raise ChunkNotPresent, (cx,cz);
if not (cx,cz) in self._loadedChunks:
self._loadedChunks[cx,cz] = InfdevChunk(self, (cx, cz));
return self._loadedChunks[cx,cz]
def getChunk(self, cx, cz): def getChunk(self, cx, cz):
""" read the chunk from disk, load it, and return it. """ read the chunk from disk, load it, and return it.
decompression and unpacking is done lazily.""" decompression and unpacking is done lazily."""
if not (cx,cz) in self._presentChunks: c = self._makeChunk(cx,cz)
raise ChunkNotPresent, "Chunk {0} not present".format((cx,cz))
c = self._presentChunks[cx,cz]
c.load(); c.load();
if not (cx,cz) in self._presentChunks: if not (cx,cz) in self._loadedChunks:
raise ChunkMalformed, "Chunk {0} malformed".format((cx,cz)) raise ChunkMalformed, "Chunk {0} malformed".format((cx,cz))
self.world.malformedChunk(*self.chunkPosition); self.world.malformedChunk(*self.chunkPosition);
return c; return c;
def markDirtyChunk(self, cx, cz): def markDirtyChunk(self, cx, cz):
if not (cx,cz) in self._presentChunks: return if not (cx,cz) in self._loadedChunks: return
self._presentChunks[cx,cz].chunkChanged(); self._loadedChunks[cx,cz].chunkChanged();
def saveInPlace(self): def saveInPlace(self):
for level in self.dimensions.itervalues(): for level in self.dimensions.itervalues():
level.saveInPlace(True); level.saveInPlace(True);
dirtyChunkCount = 0; dirtyChunkCount = 0;
for chunk in self._presentChunks.itervalues(): if self._loadedChunks:
if chunk.dirty: for chunk in self._loadedChunks.itervalues():
dirtyChunkCount += 1; if chunk.dirty:
chunk.save(); dirtyChunkCount += 1;
chunk.save();
self.root_tag.save(self.filename); self.root_tag.save(self.filename);
@ -2311,11 +2337,12 @@ class MCInfdevOldLevel(MCLevel):
startTime = datetime.now(); startTime = datetime.now();
if dirtyChunks is None: if dirtyChunks is None:
dirtyChunks = filter(lambda x: x.needsLighting, self._presentChunks.values()); dirtyChunks = (ch for ch in self._loadedChunks.itervalues() if ch.needsLighting)
else: else:
dirtyChunks = [self._presentChunks[c] for c in dirtyChunks if c in self._presentChunks]; dirtyChunks = (self._makeChunk(*c) for c in dirtyChunks if self.containsChunk(*c))
dirtyChunks = sorted(list(dirtyChunks), key=lambda x:x.chunkPosition) dirtyChunks = sorted(dirtyChunks, key=lambda x:x.chunkPosition)
#at 150k per loaded chunk, #at 150k per loaded chunk,
maxLightingChunks = 4000 maxLightingChunks = 4000
@ -2383,8 +2410,8 @@ class MCInfdevOldLevel(MCLevel):
#relight all blocks in neighboring chunks in case their light source disappeared. #relight all blocks in neighboring chunks in case their light source disappeared.
cx,cz = ch.chunkPosition cx,cz = ch.chunkPosition
for dx,dz in itertools.product( (-1, 0, 1), (-1, 0, 1) ): for dx,dz in itertools.product( (-1, 0, 1), (-1, 0, 1) ):
if (cx+dx,cz+dz) in self._presentChunks: if (cx+dx,cz+dz) in self._loadedChunks:
dirtyChunks.add(self._presentChunks[(cx+dx,cz+dz)]); dirtyChunks.add(self._loadedChunks[(cx+dx,cz+dz)]);
dirtyChunks = sorted(dirtyChunks, key=lambda x:x.chunkPosition) dirtyChunks = sorted(dirtyChunks, key=lambda x:x.chunkPosition)
@ -2453,14 +2480,14 @@ class MCInfdevOldLevel(MCLevel):
print "Chunk error during relight, chunk skipped: ", e print "Chunk error during relight, chunk skipped: ", e
continue; continue;
for dir,dx,dy,dz in ( (FaceXDecreasing,-1,0,0), for dir,dx,dz in ( (FaceXDecreasing,-1,0),
(FaceXIncreasing,1,0,0), (FaceXIncreasing,1,0),
(FaceZDecreasing,0,0, -1), (FaceZDecreasing,0, -1),
(FaceZIncreasing,0,0, 1) ): (FaceZIncreasing,0, 1) ):
try: try:
neighboringChunks[dir] = self.getChunk(cx+dx,cz+dz) neighboringChunks[dir] = self.getChunk(cx+dx,cz+dz)
except (ChunkNotPresent, ChunkMalformed): except (ChunkNotPresent, ChunkMalformed):
neighboringChunks[dir] = zeroChunk; neighboringChunks[dir] = zeroChunk;
chunkLa = la[chunk.Blocks]+1; chunkLa = la[chunk.Blocks]+1;
@ -2719,7 +2746,7 @@ class MCInfdevOldLevel(MCLevel):
def getAllChunkSlices(self): def getAllChunkSlices(self):
for cpos in self.presentChunks: for cpos in self.allChunks:
xPos, zPos = cpos xPos, zPos = cpos
try: try:
chunk = self.getChunk(xPos, zPos) chunk = self.getChunk(xPos, zPos)
@ -2917,7 +2944,7 @@ class MCInfdevOldLevel(MCLevel):
for dx, dz in itertools.product( (-1, 0, 1), (-1, 0, 1) ): for dx, dz in itertools.product( (-1, 0, 1), (-1, 0, 1) ):
ncPos = (cx+dx, cz+dz); ncPos = (cx+dx, cz+dz);
if ncPos not in changedChunkPositions: if ncPos not in changedChunkPositions:
ch = self._presentChunks.get((cx,cz), None); ch = self._loadedChunks.get((cx,cz), None);
if ch: if ch:
ch.needsLighting = True ch.needsLighting = True
@ -2957,17 +2984,21 @@ class MCInfdevOldLevel(MCLevel):
return self.containsChunk(x>>4, z>>4) return self.containsChunk(x>>4, z>>4)
def containsChunk(self, cx, cz): def containsChunk(self, cx, cz):
return (cx, cz) in self._presentChunks; if self._allChunks is not None: return (cx, cz) in self._allChunks;
if (cx,cz) in self._loadedChunks: return True;
return os.path.exists(self.chunkFilename(cx,cz))
def malformedChunk(self, cx, cz): def malformedChunk(self, cx, cz):
debug( u"Forgetting malformed chunk {0} ({1})".format((cx,cz), self.chunkFilename(cx,cz)) ) debug( u"Forgetting malformed chunk {0} ({1})".format((cx,cz), self.chunkFilename(cx,cz)) )
if (cx,cz) in self._presentChunks: if (cx,cz) in self._loadedChunks:
del self._presentChunks[(cx,cz)] del self._loadedChunks[(cx,cz)]
self._bounds = None self._bounds = None
def createChunk(self, cx, cz): def createChunk(self, cx, cz):
if (cx,cz) in self._presentChunks: raise ValueError, "{0}:Chunk {1} already present!".format(self, (cx,cz) ) if (cx,cz) in self._loadedChunks: raise ValueError, "{0}:Chunk {1} already present!".format(self, (cx,cz) )
self._presentChunks[cx,cz] = InfdevChunk(self, (cx,cz), create = True) if self._allChunks is not None: self._allChunks.add( (cx,cz) )
self._loadedChunks[cx,cz] = InfdevChunk(self, (cx,cz), create = True)
self._bounds = None self._bounds = None
def createChunks(self, chunks): def createChunks(self, chunks):
@ -2976,7 +3007,7 @@ class MCInfdevOldLevel(MCLevel):
ret = []; ret = [];
for cx,cz in chunks: for cx,cz in chunks:
i+=1; i+=1;
if not ((cx,cz) in self._presentChunks): if not ((cx,cz) in self._loadedChunks):
ret.append( (cx,cz) ) ret.append( (cx,cz) )
self.createChunk(cx,cz); self.createChunk(cx,cz);
self.compressChunk(cx,cz); self.compressChunk(cx,cz);
@ -2993,20 +3024,25 @@ class MCInfdevOldLevel(MCLevel):
return self.createChunks(box.chunkPositions); return self.createChunks(box.chunkPositions);
def deleteChunk(self, cx, cz): def deleteChunk(self, cx, cz):
if not (cx,cz) in self._presentChunks: return; if not (cx,cz) in self._loadedChunks: return;
self._presentChunks[(cx,cz)].remove(); self._loadedChunks[(cx,cz)].remove();
if self._allChunks is not None: self._allChunks.discard( (cx,cz) )
del self._presentChunks[(cx,cz)] del self._loadedChunks[(cx,cz)]
self._bounds = None self._bounds = None
def deleteChunksInBox(self, box): def deleteChunksInBox(self, box):
info( u"Deleting {0} chunks in {1}".format((box.maxcx-box.mincx)*( box.maxcz-box.mincz), ((box.mincx, box.mincz), (box.maxcx, box.maxcz))) ) info( u"Deleting {0} chunks in {1}".format((box.maxcx-box.mincx)*( box.maxcz-box.mincz), ((box.mincx, box.mincz), (box.maxcx, box.maxcz))) )
i=0; i=0;
ret = [];
for cx,cz in itertools.product(xrange(box.mincx,box.maxcx), xrange(box.mincz, box.maxcz)): for cx,cz in itertools.product(xrange(box.mincx,box.maxcx), xrange(box.mincz, box.maxcz)):
i+=1; i+=1;
if ((cx,cz) in self._presentChunks): if self.containsChunk(cx,cz):
self.deleteChunk(cx,cz); self.deleteChunk(cx,cz);
ret.append( (cx,cz) )
assert not self.containsChunk(cx,cz), "Just deleted {0} but it didn't take".format((cx,cz)) assert not self.containsChunk(cx,cz), "Just deleted {0} but it didn't take".format((cx,cz))
if i%100 == 0: if i%100 == 0:
info( u"Chunk {0}...".format( i ) ) info( u"Chunk {0}...".format( i ) )
@ -3137,7 +3173,8 @@ class ZipSchematic (MCInfdevOldLevel):
zf = ZipFile(filename) zf = ZipFile(filename)
self.zipfile = zf self.zipfile = zf
self._presentChunksDict = None; self._loadedChunks = {};
self._allChunks = None
self.dimensions = {}; self.dimensions = {};
self.loadLevelDat(False, 0, 0) self.loadLevelDat(False, 0, 0)
@ -3172,9 +3209,12 @@ class ZipSchematic (MCInfdevOldLevel):
def saveInPlace(self): def saveInPlace(self):
raise NotImplementedError, "Cannot save zipfiles yet!" raise NotImplementedError, "Cannot save zipfiles yet!"
def containsChunk(self, cx, cz):
return (cx,cz) in self.allChunks
def preloadChunkPaths(self): def preloadChunkPaths(self):
info( u"Scanning for chunks..." ) info( u"Scanning for chunks..." )
self._presentChunksDict = {} self._allChunks = set()
infos = self.zipfile.infolist() infos = self.zipfile.infolist()
names = [i.filename.split('/') for i in infos] names = [i.filename.split('/') for i in infos]
@ -3188,9 +3228,10 @@ class ZipSchematic (MCInfdevOldLevel):
except Exception, e: except Exception, e:
info( 'Skipped file {0} ({1})'.format('.'.join(c), e) ) info( 'Skipped file {0} ({1})'.format('.'.join(c), e) )
continue continue
self._presentChunksDict[ (cx, cz) ] = InfdevChunk(self, (cx, cz)); #self._loadedChunks[ (cx, cz) ] = InfdevChunk(self, (cx, cz));
self._allChunks.add( (cx,cz) )
info( u"Found {0} chunks.".format(len(self._presentChunksDict)) )
info( u"Found {0} chunks.".format(len(self._allChunks)) )
def preloadDimensions(self): def preloadDimensions(self):
@ -3605,7 +3646,7 @@ def testAlphaLevels():
indevlevel = MCLevel.fromFile("hell.mclevel") indevlevel = MCLevel.fromFile("hell.mclevel")
level = MCInfdevOldLevel(filename="d:\Testworld"); level = MCInfdevOldLevel(filename="d:\Testworld");
for ch in level.presentChunks: level.deleteChunk(*ch) for ch in level.allChunks: level.deleteChunk(*ch)
level.createChunksInBox( BoundingBox((0,0,0), (32, 0, 32)) ) level.createChunksInBox( BoundingBox((0,0,0), (32, 0, 32)) )
level.copyBlocksFrom(indevlevel, BoundingBox((0,0,0), (256, 128, 256)), (-0, 0, 0)) level.copyBlocksFrom(indevlevel, BoundingBox((0,0,0), (256, 128, 256)), (-0, 0, 0))
assert all(level.getChunk(0,0).Blocks[0:16,0:16,0:indevlevel.Height] == indevlevel.conversionTableFromLevel(level)[indevlevel.Blocks[0:16,0:16,0:indevlevel.Height]]); assert all(level.getChunk(0,0).Blocks[0:16,0:16,0:indevlevel.Height] == indevlevel.conversionTableFromLevel(level)[indevlevel.Blocks[0:16,0:16,0:indevlevel.Height]]);

View File

@ -169,6 +169,9 @@ def main(argv):
with untared_content("regression_test/alpha.tar.gz") as directory: with untared_content("regression_test/alpha.tar.gz") as directory:
test_data = os.path.join(directory, "alpha") test_data = os.path.join(directory, "alpha")
passes = []
fails = []
for func, name, sha, args in alpha_tests: for func, name, sha, args in alpha_tests:
if any(fnmatch.fnmatch(name, x) for x in do_these_regressions): if any(fnmatch.fnmatch(name, x) for x in do_these_regressions):
if options.profile: if options.profile:
@ -177,9 +180,15 @@ def main(argv):
try: try:
func(test_data, sha, args) func(test_data, sha, args)
except RegressionError, e: except RegressionError, e:
print "Regression {0} failed: {1}".format(name, e) fails.append( "Regression {0} failed: {1}".format(name, e) )
print fails[-1]
else: else:
print "Regression {0!r} complete.".format(name) passes.append( "Regression {0!r} complete.".format(name) )
print passes[-1]
print "{0} tests passed.".format(len(passes))
for line in fails: print line;
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv)) sys.exit(main(sys.argv))