put everything through pydev's code auto-formatter

This commit is contained in:
David Vierra 2011-07-23 21:59:18 -10:00
parent 6b9e82c2e4
commit 225f813d28
12 changed files with 1228 additions and 1227 deletions

View File

@ -35,7 +35,7 @@ class Torch:
alphaMaterials.RedstoneTorchOn.ID, alphaMaterials.RedstoneTorchOn.ID,
alphaMaterials.RedstoneTorchOff.ID, alphaMaterials.RedstoneTorchOff.ID,
] ]
South = 1 South = 1
North = 2 North = 2
West = 3 West = 3
@ -45,7 +45,7 @@ genericFlipRotation(Torch)
class Ladder: class Ladder:
blocktypes = [alphaMaterials.Ladder.ID] blocktypes = [alphaMaterials.Ladder.ID]
East = 2 East = 2
West = 3 West = 3
North = 4 North = 4
@ -57,7 +57,7 @@ class Stair:
alphaMaterials.WoodenStairs.ID, alphaMaterials.WoodenStairs.ID,
alphaMaterials.StoneStairs.ID, alphaMaterials.StoneStairs.ID,
] ]
South = 0 South = 0
North = 1 North = 1
West = 2 West = 2
@ -66,13 +66,13 @@ genericFlipRotation(Stair)
class WallSign: class WallSign:
blocktypes = [alphaMaterials.WallSign.ID] blocktypes = [alphaMaterials.WallSign.ID]
East = 2 East = 2
West = 3 West = 3
North = 4 North = 4
South = 5 South = 5
genericFlipRotation(WallSign) genericFlipRotation(WallSign)
class Furnace: class Furnace:
blocktypes = [ blocktypes = [
alphaMaterials.Furnace.ID, alphaMaterials.Furnace.ID,
@ -87,15 +87,15 @@ genericFlipRotation(Furnace)
class Dispenser(Furnace): class Dispenser(Furnace):
blocktypes = [ blocktypes = [
alphaMaterials.Dispenser.ID, alphaMaterials.Dispenser.ID,
] ]
genericFlipRotation(Dispenser) genericFlipRotation(Dispenser)
class Pumpkin: class Pumpkin:
blocktypes = [ blocktypes = [
alphaMaterials.Pumpkin.ID, alphaMaterials.Pumpkin.ID,
alphaMaterials.JackOLantern.ID, alphaMaterials.JackOLantern.ID,
] ]
East = 0 East = 0
South = 1 South = 1
West = 2 West = 2
@ -104,14 +104,14 @@ genericFlipRotation(Pumpkin)
class Rail: class Rail:
blocktypes = [alphaMaterials.Rail.ID] blocktypes = [alphaMaterials.Rail.ID]
EastWest = 0 EastWest = 0
NorthSouth = 1 NorthSouth = 1
South = 2 South = 2
North = 3 North = 3
East = 4 East = 4
West = 5 West = 5
Northeast = 6 Northeast = 6
Southeast = 7 Southeast = 7
Southwest = 8 Southwest = 8
@ -143,7 +143,7 @@ def applyBit8(array):
def applyBit4(array): def applyBit4(array):
array[4:8] = array[0:4] | 0x4 array[4:8] = array[0:4] | 0x4
array[12:16] = array[8:12] | 0x4 array[12:16] = array[8:12] | 0x4
applyThrownBit = applyBit8 applyThrownBit = applyBit8
class PoweredDetectorRail(Rail): class PoweredDetectorRail(Rail):
@ -161,7 +161,7 @@ applyThrownBit(PoweredDetectorRail.flipEastWest)
applyThrownBit(PoweredDetectorRail.flipNorthSouth) applyThrownBit(PoweredDetectorRail.flipNorthSouth)
rotationClasses.append(PoweredDetectorRail) rotationClasses.append(PoweredDetectorRail)
class Lever: class Lever:
blocktypes = [alphaMaterials.Lever.ID] blocktypes = [alphaMaterials.Lever.ID]
ThrownBit = 0x8 ThrownBit = 0x8
@ -199,11 +199,11 @@ rotationClasses.append(Button)
class SignPost: class SignPost:
blocktypes = [alphaMaterials.Sign.ID] blocktypes = [alphaMaterials.Sign.ID]
#west is 0, increasing clockwise #west is 0, increasing clockwise
rotateLeft = arange(16, dtype='uint8') rotateLeft = arange(16, dtype='uint8')
rotateLeft -= 4 rotateLeft -= 4
rotateLeft &= 0xf rotateLeft &= 0xf
flipEastWest = arange(16, dtype='uint8') flipEastWest = arange(16, dtype='uint8')
flipNorthSouth = arange(16, dtype='uint8') flipNorthSouth = arange(16, dtype='uint8')
pass pass
@ -217,14 +217,14 @@ class Door:
] ]
TopHalfBit = 0x8 TopHalfBit = 0x8
SwungCCWBit = 0x4 SwungCCWBit = 0x4
Northeast = 0 Northeast = 0
Southeast = 1 Southeast = 1
Southwest = 2 Southwest = 2
Northwest = 3 Northwest = 3
rotateLeft = arange(16, dtype='uint8') rotateLeft = arange(16, dtype='uint8')
Door.rotateLeft[Door.Northeast] = Door.Northwest Door.rotateLeft[Door.Northeast] = Door.Northwest
Door.rotateLeft[Door.Southeast] = Door.Northeast Door.rotateLeft[Door.Southeast] = Door.Northeast
Door.rotateLeft[Door.Southwest] = Door.Southeast Door.rotateLeft[Door.Southwest] = Door.Southeast
@ -260,14 +260,14 @@ class RedstoneRepeater:
blocktypes = [ blocktypes = [
alphaMaterials.RedstoneRepeaterOff.ID, alphaMaterials.RedstoneRepeaterOff.ID,
alphaMaterials.RedstoneRepeaterOn.ID, alphaMaterials.RedstoneRepeaterOn.ID,
] ]
East = 0 East = 0
South = 1 South = 1
West = 2 West = 2
North = 3 North = 3
genericFlipRotation(RedstoneRepeater) genericFlipRotation(RedstoneRepeater)
#high bits of the repeater indicate repeater delay, and should be preserved #high bits of the repeater indicate repeater delay, and should be preserved
@ -285,7 +285,7 @@ applyOpenedBit = applyBit4
class Trapdoor: class Trapdoor:
blocktypes = [alphaMaterials.Trapdoor.ID] blocktypes = [alphaMaterials.Trapdoor.ID]
West = 0 West = 0
East = 1 East = 1
South = 2 South = 2
@ -299,7 +299,7 @@ applyOpenedBit(Trapdoor.flipNorthSouth)
applyPistonBit = applyBit8 applyPistonBit = applyBit8
class PistonBody: class PistonBody:
blocktypes = [alphaMaterials.StickyPiston.ID, alphaMaterials.Piston.ID] blocktypes = [alphaMaterials.StickyPiston.ID, alphaMaterials.Piston.ID]
East = 2 East = 2
West = 3 West = 3
North = 4 North = 4
@ -308,36 +308,36 @@ genericFlipRotation(PistonBody)
applyPistonBit(PistonBody.rotateLeft) applyPistonBit(PistonBody.rotateLeft)
applyPistonBit(PistonBody.flipEastWest) applyPistonBit(PistonBody.flipEastWest)
applyPistonBit(PistonBody.flipNorthSouth) applyPistonBit(PistonBody.flipNorthSouth)
class PistonHead(PistonBody): class PistonHead(PistonBody):
blocktypes = [alphaMaterials.PistonHead.ID] blocktypes = [alphaMaterials.PistonHead.ID]
rotationClasses.append(PistonHead) rotationClasses.append(PistonHead)
def masterRotationTable(rotationFunc): def masterRotationTable(rotationFunc):
# compute a 256x16 table mapping each possible blocktype/data combination to # compute a 256x16 table mapping each possible blocktype/data combination to
# the resulting data when the block is rotated # the resulting data when the block is rotated
table = zeros( (256, 16), dtype='uint8') table = zeros((256, 16), dtype='uint8')
table[:] = arange(16, dtype='uint8') table[:] = arange(16, dtype='uint8')
for cls in rotationClasses: for cls in rotationClasses:
for blocktype in cls.blocktypes: for blocktype in cls.blocktypes:
table[blocktype] = rotationFunc(cls) table[blocktype] = rotationFunc(cls)
return table return table
class BlockRotation: class BlockRotation:
rotateLeft = masterRotationTable(lambda cls:cls.rotateLeft); rotateLeft = masterRotationTable(lambda cls:cls.rotateLeft);
flipEastWest = masterRotationTable(lambda cls:cls.flipEastWest); flipEastWest = masterRotationTable(lambda cls:cls.flipEastWest);
flipNorthSouth = masterRotationTable(lambda cls:cls.flipNorthSouth); flipNorthSouth = masterRotationTable(lambda cls:cls.flipNorthSouth);
def FlipNorthSouth(blocks, data): def FlipNorthSouth(blocks, data):
data[:] = BlockRotation.flipNorthSouth[blocks, data] data[:] = BlockRotation.flipNorthSouth[blocks, data]
def FlipEastWest(blocks, data): def FlipEastWest(blocks, data):
data[:] = BlockRotation.flipEastWest[blocks, data] data[:] = BlockRotation.flipEastWest[blocks, data]
def RotateLeft(blocks, data): def RotateLeft(blocks, data):
data[:] = BlockRotation.rotateLeft[blocks, data] data[:] = BlockRotation.rotateLeft[blocks, data]

View File

@ -11,7 +11,7 @@ class TileEntity(object):
@classmethod @classmethod
def pos(cls, tag): def pos(cls, tag):
return [tag[a].value for a in 'xyz'] return [tag[a].value for a in 'xyz']
@classmethod @classmethod
def setpos(cls, tag, pos): def setpos(cls, tag, pos):
for a, p in zip('xyz', pos): for a, p in zip('xyz', pos):
@ -23,21 +23,21 @@ class Entity(object):
if "Pos" not in tag: if "Pos" not in tag:
print tag print tag
return [a.value for a in tag["Pos"]] return [a.value for a in tag["Pos"]]
@classmethod @classmethod
def setpos(cls, tag, pos): def setpos(cls, tag, pos):
tag["Pos"] = TAG_List([TAG_Int(p) for p in pos]) tag["Pos"] = TAG_List([TAG_Int(p) for p in pos])
@classmethod @classmethod
def copyWithOffset(cls, entity, copyOffset): def copyWithOffset(cls, entity, copyOffset):
eTag = deepcopy(entity) eTag = deepcopy(entity)
positionTags = map(lambda p, co: nbt.TAG_Double(p.value+co), eTag["Pos"], copyOffset) positionTags = map(lambda p, co: nbt.TAG_Double(p.value + co), eTag["Pos"], copyOffset)
eTag["Pos"] = TAG_List(positionTags) eTag["Pos"] = TAG_List(positionTags)
if eTag["id"].value == "Painting": if eTag["id"].value == "Painting":
eTag["TileX"].value += copyOffset[0] eTag["TileX"].value += copyOffset[0]
eTag["TileY"].value += copyOffset[1] eTag["TileY"].value += copyOffset[1]
eTag["TileZ"].value += copyOffset[2] eTag["TileZ"].value += copyOffset[2]
return eTag return eTag

160
indev.py
View File

@ -86,115 +86,115 @@ __all__ = ["MCIndevLevel"]
class MCIndevLevel(MCLevel): class MCIndevLevel(MCLevel):
""" IMPORTANT: self.Blocks and self.Data are indexed with [x,z,y] via axis """ IMPORTANT: self.Blocks and self.Data are indexed with [x,z,y] via axis
swapping to be consistent with infinite levels.""" swapping to be consistent with infinite levels."""
hasEntities = True hasEntities = True
def setPlayerSpawnPosition(self, pos, player = None): def setPlayerSpawnPosition(self, pos, player=None):
assert len(pos) == 3 assert len(pos) == 3
self.Spawn = array(pos); self.Spawn = array(pos);
def playerSpawnPosition(self, player = None): def playerSpawnPosition(self, player=None):
return self.Spawn; return self.Spawn;
def setPlayerPosition(self, pos, player = "Ignored"): def setPlayerPosition(self, pos, player="Ignored"):
for x in self.root_tag["Entities"]: for x in self.root_tag["Entities"]:
if x["id"].value == "LocalPlayer": if x["id"].value == "LocalPlayer":
x["Pos"] = TAG_List([TAG_Float(p) for p in pos]) x["Pos"] = TAG_List([TAG_Float(p) for p in pos])
def getPlayerPosition(self, player = "Ignored"): def getPlayerPosition(self, player="Ignored"):
for x in self.root_tag["Entities"]: for x in self.root_tag["Entities"]:
if x["id"].value == "LocalPlayer": if x["id"].value == "LocalPlayer":
return array(map(lambda x:x.value, x["Pos"])); return array(map(lambda x:x.value, x["Pos"]));
def setPlayerOrientation(self, yp, player = "Ignored"): def setPlayerOrientation(self, yp, player="Ignored"):
for x in self.root_tag["Entities"]: for x in self.root_tag["Entities"]:
if x["id"].value == "LocalPlayer": if x["id"].value == "LocalPlayer":
x["Rotation"] = TAG_List([TAG_Float(p) for p in yp]) x["Rotation"] = TAG_List([TAG_Float(p) for p in yp])
def playerOrientation(self, player = "Ignored"): def playerOrientation(self, player="Ignored"):
""" returns (yaw, pitch) """ """ returns (yaw, pitch) """
for x in self.root_tag["Entities"]: for x in self.root_tag["Entities"]:
if x["id"].value == "LocalPlayer": if x["id"].value == "LocalPlayer":
return array(map(lambda x:x.value, x["Rotation"])); return array(map(lambda x:x.value, x["Rotation"]));
def setBlockDataAt(self, x,y,z, newdata): def setBlockDataAt(self, x, y, z, newdata):
if x<0 or y<0 or z<0: return 0 if x < 0 or y < 0 or z < 0: return 0
if x>=self.Width or y>=self.Height or z>=self.Length: return 0; if x >= self.Width or y >= self.Height or z >= self.Length: return 0;
self.Data[x,z,y] = (newdata & 0xf); self.Data[x, z, y] = (newdata & 0xf);
def blockDataAt(self, x, y, z): def blockDataAt(self, x, y, z):
if x<0 or y<0 or z<0: return 0 if x < 0 or y < 0 or z < 0: return 0
if x>=self.Width or y>=self.Height or z>=self.Length: return 0; if x >= self.Width or y >= self.Height or z >= self.Length: return 0;
return self.Data[x,z,y]; return self.Data[x, z, y];
def blockLightAt(self, x, y, z): def blockLightAt(self, x, y, z):
if x<0 or y<0 or z<0: return 0 if x < 0 or y < 0 or z < 0: return 0
if x>=self.Width or y>=self.Height or z>=self.Length: return 0; if x >= self.Width or y >= self.Height or z >= self.Length: return 0;
return self.BlockLight[x,z,y]; return self.BlockLight[x, z, y];
def __repr__(self): def __repr__(self):
return u"MCIndevLevel({0}): {1}W {2}L {3}H".format(self.filename, self.Width, self.Length, self.Height) return u"MCIndevLevel({0}): {1}W {2}L {3}H".format(self.filename, self.Width, self.Length, self.Height)
@classmethod @classmethod
def _isTagLevel(cls, root_tag): def _isTagLevel(cls, root_tag):
return "MinecraftLevel" == root_tag.name return "MinecraftLevel" == root_tag.name
def __init__(self, root_tag = None, filename = ""): def __init__(self, root_tag=None, filename=""):
self.Width = 0 self.Width = 0
self.Height = 0 self.Height = 0
self.Length = 0 self.Length = 0
self.Blocks = array([], uint8) self.Blocks = array([], uint8)
self.Data = array([], uint8) self.Data = array([], uint8)
self.Spawn = (0,0,0) self.Spawn = (0, 0, 0)
self.filename = filename; self.filename = filename;
if root_tag: if root_tag:
self.root_tag = root_tag; self.root_tag = root_tag;
mapTag = root_tag[Map]; mapTag = root_tag[Map];
self.Width = mapTag[Width].value self.Width = mapTag[Width].value
self.Length = mapTag[Length].value self.Length = mapTag[Length].value
self.Height = mapTag[Height].value self.Height = mapTag[Height].value
mapTag[Blocks].value.shape = (self.Height, self.Length, self.Width)
self.Blocks = swapaxes(mapTag[Blocks].value, 0, 2)
mapTag[Data].value.shape = (self.Height, self.Length, self.Width)
self.Data = swapaxes(mapTag[Data].value, 0, 2)
mapTag[Blocks].value.shape = (self.Height, self.Length, self.Width)
self.Blocks = swapaxes(mapTag[Blocks].value, 0, 2)
mapTag[Data].value.shape = (self.Height, self.Length, self.Width)
self.Data = swapaxes(mapTag[Data].value, 0, 2)
self.BlockLight = self.Data & 0xf self.BlockLight = self.Data & 0xf
self.Data >>= 4 self.Data >>= 4
self.Spawn = [mapTag[Spawn][i].value for i in range(3)]; self.Spawn = [mapTag[Spawn][i].value for i in range(3)];
if not Entities in root_tag: if not Entities in root_tag:
root_tag[Entities] = TAG_List(); root_tag[Entities] = TAG_List();
self.Entities = root_tag[Entities] self.Entities = root_tag[Entities]
if not TileEntities in root_tag: if not TileEntities in root_tag:
root_tag[TileEntities] = TAG_List(); root_tag[TileEntities] = TAG_List();
self.TileEntities = root_tag[TileEntities] self.TileEntities = root_tag[TileEntities]
if len(filter(lambda x:x['id'].value=='LocalPlayer', root_tag[Entities])) == 0: #omen doesn't make a player entity
p=TAG_Compound() if len(filter(lambda x:x['id'].value == 'LocalPlayer', root_tag[Entities])) == 0: #omen doesn't make a player entity
p = TAG_Compound()
p['id'] = TAG_String('LocalPlayer') p['id'] = TAG_String('LocalPlayer')
p['Pos'] = TAG_List([TAG_Float(0.), TAG_Float(64.), TAG_Float(0.)]) p['Pos'] = TAG_List([TAG_Float(0.), TAG_Float(64.), TAG_Float(0.)])
p['Rotation'] = TAG_List([TAG_Float(0.), TAG_Float(45.)]) p['Rotation'] = TAG_List([TAG_Float(0.), TAG_Float(45.)])
root_tag[Entities].append(p) root_tag[Entities].append(p)
#self.saveInPlace(); #self.saveInPlace();
else: else:
info( u"Creating new Indev levels is not yet implemented.!" ) info(u"Creating new Indev levels is not yet implemented.!")
raise ValueError, "Can't do that yet" raise ValueError, "Can't do that yet"
# self.SurroundingGroundHeight = root_tag[Environment][SurroundingGroundHeight].value # self.SurroundingGroundHeight = root_tag[Environment][SurroundingGroundHeight].value
# self.SurroundingGroundType = root_tag[Environment][SurroundingGroundType].value # self.SurroundingGroundType = root_tag[Environment][SurroundingGroundType].value
@ -212,65 +212,65 @@ class MCIndevLevel(MCLevel):
# self.Author = self.root_tag[About][Author].value # self.Author = self.root_tag[About][Author].value
# self.CreatedOn = self.root_tag[About][CreatedOn].value # self.CreatedOn = self.root_tag[About][CreatedOn].value
def rotateLeft(self): def rotateLeft(self):
MCLevel.rotateLeft(self); MCLevel.rotateLeft(self);
self.Data = swapaxes(self.Data, 1, 0)[:,::-1,:]; #x=y; y=-x self.Data = swapaxes(self.Data, 1, 0)[:, ::-1, :]; #x=y; y=-x
torchRotation = array([0, 4, 3, 1, 2, 5, torchRotation = array([0, 4, 3, 1, 2, 5,
6, 7, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15]); 8, 9, 10, 11, 12, 13, 14, 15]);
torchIndexes = (self.Blocks == self.materials.Torch.ID) torchIndexes = (self.Blocks == self.materials.Torch.ID)
info( u"Rotating torches: {0}".format( len(torchIndexes.nonzero()[0]) ) ) info(u"Rotating torches: {0}".format(len(torchIndexes.nonzero()[0])))
self.Data[torchIndexes] = torchRotation[self.Data[torchIndexes]] self.Data[torchIndexes] = torchRotation[self.Data[torchIndexes]]
def saveToFile(self, filename = None): def saveToFile(self, filename=None):
if filename == None: filename = self.filename; if filename == None: filename = self.filename;
if filename == None: if filename == None:
warn( u"Attempted to save an unnamed file in place" ) warn(u"Attempted to save an unnamed file in place")
return; #you fool! return; #you fool!
self.Data <<= 4; self.Data <<= 4;
self.Data |= (self.BlockLight & 0xf) self.Data |= (self.BlockLight & 0xf)
self.Blocks = swapaxes(self.Blocks, 0, 2) self.Blocks = swapaxes(self.Blocks, 0, 2)
self.Data = swapaxes(self.Data, 0, 2) self.Data = swapaxes(self.Data, 0, 2)
mapTag = TAG_Compound( name=Map ); mapTag = TAG_Compound(name=Map);
mapTag[Width] = TAG_Short(self.Width); mapTag[Width] = TAG_Short(self.Width);
mapTag[Height] = TAG_Short(self.Height); mapTag[Height] = TAG_Short(self.Height);
mapTag[Length] = TAG_Short(self.Length); mapTag[Length] = TAG_Short(self.Length);
mapTag[Blocks] = TAG_Byte_Array(self.Blocks); mapTag[Blocks] = TAG_Byte_Array(self.Blocks);
mapTag[Data] = TAG_Byte_Array(self.Data); mapTag[Data] = TAG_Byte_Array(self.Data);
self.Blocks = swapaxes(self.Blocks, 0, 2) self.Blocks = swapaxes(self.Blocks, 0, 2)
self.Data = swapaxes(self.Data, 0, 2) self.Data = swapaxes(self.Data, 0, 2)
mapTag[Spawn] = TAG_List([TAG_Short(i) for i in self.Spawn]) mapTag[Spawn] = TAG_List([TAG_Short(i) for i in self.Spawn])
self.root_tag[Map] = mapTag; self.root_tag[Map] = mapTag;
self.root_tag[Map] self.root_tag[Map]
#output_file = gzip.open(self.filename, "wb", compresslevel=1) #output_file = gzip.open(self.filename, "wb", compresslevel=1)
try: try:
os.rename(filename, filename + ".old"); os.rename(filename, filename + ".old");
except Exception,e: except Exception, e:
pass pass
try: try:
self.root_tag.saveGzipped(filename); self.root_tag.saveGzipped(filename);
except: except:
os.rename(filename + ".old", filename); os.rename(filename + ".old", filename);
try: os.remove(filename + ".old"); try: os.remove(filename + ".old");
except Exception,e: except Exception, e:
pass pass
self.BlockLight = self.Data & 0xf self.BlockLight = self.Data & 0xf
self.Data >>= 4 self.Data >>= 4

View File

@ -257,20 +257,20 @@ items_txt = """
""" """
class ItemType (object): class ItemType (object):
def __init__(self, id, name, imagefile = None, imagecoords = None, maxdamage = 0, damagevalue = 0, stacksize = 64): def __init__(self, id, name, imagefile=None, imagecoords=None, maxdamage=0, damagevalue=0, stacksize=64):
self.id=id self.id = id
self.name=name self.name = name
self.imagefile=imagefile self.imagefile = imagefile
self.imagecoords=imagecoords self.imagecoords = imagecoords
self.maxdamage=maxdamage self.maxdamage = maxdamage
def __repr__(self): def __repr__(self):
return "ItemType({0}, '{1}')".format(self.id, self.name) return "ItemType({0}, '{1}')".format(self.id, self.name)
def __str__(self): def __str__(self):
return "ItemType {0}: {1}".format(self.id, self.name) return "ItemType {0}: {1}".format(self.id, self.name)
class Items (object): class Items (object):
items_txt = items_txt items_txt = items_txt
def __init__(self, filename = None): def __init__(self, filename=None):
if filename is None: if filename is None:
items_txt = self.items_txt items_txt = self.items_txt
else: else:
@ -281,9 +281,9 @@ class Items (object):
print "Error reading items.txt: ", e; print "Error reading items.txt: ", e;
print "Using internal data." print "Using internal data."
items_txt = self.items_txt items_txt = self.items_txt
self.itemtypes = {}; self.itemtypes = {};
for line in items_txt.split("\n"): for line in items_txt.split("\n"):
try: try:
line = line.strip() line = line.strip()
@ -293,7 +293,7 @@ class Items (object):
stacksize = 64 stacksize = 64
damagevalue = None damagevalue = None
maxdamage = 0 maxdamage = 0
fields = line.split(); fields = line.split();
if len(fields) >= 4: if len(fields) >= 4:
maxdamage = None; maxdamage = None;
@ -309,25 +309,25 @@ class Items (object):
id = int(id); id = int(id);
name = name.replace("_", " "); name = name.replace("_", " ");
imagecoords = imagecoords.split(","); imagecoords = imagecoords.split(",");
self.itemtypes[(id, damagevalue)] = ItemType(id, name, imagefile, imagecoords, maxdamage, damagevalue, stacksize) self.itemtypes[(id, damagevalue)] = ItemType(id, name, imagefile, imagecoords, maxdamage, damagevalue, stacksize)
except Exception, e: except Exception, e:
print "Error reading line:", e print "Error reading line:", e
print "Line: ", line print "Line: ", line
print print
self.names = dict((item.name, item.id) for item in self.itemtypes.itervalues()) self.names = dict((item.name, item.id) for item in self.itemtypes.itervalues())
def findItem(self, id=0, damage=None): def findItem(self, id=0, damage=None):
item = self.itemtypes.get((id, damage)) item = self.itemtypes.get((id, damage))
if item: return item if item: return item
item = self.itemtypes.get((id, None)) item = self.itemtypes.get((id, None))
if item: return item if item: return item
item = self.itemtypes.get((id, 0)) item = self.itemtypes.get((id, 0))
if item: return item if item: return item
raise ItemNotFound, "Item {0}:{1} not found".format(id, damage) raise ItemNotFound, "Item {0}:{1} not found".format(id, damage)
class ItemNotFound(KeyError): pass class ItemNotFound(KeyError): pass

636
level.py

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

584
mce.py

File diff suppressed because it is too large Load Diff

View File

@ -192,12 +192,12 @@ import sys
# we need to decode file paths from environment variables or else we get an error # we need to decode file paths from environment variables or else we get an error
# if they are formatted or joined to a unicode string # if they are formatted or joined to a unicode string
if sys.platform == "win32": if sys.platform == "win32":
#not sure why win32com is needed if the %APPDATA% var is available #not sure why win32com is needed if the %APPDATA% var is available
try: try:
import win32com.client import win32com.client
objShell = win32com.client.Dispatch("WScript.Shell") objShell = win32com.client.Dispatch("WScript.Shell")
minecraftDir = os.path.join(objShell.SpecialFolders("AppData"), u".minecraft") minecraftDir = os.path.join(objShell.SpecialFolders("AppData"), u".minecraft")
except Exception, e: except Exception, e:
@ -211,9 +211,9 @@ elif sys.platform == "darwin":
else: else:
minecraftDir = os.path.expanduser("~/.minecraft") minecraftDir = os.path.expanduser("~/.minecraft")
minecraftDir.decode(sys.getfilesystemencoding()); minecraftDir.decode(sys.getfilesystemencoding());
saveFileDir = os.path.join(minecraftDir, u"saves") saveFileDir = os.path.join(minecraftDir, u"saves")
#if sys.platform == "win32": #if sys.platform == "win32":
# from win32com.shell import shell, shellcon # from win32com.shell import shell, shellcon
# saveFileDir = shell.SHGetPathFromIDListEx ( # saveFileDir = shell.SHGetPathFromIDListEx (
@ -221,53 +221,53 @@ saveFileDir = os.path.join(minecraftDir, u"saves")
# ) # )
# #
def fromFile(filename, loadInfinite=True): def fromFile(filename, loadInfinite=True):
''' 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( u"Identifying " + filename ) info(u"Identifying " + filename)
class LoadingError(RuntimeError): pass 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):
raise IOError, "File not found: "+filename raise IOError, "File not found: " + filename
if (ZipSchematic._isLevel(filename)): if (ZipSchematic._isLevel(filename)):
info( "Zipfile found, attempting zipped infinite level" ) info("Zipfile found, attempting zipped infinite level")
lev = ZipSchematic(filename); lev = ZipSchematic(filename);
info( "Detected zipped Infdev level" ) info("Detected zipped Infdev level")
return lev return lev
if (MCInfdevOldLevel._isLevel(filename)): if (MCInfdevOldLevel._isLevel(filename)):
info( u"Detected Infdev level.dat" ) info(u"Detected Infdev level.dat")
if (loadInfinite): if (loadInfinite):
return MCInfdevOldLevel(filename=filename); return MCInfdevOldLevel(filename=filename);
else: else:
raise ValueError, "Asked to load {0} which is an infinite level, loadInfinite was False".format(os.path.basename(filename)); raise ValueError, "Asked to load {0} which is an infinite level, loadInfinite was False".format(os.path.basename(filename));
if os.path.isdir(filename): if os.path.isdir(filename):
raise ValueError, "Folder {0} was not identified as a Minecraft level.".format(os.path.basename(filename)); raise ValueError, "Folder {0} was not identified as a Minecraft level.".format(os.path.basename(filename));
f = file(filename, 'rb'); f = file(filename, 'rb');
rawdata = f.read() rawdata = f.read()
f.close() f.close()
if len(rawdata) < 4: if len(rawdata) < 4:
raise ValueError, "{0} is too small! ({1}) ".format(filename, len(rawdata)) raise ValueError, "{0} is too small! ({1}) ".format(filename, len(rawdata))
data = fromstring(rawdata, dtype='uint8') data = fromstring(rawdata, dtype='uint8')
if not data.any(): if not data.any():
raise ValueError, "{0} contains only zeroes. This file is damaged beyond repair." raise ValueError, "{0} contains only zeroes. This file is damaged beyond repair."
if MCJavaLevel._isDataLevel(data): if MCJavaLevel._isDataLevel(data):
info( u"Detected Java-style level" ) info(u"Detected Java-style level")
lev = MCJavaLevel(filename, data); lev = MCJavaLevel(filename, data);
lev.compressed = False; lev.compressed = False;
return lev; return lev;
@ -277,16 +277,16 @@ def fromFile(filename, loadInfinite=True):
unzippedData = None; unzippedData = None;
try: try:
unzippedData = gunzip(rawdata) unzippedData = gunzip(rawdata)
except Exception,e: except Exception, e:
info( u"Exception during Gzip operation, assuming {0} uncompressed: {1!r}".format(filename, e) ) info(u"Exception during Gzip operation, assuming {0} uncompressed: {1!r}".format(filename, e))
if unzippedData is None: if unzippedData is None:
compressed = False; compressed = False;
unzippedData = rawdata unzippedData = rawdata
data = fromstring(unzippedData, dtype='uint8') data = fromstring(unzippedData, dtype='uint8')
if MCJavaLevel._isDataLevel(data): if MCJavaLevel._isDataLevel(data):
info( u"Detected compressed Java-style level" ) info(u"Detected compressed Java-style level")
lev = MCJavaLevel(filename, data); lev = MCJavaLevel(filename, data);
lev.compressed = compressed; lev.compressed = compressed;
return lev; return lev;
@ -294,37 +294,37 @@ def fromFile(filename, loadInfinite=True):
try: try:
root_tag = nbt.load(buf=data); root_tag = nbt.load(buf=data);
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 ")
try: try:
lev = MCJavaLevel(filename, data); lev = MCJavaLevel(filename, data);
lev.compressed = compressed; lev.compressed = compressed;
return lev; return lev;
except Exception, e2: except Exception, e2:
raise LoadingError, ("Multiple errors encountered", e, 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")
return MCIndevLevel(root_tag, filename) return MCIndevLevel(root_tag, filename)
if(MCSchematic._isTagLevel(root_tag)): if(MCSchematic._isTagLevel(root_tag)):
info( u"Detected Schematic." ) info(u"Detected Schematic.")
return MCSchematic(root_tag=root_tag, filename=filename) return MCSchematic(root_tag=root_tag, filename=filename)
if (INVEditChest._isTagLevel(root_tag)): if (INVEditChest._isTagLevel(root_tag)):
info( u"Detected INVEdit inventory file" ) info(u"Detected INVEdit inventory file")
return INVEditChest(root_tag=root_tag, filename=filename); return INVEditChest(root_tag=root_tag, filename=filename);
#it must be a plain array of blocks. see if MCJavaLevel handles it. #it must be a plain array of blocks. see if MCJavaLevel handles it.
raise IOError, "Cannot detect file type." raise IOError, "Cannot detect file type."
def loadWorld(name): def loadWorld(name):
filename = os.path.join(saveFileDir, name) filename = os.path.join(saveFileDir, name)
return fromFile(filename) return fromFile(filename)
def loadWorldNumber(i): def loadWorldNumber(i):
#deprecated #deprecated
filename = u"{0}{1}{2}{3}{1}".format(saveFileDir, os.sep, u"World", i) filename = u"{0}{1}{2}{3}{1}".format(saveFileDir, os.sep, u"World", i)

View File

@ -60,8 +60,8 @@ def unpack_first(func):
return func(self, *args, **kw); return func(self, *args, **kw);
upk_first.__doc__ = func.__doc__ upk_first.__doc__ = func.__doc__
return upk_first return upk_first
class PlayerNotFound(Exception): pass class PlayerNotFound(Exception): pass
class ChunkNotPresent(Exception): pass class ChunkNotPresent(Exception): pass
class RegionMalformed(Exception): pass class RegionMalformed(Exception): pass
class ChunkMalformed(ChunkNotPresent): pass class ChunkMalformed(ChunkNotPresent): pass

248
nbt.py
View File

@ -33,17 +33,17 @@ class NBTFormatError(RuntimeError): pass
class TAG_Value(object): class TAG_Value(object):
"""Simple values. Subclasses override fmt to change the type and size. """Simple values. Subclasses override fmt to change the type and size.
Subclasses may set dataType instead of overriding setValue for automatic data type coercion""" Subclasses may set dataType instead of overriding setValue for automatic data type coercion"""
fmt = ">b"; fmt = ">b";
tag = -1; #error! tag = -1; #error!
_value = None _value = None
def getValue(self): def getValue(self):
return self._value return self._value
def setValue(self, newVal): def setValue(self, newVal):
self._value = self.dataType(newVal) self._value = self.dataType(newVal)
value = property(getValue, setValue, None, "Change the TAG's value. Data types are checked and coerced if needed.") value = property(getValue, setValue, None, "Change the TAG's value. Data types are checked and coerced if needed.")
_name = None _name = None
def getName(self): def getName(self):
return self._name return self._name
@ -52,29 +52,29 @@ class TAG_Value(object):
def delName(self): def delName(self):
self._name = "" self._name = ""
name = property(getName, setName, delName, "Change the TAG's name. Coerced to a string.") name = property(getName, setName, delName, "Change the TAG's name. Coerced to a string.")
def __init__(self, value=0, name=None, data=""): def __init__(self, value=0, name=None, data=""):
self.name = name self.name = name
if(data == ""): if(data == ""):
self.value = value self.value = value
else: else:
(self.value,) = struct.unpack_from(self.fmt, data); (self.value,) = struct.unpack_from(self.fmt, data);
def __repr__(self): def __repr__(self):
return "%s( \"%s\" ): %s" % (str(self.__class__), self.name, repr(self.value)) return "%s( \"%s\" ): %s" % (str(self.__class__), self.name, repr(self.value))
def __str__(self): def __str__(self):
return self.pretty_string() return self.pretty_string()
def pretty_string(self, indent=0): def pretty_string(self, indent=0):
if self.name: if self.name:
return " "*indent + "%s( \"%s\" ): %s" % (str(self.__class__.__name__), self.name, self.value) return " " * indent + "%s( \"%s\" ): %s" % (str(self.__class__.__name__), self.name, self.value)
else: else:
return " "*indent + "%s: %s" % (str(self.__class__.__name__), self.value) return " " * indent + "%s: %s" % (str(self.__class__.__name__), self.value)
def nbt_length(self): def nbt_length(self):
return struct.calcsize(self.fmt); return struct.calcsize(self.fmt);
def write_tag(self, buf): def write_tag(self, buf):
buf.write(struct.pack(TAGfmt, self.tag)) buf.write(struct.pack(TAGfmt, self.tag))
def write_name(self, buf): def write_name(self, buf):
@ -82,7 +82,7 @@ class TAG_Value(object):
TAG_String(self.name).write_value(buf) TAG_String(self.name).write_value(buf)
def write_value(self, buf): def write_value(self, buf):
buf.write(struct.pack(self.fmt, self.value)) buf.write(struct.pack(self.fmt, self.value))
def save(self, filename="", buf=None): def save(self, filename="", buf=None):
if(filename): if(filename):
self.saveGzipped(filename); self.saveGzipped(filename);
@ -100,7 +100,7 @@ class TAG_Value(object):
except Exception, e: except Exception, e:
#print "Atomic Save: No existing file to rename" #print "Atomic Save: No existing file to rename"
pass pass
with closing(gzip.GzipFile(fileobj=sio, mode="wb", compresslevel=compresslevel)) as outputGz: with closing(gzip.GzipFile(fileobj=sio, mode="wb", compresslevel=compresslevel)) as outputGz:
self.save(buf=outputGz); self.save(buf=outputGz);
outputGz.flush(); outputGz.flush();
@ -115,27 +115,27 @@ class TAG_Value(object):
except Exception, e: except Exception, e:
print e; print e;
return return
try: os.remove(filename + ".old"); try: os.remove(filename + ".old");
except Exception, e: except Exception, e:
#print "Atomic Save: No old file to remove" #print "Atomic Save: No old file to remove"
pass; pass;
class TAG_Byte(TAG_Value): class TAG_Byte(TAG_Value):
tag = 1; tag = 1;
fmt = ">b"; fmt = ">b";
dataType = int dataType = int
class TAG_Short(TAG_Value): class TAG_Short(TAG_Value):
tag = 2; tag = 2;
fmt = ">h"; fmt = ">h";
dataType = int dataType = int
class TAG_Int(TAG_Value): class TAG_Int(TAG_Value):
tag = 3; tag = 3;
fmt = ">i"; fmt = ">i";
dataType = int dataType = int
class TAG_Long(TAG_Value): class TAG_Long(TAG_Value):
tag = 4; tag = 4;
fmt = ">q"; fmt = ">q";
@ -146,7 +146,7 @@ class TAG_Float(TAG_Value):
fmt = ">f"; fmt = ">f";
dataType = float dataType = float
class TAG_Double(TAG_Value): class TAG_Double(TAG_Value):
tag = 6; tag = 6;
fmt = ">d"; fmt = ">d";
@ -162,22 +162,22 @@ class TAG_Byte_Array(TAG_Value):
def dataType(self, value): def dataType(self, value):
return array(value, uint8) return array(value, uint8)
def __repr__(self): def __repr__(self):
return "<%s: length %d> ( %s )" % (self.__class__, len(self.value), self.name) return "<%s: length %d> ( %s )" % (self.__class__, len(self.value), self.name)
def pretty_string(self, indent=0): def pretty_string(self, indent=0):
if self.name: if self.name:
return " "*indent + "%s( \"%s\" ): shape=%s dtype=%s %s" % ( return " " * indent + "%s( \"%s\" ): shape=%s dtype=%s %s" % (
str(self.__class__.__name__), str(self.__class__.__name__),
self.name, self.name,
str(self.value.shape), str(self.value.shape),
str(self.value.dtype), str(self.value.dtype),
self.value) self.value)
else: else:
return " "*indent + "%s: %s %s" % (str(self.__class__.__name__), str(self.value.shape), self.value) return " " * indent + "%s: %s %s" % (str(self.__class__.__name__), str(self.value.shape), self.value)
def __init__(self, value=zeros(0, uint8), name=None, data=""): def __init__(self, value=zeros(0, uint8), name=None, data=""):
self.name = name self.name = name
if(data == ""): if(data == ""):
@ -185,21 +185,21 @@ class TAG_Byte_Array(TAG_Value):
else: else:
(string_len,) = struct.unpack_from(">I", data); (string_len,) = struct.unpack_from(">I", data);
self.value = fromstring(data[4:string_len + 4], 'uint8'); self.value = fromstring(data[4:string_len + 4], 'uint8');
def nbt_length(self) : def nbt_length(self) :
return len(self.value) + 4; return len(self.value) + 4;
def write_value(self, buf): def write_value(self, buf):
#print self.value #print self.value
valuestr = self.value.tostring() valuestr = self.value.tostring()
buf.write(struct.pack(self.fmt % (len(valuestr),), len(valuestr), valuestr)) buf.write(struct.pack(self.fmt % (len(valuestr),), len(valuestr), valuestr))
class TAG_Int_Array(TAG_Byte_Array): class TAG_Int_Array(TAG_Byte_Array):
"""An array of ints""" """An array of ints"""
tag = 11; tag = 11;
def dataType(self, value): def dataType(self, value):
return array(value, '>u4') return array(value, '>u4')
def __init__(self, value=zeros(0, ">u4"), name=None, data=""): def __init__(self, value=zeros(0, ">u4"), name=None, data=""):
self.name = name self.name = name
if(data == ""): if(data == ""):
@ -207,22 +207,22 @@ class TAG_Int_Array(TAG_Byte_Array):
else: else:
(string_len,) = struct.unpack_from(">I", data); (string_len,) = struct.unpack_from(">I", data);
self.value = fromstring(data[4:string_len * 4 + 4], '>u4') self.value = fromstring(data[4:string_len * 4 + 4], '>u4')
def nbt_length(self) : def nbt_length(self) :
return len(self.value) * 4 + 4; return len(self.value) * 4 + 4;
def write_value(self, buf): def write_value(self, buf):
#print self.value #print self.value
valuestr = self.value.tostring() valuestr = self.value.tostring()
buf.write(struct.pack(self.fmt % (len(valuestr),), len(valuestr)/4, valuestr)) buf.write(struct.pack(self.fmt % (len(valuestr),), len(valuestr) / 4, valuestr))
class TAG_Short_Array(TAG_Int_Array): class TAG_Short_Array(TAG_Int_Array):
"""An array of ints""" """An array of ints"""
tag = 12; tag = 12;
def dataType(self, value): def dataType(self, value):
return array(value, '>u2') return array(value, '>u2')
def __init__(self, value=zeros(0, ">u2"), name=None, data=""): def __init__(self, value=zeros(0, ">u2"), name=None, data=""):
self.name = name self.name = name
if(data == ""): if(data == ""):
@ -230,25 +230,25 @@ class TAG_Short_Array(TAG_Int_Array):
else: else:
(string_len,) = struct.unpack_from(">I", data); (string_len,) = struct.unpack_from(">I", data);
self.value = fromstring(data[4:string_len * 2 + 4], '>u2') self.value = fromstring(data[4:string_len * 2 + 4], '>u2')
def nbt_length(self) : def nbt_length(self) :
return len(self.value) * 2 + 4; return len(self.value) * 2 + 4;
def write_value(self, buf): def write_value(self, buf):
#print self.value #print self.value
valuestr = self.value.tostring() valuestr = self.value.tostring()
buf.write(struct.pack(self.fmt % (len(valuestr),), len(valuestr)/2, valuestr)) buf.write(struct.pack(self.fmt % (len(valuestr),), len(valuestr) / 2, valuestr))
class TAG_String(TAG_Value): class TAG_String(TAG_Value):
"""String in UTF-8 """String in UTF-8
The data parameter should either be a 'unicode' or an ascii-encoded 'str' The data parameter should either be a 'unicode' or an ascii-encoded 'str'
""" """
tag = 8; tag = 8;
fmt = ">h%ds" fmt = ">h%ds"
dataType = unicode dataType = unicode
def __init__(self, value="", name=None, data=""): def __init__(self, value="", name=None, data=""):
self.name = name self.name = name
if(data == ""): if(data == ""):
@ -263,7 +263,7 @@ class TAG_String(TAG_Value):
def write_value(self, buf): def write_value(self, buf):
u8value = self.value.encode('utf-8') u8value = self.value.encode('utf-8')
buf.write(struct.pack(self.fmt % (len(u8value),), len(u8value), u8value)) buf.write(struct.pack(self.fmt % (len(u8value),), len(u8value), u8value))
@ -273,29 +273,29 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
operator []. This will automatically name the tags.""" operator []. This will automatically name the tags."""
tag = 10; tag = 10;
def dataType(self, val): def dataType(self, val):
for i in val: for i in val:
assert isinstance(i, TAG_Value) assert isinstance(i, TAG_Value)
assert i.name assert i.name
return list(val) return list(val)
def __repr__(self): def __repr__(self):
return "%s( %s ): %s" % (str(self.__class__.__name__), self.name, self.value) return "%s( %s ): %s" % (str(self.__class__.__name__), self.name, self.value)
def pretty_string(self, indent=0): def pretty_string(self, indent=0):
if self.name: if self.name:
pretty = " "*indent + "%s( \"%s\" ):\n" % (str(self.__class__.__name__), self.name) pretty = " " * indent + "%s( \"%s\" ):\n" % (str(self.__class__.__name__), self.name)
else: else:
pretty = " "*indent + "%s():\n" % (str(self.__class__.__name__)) pretty = " " * indent + "%s():\n" % (str(self.__class__.__name__))
indent += 4 indent += 4
for tag in self.value: for tag in self.value:
pretty += tag.pretty_string(indent) + "\n" pretty += tag.pretty_string(indent) + "\n"
return pretty return pretty
def __init__(self, value=[], name="", data=""): def __init__(self, value=[], name="", data=""):
self.name = name; self.name = name;
if value.__class__ == ''.__class__: if value.__class__ == ''.__class__:
self.name = value; self.name = value;
@ -306,7 +306,7 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
else: else:
data_cursor = 0; data_cursor = 0;
while data_cursor < len(data): while data_cursor < len(data):
tag_type = data[data_cursor]; tag_type = data[data_cursor];
data_cursor += 1; data_cursor += 1;
@ -314,21 +314,21 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
break; break;
assert_type(tag_type, data_cursor) assert_type(tag_type, data_cursor)
data_cursor, tag = load_named(data, data_cursor, tag_type) data_cursor, tag = load_named(data, data_cursor, tag_type)
self.value.append(tag); self.value.append(tag);
def nbt_length(self): def nbt_length(self):
return sum(x.nbt_length() + len(x.name) + 3 for x in self.value) + 1; return sum(x.nbt_length() + len(x.name) + 3 for x in self.value) + 1;
def write_value(self, buf): def write_value(self, buf):
for i in self.value: for i in self.value:
i.save(buf=buf) i.save(buf=buf)
buf.write("\x00") buf.write("\x00")
"collection functions" "collection functions"
def __getitem__(self, k): def __getitem__(self, k):
#hits=filter(lambda x:x.name==k, self.value); #hits=filter(lambda x:x.name==k, self.value);
@ -336,11 +336,11 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
for key in self.value: for key in self.value:
if key.name == k: return key if key.name == k: return key
raise KeyError("Key {0} not found".format(k)); raise KeyError("Key {0} not found".format(k));
def __iter__(self): return itertools.imap(lambda x:x.name, self.value); def __iter__(self): return itertools.imap(lambda x:x.name, self.value);
def __contains__(self, k):return k in map(lambda x:x.name, self.value); def __contains__(self, k):return k in map(lambda x:x.name, self.value);
def __len__(self): return self.value.__len__() def __len__(self): return self.value.__len__()
def __setitem__(self, k, v): def __setitem__(self, k, v):
if not (v.__class__ in tag_handlers.values()): raise TypeError("Invalid type %s for TAG_Compound" % (v.__class__)) if not (v.__class__ in tag_handlers.values()): raise TypeError("Invalid type %s for TAG_Compound" % (v.__class__))
@ -349,14 +349,14 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
for i in olditems: self.value.remove(i) for i in olditems: self.value.remove(i)
self.value.append(v); self.value.append(v);
v.name = k; v.name = k;
def __delitem__(self, k): self.value.__delitem__(self.value.index(self[k])); def __delitem__(self, k): self.value.__delitem__(self.value.index(self[k]));
def add(self, v): def add(self, v):
self[v.name] = v; self[v.name] = v;
class TAG_List(TAG_Value, collections.MutableSequence): class TAG_List(TAG_Value, collections.MutableSequence):
"""A homogenous list of unnamed data of a single TAG_* type. """A homogenous list of unnamed data of a single TAG_* type.
Once created, the type can only be changed by emptying the list Once created, the type can only be changed by emptying the list
and adding an element of the new type. If created with no arguments, and adding an element of the new type. If created with no arguments,
@ -372,53 +372,53 @@ class TAG_List(TAG_Value, collections.MutableSequence):
# FIXME: This is kinda weird; None as the empty tag name? # FIXME: This is kinda weird; None as the empty tag name?
assert all(isinstance(x, listType) and x.name in ("", "None") for x in val) assert all(isinstance(x, listType) and x.name in ("", "None") for x in val)
return list(val) return list(val)
def __repr__(self): def __repr__(self):
return "%s( %s ): %s" % (self.__class__.__name__, self.name, self.value) return "%s( %s ): %s" % (self.__class__.__name__, self.name, self.value)
def pretty_string(self, indent=0): def pretty_string(self, indent=0):
if self.name: if self.name:
pretty = " "*indent + "%s( \"%s\" ):\n" % (str(self.__class__.__name__), self.name) pretty = " " * indent + "%s( \"%s\" ):\n" % (str(self.__class__.__name__), self.name)
else: else:
pretty = " "*indent + "%s():\n" % (str(self.__class__.__name__), ) pretty = " " * indent + "%s():\n" % (str(self.__class__.__name__),)
indent += 4 indent += 4
for tag in self.value: for tag in self.value:
pretty += tag.pretty_string(indent) + "\n" pretty += tag.pretty_string(indent) + "\n"
return pretty return pretty
def __init__(self, value=[], name=None, data=None, list_type=TAG_Compound): def __init__(self, value=[], name=None, data=None, list_type=TAG_Compound):
#can be created from a list of tags in value, with an optional #can be created from a list of tags in value, with an optional
#name, or created from raw tag data, or created with list_type #name, or created from raw tag data, or created with list_type
#taken from a TAG class or instance #taken from a TAG class or instance
self.name = name self.name = name
self.value = []; self.value = [];
self.list_type = list_type.tag self.list_type = list_type.tag
if(data == None): if(data == None):
if(len(value)): if(len(value)):
self.list_type = value[0].tag; self.list_type = value[0].tag;
value = filter(lambda x:x.__class__ == value[0].__class__, value) value = filter(lambda x:x.__class__ == value[0].__class__, value)
self.value = value self.value = value
else: else:
data_cursor = 0; data_cursor = 0;
self.list_type = data[data_cursor]; self.list_type = data[data_cursor];
assert_type(self.list_type, data_cursor); assert_type(self.list_type, data_cursor);
data_cursor += 1; data_cursor += 1;
list_length = TAG_Int(data=data[data_cursor:]) list_length = TAG_Int(data=data[data_cursor:])
data_cursor += list_length.nbt_length() data_cursor += list_length.nbt_length()
list_length = list_length.value list_length = list_length.value
for i in range(list_length): for i in range(list_length):
tag = tag_handlers[self.list_type](data=data[data_cursor:]) tag = tag_handlers[self.list_type](data=data[data_cursor:])
self.append(tag); self.append(tag);
data_cursor += tag.nbt_length() data_cursor += tag.nbt_length()
@ -428,35 +428,35 @@ class TAG_List(TAG_Value, collections.MutableSequence):
def __contains__(self, k):return k in self.value; def __contains__(self, k):return k in self.value;
def __getitem__(self, i): return self.value[i]; def __getitem__(self, i): return self.value[i];
def __len__(self): return len(self.value) def __len__(self): return len(self.value)
def __setitem__(self, i, v): def __setitem__(self, i, v):
if v.__class__ != tag_handlers[self.list_type]: if v.__class__ != tag_handlers[self.list_type]:
raise TypeError("Invalid type %s for TAG_List(%s)" % (v.__class__, tag_handlers[self.list_type])) raise TypeError("Invalid type %s for TAG_List(%s)" % (v.__class__, tag_handlers[self.list_type]))
v.name = "" v.name = ""
self.value[i] = v; self.value[i] = v;
def __delitem__(self, i): def __delitem__(self, i):
del self.value[i] del self.value[i]
def insert(self, i, v): def insert(self, i, v):
if not v.tag in tag_handlers: raise TypeError("Not a tag type: %s" % (v,)) if not v.tag in tag_handlers: raise TypeError("Not a tag type: %s" % (v,))
if len(self) == 0: if len(self) == 0:
self.list_type = v.tag self.list_type = v.tag
else: else:
if v.__class__ != tag_handlers[self.list_type]: raise TypeError("Invalid type %s for TAG_List(%s)" % (v.__class__, tag_handlers[self.list_type])) if v.__class__ != tag_handlers[self.list_type]: raise TypeError("Invalid type %s for TAG_List(%s)" % (v.__class__, tag_handlers[self.list_type]))
v.name = "" v.name = ""
self.value.insert(i, v); self.value.insert(i, v);
def nbt_length(self): def nbt_length(self):
return 5 + sum(x.nbt_length() for x in self.value) return 5 + sum(x.nbt_length() for x in self.value)
def write_value(self, buf): def write_value(self, buf):
buf.write(struct.pack(TAGfmt, self.list_type)) buf.write(struct.pack(TAGfmt, self.list_type))
TAG_Int(len(self)).write_value(buf) TAG_Int(len(self)).write_value(buf)
for i in self.value: for i in self.value:
i.write_value(buf) i.write_value(buf)
tag_handlers = { tag_handlers = {
1 : TAG_Byte, 1 : TAG_Byte,
@ -476,11 +476,11 @@ tag_handlers = {
def assert_type(t, offset) : def assert_type(t, offset) :
if not t in tag_handlers: raise ValueError("Unexpected tag type %d at %d" % (t, offset)); if not t in tag_handlers: raise ValueError("Unexpected tag type %d at %d" % (t, offset));
import zlib import zlib
def gunzip(data): def gunzip(data):
#strip off the header and use negative WBITS to tell zlib there's no header #strip off the header and use negative WBITS to tell zlib there's no header
return zlib.decompress(data[10:], -zlib.MAX_WBITS) return zlib.decompress(data[10:], -zlib.MAX_WBITS)
def loadFile(filename): def loadFile(filename):
#sio = StringIO.StringIO(); #sio = StringIO.StringIO();
with file(filename, "rb") as f: with file(filename, "rb") as f:
@ -491,14 +491,14 @@ def loadFile(filename):
data = gunzip(inputdata) data = gunzip(inputdata)
except IOError: except IOError:
print "File %s not zipped" % filename print "File %s not zipped" % filename
return load(buf=fromstring(data, 'uint8')); return load(buf=fromstring(data, 'uint8'));
def load_named(data, data_cursor, tag_type): def load_named(data, data_cursor, tag_type):
tag_name = TAG_String(data=data[data_cursor:]) tag_name = TAG_String(data=data[data_cursor:])
data_cursor += tag_name.nbt_length() data_cursor += tag_name.nbt_length()
tag_name = tag_name.value tag_name = tag_name.value
tag = tag_handlers[tag_type](data=data[data_cursor:], name=tag_name) tag = tag_handlers[tag_type](data=data[data_cursor:], name=tag_name)
data_cursor += tag.nbt_length() data_cursor += tag.nbt_length()
return data_cursor, tag return data_cursor, tag
@ -507,7 +507,7 @@ 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
filename or an array of integers containing TAG_Compound data. """ filename or an array of integers containing TAG_Compound data. """
if filename and isinstance(filename, (str, unicode)): if filename and isinstance(filename, (str, unicode)):
return loadFile(filename) return loadFile(filename)
if isinstance(buf, str): buf = fromstring(buf, uint8) if isinstance(buf, str): buf = fromstring(buf, uint8)
@ -537,17 +537,17 @@ def loadtest():
"""Use the [] operator to look up subtags of a TAG_Compound.""" """Use the [] operator to look up subtags of a TAG_Compound."""
print level["Environment"]["SurroundingGroundHeight"].value; print level["Environment"]["SurroundingGroundHeight"].value;
"""Numeric, string, and bytearray types have a value """Numeric, string, and bytearray types have a value
that can be accessed and changed. """ that can be accessed and changed. """
print level["Map"]["Blocks"].value print level["Map"]["Blocks"].value
return level; return level;
def createtest(): def createtest():
"Create an indev level." "Create an indev level."
"The root of an NBT file is always a TAG_Compound." "The root of an NBT file is always a TAG_Compound."
level = TAG_Compound(name="MinecraftLevel") level = TAG_Compound(name="MinecraftLevel")
@ -558,52 +558,52 @@ def createtest():
level["Environment"] = TAG_Compound() level["Environment"] = TAG_Compound()
level["Environment"]["SkyBrightness"] = TAG_Byte(16) level["Environment"]["SkyBrightness"] = TAG_Byte(16)
level["Environment"]["SurroundingWaterHeight"] = TAG_Short(32) level["Environment"]["SurroundingWaterHeight"] = TAG_Short(32)
"You can also create and name a tag before adding it to the compound." "You can also create and name a tag before adding it to the compound."
spawn = TAG_List((TAG_Short(100), TAG_Short(45), TAG_Short(55))) spawn = TAG_List((TAG_Short(100), TAG_Short(45), TAG_Short(55)))
spawn.name = "Spawn" spawn.name = "Spawn"
mapTag = TAG_Compound() mapTag = TAG_Compound()
mapTag.add(spawn); mapTag.add(spawn);
mapTag.name = "Map" mapTag.name = "Map"
level.add(mapTag) level.add(mapTag)
"I think it looks more familiar with [] syntax." "I think it looks more familiar with [] syntax."
l, w, h = 128, 128, 128 l, w, h = 128, 128, 128
mapTag["Height"] = TAG_Short(h) # y dimension mapTag["Height"] = TAG_Short(h) # y dimension
mapTag["Length"] = TAG_Short(l) # z dimension mapTag["Length"] = TAG_Short(l) # z dimension
mapTag["Width"] = TAG_Short(w) # x dimension mapTag["Width"] = TAG_Short(w) # x dimension
"Byte arrays are stored as numpy.uint8 arrays. " "Byte arrays are stored as numpy.uint8 arrays. "
mapTag["Blocks"] = TAG_Byte_Array() mapTag["Blocks"] = TAG_Byte_Array()
mapTag["Blocks"].value = zeros(l * w * h, dtype=uint8) #create lots of air! mapTag["Blocks"].value = zeros(l * w * h, dtype=uint8) #create lots of air!
"The blocks array is indexed (y,z,x) for indev levels, so reshape the blocks" "The blocks array is indexed (y,z,x) for indev levels, so reshape the blocks"
mapTag["Blocks"].value.shape = (h, l, w); mapTag["Blocks"].value.shape = (h, l, w);
"Replace the bottom layer of the indev level with wood" "Replace the bottom layer of the indev level with wood"
mapTag["Blocks"].value[0, :, :] = 5; mapTag["Blocks"].value[0, :, :] = 5;
"This is a great way to learn the power of numpy array slicing and indexing." "This is a great way to learn the power of numpy array slicing and indexing."
return level; return level;
def modifytest(): def modifytest():
level = createtest(); level = createtest();
"Most of the value types work as expected. Here, we replace the entire tag with a TAG_String" "Most of the value types work as expected. Here, we replace the entire tag with a TAG_String"
level["About"]["Author"] = TAG_String("YARRR~!"); level["About"]["Author"] = TAG_String("YARRR~!");
"Because the tag type usually doesn't change, " "Because the tag type usually doesn't change, "
"we can replace the string tag's value instead of replacing the entire tag." "we can replace the string tag's value instead of replacing the entire tag."
level["About"]["Author"].value = "Stew Pickles" level["About"]["Author"].value = "Stew Pickles"
"Remove members of a TAG_Compound using del, similar to a python dict." "Remove members of a TAG_Compound using del, similar to a python dict."
del(level["About"]); del(level["About"]);
"Replace all of the wood blocks with gold using a boolean index array" "Replace all of the wood blocks with gold using a boolean index array"
blocks = level["Map"]["Blocks"].value blocks = level["Map"]["Blocks"].value
blocks[blocks == 5] = 41; blocks[blocks == 5] = 41;
@ -613,10 +613,10 @@ def savetest():
level = createtest() level = createtest()
level["Environment"]["SurroundingWaterHeight"].value += 6; level["Environment"]["SurroundingWaterHeight"].value += 6;
"Save the entire TAG structure to a different file." "Save the entire TAG structure to a different file."
level.save("atlantis.mclevel") level.save("atlantis.mclevel")
level = createtest(); level = createtest();
level.save("synthetic.mclevel"); level.save("synthetic.mclevel");
@ -626,7 +626,7 @@ def abusetest():
named list elements are not allowed by the NBT spec, named list elements are not allowed by the NBT spec,
so we must discard any names when writing a list. so we must discard any names when writing a list.
""" """
level = createtest(); level = createtest();
level["Map"]["Spawn"][0].name = "Torg Potter" level["Map"]["Spawn"][0].name = "Torg Potter"
sio = StringIO.StringIO() sio = StringIO.StringIO()
@ -647,9 +647,9 @@ def abusetest():
pass pass
else: else:
assert False assert False
def runtests(): def runtests():
loadtest(); loadtest();
createtest(); createtest();
modifytest(); modifytest();
@ -661,5 +661,5 @@ if(__name__ == "__main__") :
runtests() runtests()
__all__ = [a.__name__ for a in tag_handlers.itervalues()] + ["loadFile", "gunzip"] __all__ = [a.__name__ for a in tag_handlers.itervalues()] + ["loadFile", "gunzip"]

View File

@ -19,7 +19,7 @@ def generate_file_list(directory):
yield os.path.join(dirpath, filename) yield os.path.join(dirpath, filename)
def sha1_file(name, checksum=None): def sha1_file(name, checksum=None):
CHUNKSIZE=1024 CHUNKSIZE = 1024
if checksum is None: if checksum is None:
checksum = hashlib.sha1() checksum = hashlib.sha1()
if fnmatch.fnmatch(name, "*.dat"): if fnmatch.fnmatch(name, "*.dat"):
@ -71,17 +71,17 @@ def untared_content(src):
f.extractall(dest) f.extractall(dest)
yield dest yield dest
def launch_subprocess(directory, arguments, env = {}): def launch_subprocess(directory, arguments, env={}):
#my python breaks with an empty environ, i think it wants PATH #my python breaks with an empty environ, i think it wants PATH
#if sys.platform == "win32": #if sys.platform == "win32":
newenv = {} newenv = {}
newenv.update(os.environ) newenv.update(os.environ)
newenv.update(env); newenv.update(env);
proc = subprocess.Popen((["python.exe"] if sys.platform == "win32" else []) + [ proc = subprocess.Popen((["python.exe"] if sys.platform == "win32" else []) + [
"./mce.py", "./mce.py",
directory] + arguments, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=newenv) directory] + arguments, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=newenv)
return proc return proc
class RegressionError(Exception): pass class RegressionError(Exception): pass
@ -129,7 +129,7 @@ def do_test_match_output(test_data, result_check, arguments=[]):
proc.stdin.close() proc.stdin.close()
output = proc.stdout.read() output = proc.stdout.read()
proc.wait() proc.wait()
if proc.returncode: if proc.returncode:
raise RegressionError("Program execution failed!") raise RegressionError("Program execution failed!")
@ -146,13 +146,13 @@ def do_test_match_output(test_data, result_check, arguments=[]):
alpha_tests = [ alpha_tests = [
(do_test, 'baseline', '9e7460d39c8e0456789cf89fee45276db2719aaa', []), (do_test, 'baseline', '9e7460d39c8e0456789cf89fee45276db2719aaa', []),
(do_test, 'degrief', '403e6c6147cf1f8d73377b18bbf5e4973606a311', ['degrief']), (do_test, 'degrief', '403e6c6147cf1f8d73377b18bbf5e4973606a311', ['degrief']),
(do_test_match_output, 'analyze', '89ae362dec7f6c0fd743d6ed4e3957459cb3c34d', ['analyze']), (do_test_match_output, 'analyze', '89ae362dec7f6c0fd743d6ed4e3957459cb3c34d', ['analyze']),
(do_test, 'relight', 'e0cf60c62adfdb313f198af5314c31f89d158c12', ['relight']), (do_test, 'relight', 'e0cf60c62adfdb313f198af5314c31f89d158c12', ['relight']),
(do_test, 'replace', 'd73767293e903b6d1c49c1838eb1849b69d83ad8', ['replace', 'Water (active)', 'with', 'Lava (active)']), (do_test, 'replace', 'd73767293e903b6d1c49c1838eb1849b69d83ad8', ['replace', 'Water (active)', 'with', 'Lava (active)']),
(do_test, 'fill', 'f4f57c3d902b6894031d416cb9279232e7e24bd7', ['fill', 'Water (active)']), (do_test, 'fill', 'f4f57c3d902b6894031d416cb9279232e7e24bd7', ['fill', 'Water (active)']),
(do_test, 'heightmap', '9e7460d39c8e0456789cf89fee45276db2719aaa', ['heightmap', 'regression_test/mars.png']), (do_test, 'heightmap', '9e7460d39c8e0456789cf89fee45276db2719aaa', ['heightmap', 'regression_test/mars.png']),
] ]
import optparse import optparse
@ -172,26 +172,26 @@ def main(argv):
test_data = os.path.join(directory, "alpha") test_data = os.path.join(directory, "alpha")
passes = [] passes = []
fails = [] fails = []
for func, name, sha, args in alpha_tests: for func, name, sha, args in alpha_tests:
print "Starting regression {0} ({1})".format( name, args ) print "Starting regression {0} ({1})".format(name, args)
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:
print >>sys.stderr, "Starting to profile to %s.profile" % name print >> sys.stderr, "Starting to profile to %s.profile" % name
os.environ['MCE_PROFILE'] = '%s.profile' % name os.environ['MCE_PROFILE'] = '%s.profile' % name
try: try:
func(test_data, sha, args) func(test_data, sha, args)
except RegressionError, e: except RegressionError, e:
fails.append( "Regression {0} failed: {1}".format(name, e) ) fails.append("Regression {0} failed: {1}".format(name, e))
print fails[-1] print fails[-1]
else: else:
passes.append( "Regression {0!r} complete.".format(name) ) passes.append("Regression {0!r} complete.".format(name))
print passes[-1] print passes[-1]
print "{0} tests passed.".format(len(passes)) print "{0} tests passed.".format(len(passes))
for line in fails: print line; for line in fails: print line;
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv)) sys.exit(main(sys.argv))

View File

@ -468,6 +468,7 @@ def extractSchematicFrom(sourceLevel, box):
return tempSchematic return tempSchematic
import tempfile
def extractZipSchematicFrom(sourceLevel, box, zipfilename): def extractZipSchematicFrom(sourceLevel, box, zipfilename):
#converts classic blocks to alpha #converts classic blocks to alpha
#probably should only apply to alpha levels #probably should only apply to alpha levels