put everything through pydev's code auto-formatter
This commit is contained in:
parent
6b9e82c2e4
commit
225f813d28
@ -35,7 +35,7 @@ class Torch:
|
||||
alphaMaterials.RedstoneTorchOn.ID,
|
||||
alphaMaterials.RedstoneTorchOff.ID,
|
||||
]
|
||||
|
||||
|
||||
South = 1
|
||||
North = 2
|
||||
West = 3
|
||||
@ -45,7 +45,7 @@ genericFlipRotation(Torch)
|
||||
|
||||
class Ladder:
|
||||
blocktypes = [alphaMaterials.Ladder.ID]
|
||||
|
||||
|
||||
East = 2
|
||||
West = 3
|
||||
North = 4
|
||||
@ -57,7 +57,7 @@ class Stair:
|
||||
alphaMaterials.WoodenStairs.ID,
|
||||
alphaMaterials.StoneStairs.ID,
|
||||
]
|
||||
|
||||
|
||||
South = 0
|
||||
North = 1
|
||||
West = 2
|
||||
@ -66,13 +66,13 @@ genericFlipRotation(Stair)
|
||||
|
||||
class WallSign:
|
||||
blocktypes = [alphaMaterials.WallSign.ID]
|
||||
|
||||
|
||||
East = 2
|
||||
West = 3
|
||||
North = 4
|
||||
South = 5
|
||||
genericFlipRotation(WallSign)
|
||||
|
||||
|
||||
class Furnace:
|
||||
blocktypes = [
|
||||
alphaMaterials.Furnace.ID,
|
||||
@ -87,15 +87,15 @@ genericFlipRotation(Furnace)
|
||||
class Dispenser(Furnace):
|
||||
blocktypes = [
|
||||
alphaMaterials.Dispenser.ID,
|
||||
]
|
||||
]
|
||||
genericFlipRotation(Dispenser)
|
||||
|
||||
|
||||
class Pumpkin:
|
||||
blocktypes = [
|
||||
alphaMaterials.Pumpkin.ID,
|
||||
alphaMaterials.JackOLantern.ID,
|
||||
]
|
||||
|
||||
|
||||
East = 0
|
||||
South = 1
|
||||
West = 2
|
||||
@ -104,14 +104,14 @@ genericFlipRotation(Pumpkin)
|
||||
|
||||
class Rail:
|
||||
blocktypes = [alphaMaterials.Rail.ID]
|
||||
|
||||
|
||||
EastWest = 0
|
||||
NorthSouth = 1
|
||||
South = 2
|
||||
North = 3
|
||||
East = 4
|
||||
West = 5
|
||||
|
||||
|
||||
Northeast = 6
|
||||
Southeast = 7
|
||||
Southwest = 8
|
||||
@ -143,7 +143,7 @@ def applyBit8(array):
|
||||
def applyBit4(array):
|
||||
array[4:8] = array[0:4] | 0x4
|
||||
array[12:16] = array[8:12] | 0x4
|
||||
|
||||
|
||||
applyThrownBit = applyBit8
|
||||
|
||||
class PoweredDetectorRail(Rail):
|
||||
@ -161,7 +161,7 @@ applyThrownBit(PoweredDetectorRail.flipEastWest)
|
||||
applyThrownBit(PoweredDetectorRail.flipNorthSouth)
|
||||
rotationClasses.append(PoweredDetectorRail)
|
||||
|
||||
|
||||
|
||||
class Lever:
|
||||
blocktypes = [alphaMaterials.Lever.ID]
|
||||
ThrownBit = 0x8
|
||||
@ -199,11 +199,11 @@ rotationClasses.append(Button)
|
||||
class SignPost:
|
||||
blocktypes = [alphaMaterials.Sign.ID]
|
||||
#west is 0, increasing clockwise
|
||||
|
||||
|
||||
rotateLeft = arange(16, dtype='uint8')
|
||||
rotateLeft -= 4
|
||||
rotateLeft &= 0xf
|
||||
|
||||
|
||||
flipEastWest = arange(16, dtype='uint8')
|
||||
flipNorthSouth = arange(16, dtype='uint8')
|
||||
pass
|
||||
@ -217,14 +217,14 @@ class Door:
|
||||
]
|
||||
TopHalfBit = 0x8
|
||||
SwungCCWBit = 0x4
|
||||
|
||||
|
||||
Northeast = 0
|
||||
Southeast = 1
|
||||
Southwest = 2
|
||||
Northwest = 3
|
||||
|
||||
|
||||
rotateLeft = arange(16, dtype='uint8')
|
||||
|
||||
|
||||
Door.rotateLeft[Door.Northeast] = Door.Northwest
|
||||
Door.rotateLeft[Door.Southeast] = Door.Northeast
|
||||
Door.rotateLeft[Door.Southwest] = Door.Southeast
|
||||
@ -260,14 +260,14 @@ class RedstoneRepeater:
|
||||
blocktypes = [
|
||||
alphaMaterials.RedstoneRepeaterOff.ID,
|
||||
alphaMaterials.RedstoneRepeaterOn.ID,
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
East = 0
|
||||
South = 1
|
||||
West = 2
|
||||
North = 3
|
||||
|
||||
|
||||
genericFlipRotation(RedstoneRepeater)
|
||||
|
||||
#high bits of the repeater indicate repeater delay, and should be preserved
|
||||
@ -285,7 +285,7 @@ applyOpenedBit = applyBit4
|
||||
|
||||
class Trapdoor:
|
||||
blocktypes = [alphaMaterials.Trapdoor.ID]
|
||||
|
||||
|
||||
West = 0
|
||||
East = 1
|
||||
South = 2
|
||||
@ -299,7 +299,7 @@ applyOpenedBit(Trapdoor.flipNorthSouth)
|
||||
applyPistonBit = applyBit8
|
||||
class PistonBody:
|
||||
blocktypes = [alphaMaterials.StickyPiston.ID, alphaMaterials.Piston.ID]
|
||||
|
||||
|
||||
East = 2
|
||||
West = 3
|
||||
North = 4
|
||||
@ -308,36 +308,36 @@ genericFlipRotation(PistonBody)
|
||||
applyPistonBit(PistonBody.rotateLeft)
|
||||
applyPistonBit(PistonBody.flipEastWest)
|
||||
applyPistonBit(PistonBody.flipNorthSouth)
|
||||
|
||||
|
||||
class PistonHead(PistonBody):
|
||||
blocktypes = [alphaMaterials.PistonHead.ID]
|
||||
rotationClasses.append(PistonHead)
|
||||
|
||||
rotationClasses.append(PistonHead)
|
||||
|
||||
def masterRotationTable(rotationFunc):
|
||||
# compute a 256x16 table mapping each possible blocktype/data combination to
|
||||
# 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')
|
||||
for cls in rotationClasses:
|
||||
for blocktype in cls.blocktypes:
|
||||
table[blocktype] = rotationFunc(cls)
|
||||
|
||||
return table
|
||||
|
||||
|
||||
return table
|
||||
|
||||
class BlockRotation:
|
||||
rotateLeft = masterRotationTable(lambda cls:cls.rotateLeft);
|
||||
flipEastWest = masterRotationTable(lambda cls:cls.flipEastWest);
|
||||
flipNorthSouth = masterRotationTable(lambda cls:cls.flipNorthSouth);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def FlipNorthSouth(blocks, data):
|
||||
data[:] = BlockRotation.flipNorthSouth[blocks, data]
|
||||
|
||||
|
||||
def FlipEastWest(blocks, data):
|
||||
data[:] = BlockRotation.flipEastWest[blocks, data]
|
||||
|
||||
|
||||
|
||||
def RotateLeft(blocks, data):
|
||||
data[:] = BlockRotation.rotateLeft[blocks, data]
|
||||
|
||||
|
18
entity.py
18
entity.py
@ -11,7 +11,7 @@ class TileEntity(object):
|
||||
@classmethod
|
||||
def pos(cls, tag):
|
||||
return [tag[a].value for a in 'xyz']
|
||||
|
||||
|
||||
@classmethod
|
||||
def setpos(cls, tag, pos):
|
||||
for a, p in zip('xyz', pos):
|
||||
@ -23,21 +23,21 @@ class Entity(object):
|
||||
if "Pos" not in tag:
|
||||
print tag
|
||||
return [a.value for a in tag["Pos"]]
|
||||
|
||||
|
||||
@classmethod
|
||||
def setpos(cls, tag, pos):
|
||||
tag["Pos"] = TAG_List([TAG_Int(p) for p in pos])
|
||||
|
||||
|
||||
@classmethod
|
||||
def copyWithOffset(cls, entity, copyOffset):
|
||||
def copyWithOffset(cls, entity, copyOffset):
|
||||
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)
|
||||
|
||||
|
||||
if eTag["id"].value == "Painting":
|
||||
eTag["TileX"].value += copyOffset[0]
|
||||
eTag["TileY"].value += copyOffset[1]
|
||||
eTag["TileZ"].value += copyOffset[2]
|
||||
|
||||
return eTag
|
||||
|
||||
return eTag
|
||||
|
160
indev.py
160
indev.py
@ -86,115 +86,115 @@ __all__ = ["MCIndevLevel"]
|
||||
|
||||
|
||||
class MCIndevLevel(MCLevel):
|
||||
|
||||
|
||||
""" IMPORTANT: self.Blocks and self.Data are indexed with [x,z,y] via axis
|
||||
swapping to be consistent with infinite levels."""
|
||||
hasEntities = True
|
||||
|
||||
def setPlayerSpawnPosition(self, pos, player = None):
|
||||
|
||||
def setPlayerSpawnPosition(self, pos, player=None):
|
||||
assert len(pos) == 3
|
||||
self.Spawn = array(pos);
|
||||
|
||||
def playerSpawnPosition(self, player = None):
|
||||
def playerSpawnPosition(self, player=None):
|
||||
return self.Spawn;
|
||||
|
||||
def setPlayerPosition(self, pos, player = "Ignored"):
|
||||
|
||||
def setPlayerPosition(self, pos, player="Ignored"):
|
||||
for x in self.root_tag["Entities"]:
|
||||
if x["id"].value == "LocalPlayer":
|
||||
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"]:
|
||||
if x["id"].value == "LocalPlayer":
|
||||
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"]:
|
||||
if x["id"].value == "LocalPlayer":
|
||||
x["Rotation"] = TAG_List([TAG_Float(p) for p in yp])
|
||||
|
||||
def playerOrientation(self, player = "Ignored"):
|
||||
def playerOrientation(self, player="Ignored"):
|
||||
""" returns (yaw, pitch) """
|
||||
for x in self.root_tag["Entities"]:
|
||||
if x["id"].value == "LocalPlayer":
|
||||
return array(map(lambda x:x.value, x["Rotation"]));
|
||||
|
||||
def setBlockDataAt(self, x,y,z, newdata):
|
||||
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;
|
||||
self.Data[x,z,y] = (newdata & 0xf);
|
||||
|
||||
def setBlockDataAt(self, x, y, z, newdata):
|
||||
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;
|
||||
self.Data[x, z, y] = (newdata & 0xf);
|
||||
|
||||
def blockDataAt(self, x, y, z):
|
||||
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;
|
||||
return self.Data[x,z,y];
|
||||
|
||||
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;
|
||||
return self.Data[x, z, y];
|
||||
|
||||
def blockLightAt(self, x, y, z):
|
||||
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;
|
||||
return self.BlockLight[x,z,y];
|
||||
|
||||
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;
|
||||
return self.BlockLight[x, z, y];
|
||||
|
||||
def __repr__(self):
|
||||
return u"MCIndevLevel({0}): {1}W {2}L {3}H".format(self.filename, self.Width, self.Length, self.Height)
|
||||
|
||||
|
||||
@classmethod
|
||||
def _isTagLevel(cls, root_tag):
|
||||
return "MinecraftLevel" == root_tag.name
|
||||
|
||||
def __init__(self, root_tag = None, filename = ""):
|
||||
|
||||
def __init__(self, root_tag=None, filename=""):
|
||||
self.Width = 0
|
||||
self.Height = 0
|
||||
self.Length = 0
|
||||
self.Blocks = array([], uint8)
|
||||
self.Data = array([], uint8)
|
||||
self.Spawn = (0,0,0)
|
||||
self.Spawn = (0, 0, 0)
|
||||
self.filename = filename;
|
||||
|
||||
|
||||
|
||||
|
||||
if root_tag:
|
||||
|
||||
|
||||
self.root_tag = root_tag;
|
||||
mapTag = root_tag[Map];
|
||||
self.Width = mapTag[Width].value
|
||||
self.Length = mapTag[Length].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.Data >>= 4
|
||||
|
||||
|
||||
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();
|
||||
self.Entities = root_tag[Entities]
|
||||
|
||||
if not TileEntities in root_tag:
|
||||
if not TileEntities in root_tag:
|
||||
root_tag[TileEntities] = TAG_List();
|
||||
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['Pos'] = TAG_List([TAG_Float(0.), TAG_Float(64.), TAG_Float(0.)])
|
||||
p['Rotation'] = TAG_List([TAG_Float(0.), TAG_Float(45.)])
|
||||
|
||||
|
||||
root_tag[Entities].append(p)
|
||||
#self.saveInPlace();
|
||||
|
||||
|
||||
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"
|
||||
# self.SurroundingGroundHeight = root_tag[Environment][SurroundingGroundHeight].value
|
||||
# self.SurroundingGroundType = root_tag[Environment][SurroundingGroundType].value
|
||||
@ -212,65 +212,65 @@ class MCIndevLevel(MCLevel):
|
||||
# self.Author = self.root_tag[About][Author].value
|
||||
# self.CreatedOn = self.root_tag[About][CreatedOn].value
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def 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,
|
||||
6, 7,
|
||||
|
||||
6, 7,
|
||||
|
||||
8, 9, 10, 11, 12, 13, 14, 15]);
|
||||
|
||||
|
||||
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]]
|
||||
|
||||
|
||||
def saveToFile(self, filename = None):
|
||||
|
||||
|
||||
def saveToFile(self, filename=None):
|
||||
if filename == None: filename = self.filename;
|
||||
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!
|
||||
|
||||
|
||||
self.Data <<= 4;
|
||||
self.Data |= (self.BlockLight & 0xf)
|
||||
|
||||
|
||||
self.Blocks = swapaxes(self.Blocks, 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[Height] = TAG_Short(self.Height);
|
||||
mapTag[Length] = TAG_Short(self.Length);
|
||||
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.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]
|
||||
#output_file = gzip.open(self.filename, "wb", compresslevel=1)
|
||||
try:
|
||||
os.rename(filename, filename + ".old");
|
||||
except Exception,e:
|
||||
except Exception, e:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
self.root_tag.saveGzipped(filename);
|
||||
except:
|
||||
os.rename(filename + ".old", filename);
|
||||
|
||||
|
||||
try: os.remove(filename + ".old");
|
||||
except Exception,e:
|
||||
except Exception, e:
|
||||
pass
|
||||
|
||||
|
||||
self.BlockLight = self.Data & 0xf
|
||||
|
||||
|
||||
self.Data >>= 4
|
||||
|
||||
|
||||
|
34
items.py
34
items.py
@ -257,20 +257,20 @@ items_txt = """
|
||||
|
||||
"""
|
||||
class ItemType (object):
|
||||
def __init__(self, id, name, imagefile = None, imagecoords = None, maxdamage = 0, damagevalue = 0, stacksize = 64):
|
||||
self.id=id
|
||||
self.name=name
|
||||
self.imagefile=imagefile
|
||||
self.imagecoords=imagecoords
|
||||
self.maxdamage=maxdamage
|
||||
def __init__(self, id, name, imagefile=None, imagecoords=None, maxdamage=0, damagevalue=0, stacksize=64):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.imagefile = imagefile
|
||||
self.imagecoords = imagecoords
|
||||
self.maxdamage = maxdamage
|
||||
def __repr__(self):
|
||||
return "ItemType({0}, '{1}')".format(self.id, self.name)
|
||||
def __str__(self):
|
||||
return "ItemType {0}: {1}".format(self.id, self.name)
|
||||
|
||||
|
||||
class Items (object):
|
||||
items_txt = items_txt
|
||||
def __init__(self, filename = None):
|
||||
def __init__(self, filename=None):
|
||||
if filename is None:
|
||||
items_txt = self.items_txt
|
||||
else:
|
||||
@ -281,9 +281,9 @@ class Items (object):
|
||||
print "Error reading items.txt: ", e;
|
||||
print "Using internal data."
|
||||
items_txt = self.items_txt
|
||||
|
||||
|
||||
self.itemtypes = {};
|
||||
|
||||
|
||||
for line in items_txt.split("\n"):
|
||||
try:
|
||||
line = line.strip()
|
||||
@ -293,7 +293,7 @@ class Items (object):
|
||||
stacksize = 64
|
||||
damagevalue = None
|
||||
maxdamage = 0
|
||||
|
||||
|
||||
fields = line.split();
|
||||
if len(fields) >= 4:
|
||||
maxdamage = None;
|
||||
@ -309,25 +309,25 @@ class Items (object):
|
||||
id = int(id);
|
||||
name = name.replace("_", " ");
|
||||
imagecoords = imagecoords.split(",");
|
||||
|
||||
|
||||
self.itemtypes[(id, damagevalue)] = ItemType(id, name, imagefile, imagecoords, maxdamage, damagevalue, stacksize)
|
||||
except Exception, e:
|
||||
print "Error reading line:", e
|
||||
print "Line: ", line
|
||||
print
|
||||
|
||||
|
||||
self.names = dict((item.name, item.id) for item in self.itemtypes.itervalues())
|
||||
|
||||
|
||||
def findItem(self, id=0, damage=None):
|
||||
item = self.itemtypes.get((id, damage))
|
||||
if item: return item
|
||||
|
||||
|
||||
item = self.itemtypes.get((id, None))
|
||||
if item: return item
|
||||
|
||||
|
||||
item = self.itemtypes.get((id, 0))
|
||||
if item: return item
|
||||
|
||||
|
||||
raise ItemNotFound, "Item {0}:{1} not found".format(id, damage)
|
||||
|
||||
class ItemNotFound(KeyError): pass
|
||||
|
576
materials.py
576
materials.py
File diff suppressed because it is too large
Load Diff
86
mclevel.py
86
mclevel.py
@ -192,12 +192,12 @@ import sys
|
||||
|
||||
# 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 sys.platform == "win32":
|
||||
#not sure why win32com is needed if the %APPDATA% var is available
|
||||
try:
|
||||
try:
|
||||
import win32com.client
|
||||
|
||||
|
||||
objShell = win32com.client.Dispatch("WScript.Shell")
|
||||
minecraftDir = os.path.join(objShell.SpecialFolders("AppData"), u".minecraft")
|
||||
except Exception, e:
|
||||
@ -211,9 +211,9 @@ elif sys.platform == "darwin":
|
||||
else:
|
||||
minecraftDir = os.path.expanduser("~/.minecraft")
|
||||
minecraftDir.decode(sys.getfilesystemencoding());
|
||||
|
||||
|
||||
saveFileDir = os.path.join(minecraftDir, u"saves")
|
||||
|
||||
|
||||
#if sys.platform == "win32":
|
||||
# from win32com.shell import shell, shellcon
|
||||
# saveFileDir = shell.SHGetPathFromIDListEx (
|
||||
@ -221,53 +221,53 @@ saveFileDir = os.path.join(minecraftDir, u"saves")
|
||||
# )
|
||||
#
|
||||
|
||||
|
||||
|
||||
def fromFile(filename, loadInfinite=True):
|
||||
''' The preferred method for loading Minecraft levels of any type.
|
||||
pass False to loadInfinite if you'd rather not load infdev levels.
|
||||
'''
|
||||
info( u"Identifying " + filename )
|
||||
|
||||
info(u"Identifying " + filename)
|
||||
|
||||
class LoadingError(RuntimeError): pass
|
||||
|
||||
|
||||
|
||||
|
||||
if not filename:
|
||||
raise IOError, "File not found: "+filename
|
||||
raise IOError, "File not found: " + filename
|
||||
if not os.path.exists(filename):
|
||||
raise IOError, "File not found: "+filename
|
||||
|
||||
raise IOError, "File not found: " + filename
|
||||
|
||||
if (ZipSchematic._isLevel(filename)):
|
||||
info( "Zipfile found, attempting zipped infinite level" )
|
||||
info("Zipfile found, attempting zipped infinite level")
|
||||
lev = ZipSchematic(filename);
|
||||
info( "Detected zipped Infdev level" )
|
||||
info("Detected zipped Infdev level")
|
||||
return lev
|
||||
|
||||
|
||||
if (MCInfdevOldLevel._isLevel(filename)):
|
||||
info( u"Detected Infdev level.dat" )
|
||||
info(u"Detected Infdev level.dat")
|
||||
if (loadInfinite):
|
||||
return MCInfdevOldLevel(filename=filename);
|
||||
else:
|
||||
raise ValueError, "Asked to load {0} which is an infinite level, loadInfinite was False".format(os.path.basename(filename));
|
||||
|
||||
|
||||
if os.path.isdir(filename):
|
||||
raise ValueError, "Folder {0} was not identified as a Minecraft level.".format(os.path.basename(filename));
|
||||
|
||||
|
||||
f = file(filename, 'rb');
|
||||
rawdata = f.read()
|
||||
f.close()
|
||||
if len(rawdata) < 4:
|
||||
raise ValueError, "{0} is too small! ({1}) ".format(filename, len(rawdata))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
data = fromstring(rawdata, dtype='uint8')
|
||||
if not data.any():
|
||||
raise ValueError, "{0} contains only zeroes. This file is damaged beyond repair."
|
||||
|
||||
|
||||
|
||||
|
||||
if MCJavaLevel._isDataLevel(data):
|
||||
info( u"Detected Java-style level" )
|
||||
info(u"Detected Java-style level")
|
||||
lev = MCJavaLevel(filename, data);
|
||||
lev.compressed = False;
|
||||
return lev;
|
||||
@ -277,16 +277,16 @@ def fromFile(filename, loadInfinite=True):
|
||||
unzippedData = None;
|
||||
try:
|
||||
unzippedData = gunzip(rawdata)
|
||||
except Exception,e:
|
||||
info( u"Exception during Gzip operation, assuming {0} uncompressed: {1!r}".format(filename, e) )
|
||||
except Exception, e:
|
||||
info(u"Exception during Gzip operation, assuming {0} uncompressed: {1!r}".format(filename, e))
|
||||
if unzippedData is None:
|
||||
compressed = False;
|
||||
unzippedData = rawdata
|
||||
|
||||
|
||||
data = fromstring(unzippedData, dtype='uint8')
|
||||
|
||||
|
||||
if MCJavaLevel._isDataLevel(data):
|
||||
info( u"Detected compressed Java-style level" )
|
||||
info(u"Detected compressed Java-style level")
|
||||
lev = MCJavaLevel(filename, data);
|
||||
lev.compressed = compressed;
|
||||
return lev;
|
||||
@ -294,37 +294,37 @@ def fromFile(filename, loadInfinite=True):
|
||||
try:
|
||||
root_tag = nbt.load(buf=data);
|
||||
except Exception, e:
|
||||
info( u"Error during NBT load: {0!r}".format(e) )
|
||||
info( u"Fallback: Detected compressed flat block array, yzx ordered " )
|
||||
info(u"Error during NBT load: {0!r}".format(e))
|
||||
info(u"Fallback: Detected compressed flat block array, yzx ordered ")
|
||||
try:
|
||||
lev = MCJavaLevel(filename, data);
|
||||
lev.compressed = compressed;
|
||||
return lev;
|
||||
except Exception, e2:
|
||||
raise LoadingError, ("Multiple errors encountered", e, e2)
|
||||
|
||||
|
||||
else:
|
||||
if(MCIndevLevel._isTagLevel(root_tag)):
|
||||
info( u"Detected Indev .mclevel" )
|
||||
info(u"Detected Indev .mclevel")
|
||||
return MCIndevLevel(root_tag, filename)
|
||||
if(MCSchematic._isTagLevel(root_tag)):
|
||||
info( u"Detected Schematic." )
|
||||
info(u"Detected Schematic.")
|
||||
return MCSchematic(root_tag=root_tag, filename=filename)
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
#it must be a plain array of blocks. see if MCJavaLevel handles it.
|
||||
|
||||
|
||||
raise IOError, "Cannot detect file type."
|
||||
|
||||
|
||||
|
||||
def loadWorld(name):
|
||||
filename = os.path.join(saveFileDir, name)
|
||||
return fromFile(filename)
|
||||
|
||||
|
||||
def loadWorldNumber(i):
|
||||
#deprecated
|
||||
filename = u"{0}{1}{2}{3}{1}".format(saveFileDir, os.sep, u"World", i)
|
||||
|
@ -60,8 +60,8 @@ def unpack_first(func):
|
||||
return func(self, *args, **kw);
|
||||
upk_first.__doc__ = func.__doc__
|
||||
return upk_first
|
||||
|
||||
class PlayerNotFound(Exception): pass
|
||||
|
||||
class PlayerNotFound(Exception): pass
|
||||
class ChunkNotPresent(Exception): pass
|
||||
class RegionMalformed(Exception): pass
|
||||
class ChunkMalformed(ChunkNotPresent): pass
|
||||
|
248
nbt.py
248
nbt.py
@ -33,17 +33,17 @@ class NBTFormatError(RuntimeError): pass
|
||||
class TAG_Value(object):
|
||||
"""Simple values. Subclasses override fmt to change the type and size.
|
||||
Subclasses may set dataType instead of overriding setValue for automatic data type coercion"""
|
||||
|
||||
|
||||
fmt = ">b";
|
||||
tag = -1; #error!
|
||||
|
||||
|
||||
_value = None
|
||||
def getValue(self):
|
||||
return self._value
|
||||
def setValue(self, newVal):
|
||||
self._value = self.dataType(newVal)
|
||||
value = property(getValue, setValue, None, "Change the TAG's value. Data types are checked and coerced if needed.")
|
||||
|
||||
|
||||
_name = None
|
||||
def getName(self):
|
||||
return self._name
|
||||
@ -52,29 +52,29 @@ class TAG_Value(object):
|
||||
def delName(self):
|
||||
self._name = ""
|
||||
name = property(getName, setName, delName, "Change the TAG's name. Coerced to a string.")
|
||||
|
||||
|
||||
def __init__(self, value=0, name=None, data=""):
|
||||
self.name = name
|
||||
if(data == ""):
|
||||
self.value = value
|
||||
else:
|
||||
else:
|
||||
(self.value,) = struct.unpack_from(self.fmt, data);
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "%s( \"%s\" ): %s" % (str(self.__class__), self.name, repr(self.value))
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.pretty_string()
|
||||
|
||||
|
||||
def pretty_string(self, indent=0):
|
||||
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:
|
||||
return " "*indent + "%s: %s" % (str(self.__class__.__name__), self.value)
|
||||
|
||||
return " " * indent + "%s: %s" % (str(self.__class__.__name__), self.value)
|
||||
|
||||
def nbt_length(self):
|
||||
return struct.calcsize(self.fmt);
|
||||
|
||||
|
||||
def write_tag(self, buf):
|
||||
buf.write(struct.pack(TAGfmt, self.tag))
|
||||
def write_name(self, buf):
|
||||
@ -82,7 +82,7 @@ class TAG_Value(object):
|
||||
TAG_String(self.name).write_value(buf)
|
||||
def write_value(self, buf):
|
||||
buf.write(struct.pack(self.fmt, self.value))
|
||||
|
||||
|
||||
def save(self, filename="", buf=None):
|
||||
if(filename):
|
||||
self.saveGzipped(filename);
|
||||
@ -100,7 +100,7 @@ class TAG_Value(object):
|
||||
except Exception, e:
|
||||
#print "Atomic Save: No existing file to rename"
|
||||
pass
|
||||
|
||||
|
||||
with closing(gzip.GzipFile(fileobj=sio, mode="wb", compresslevel=compresslevel)) as outputGz:
|
||||
self.save(buf=outputGz);
|
||||
outputGz.flush();
|
||||
@ -115,27 +115,27 @@ class TAG_Value(object):
|
||||
except Exception, e:
|
||||
print e;
|
||||
return
|
||||
|
||||
|
||||
try: os.remove(filename + ".old");
|
||||
except Exception, e:
|
||||
#print "Atomic Save: No old file to remove"
|
||||
pass;
|
||||
|
||||
|
||||
class TAG_Byte(TAG_Value):
|
||||
tag = 1;
|
||||
fmt = ">b";
|
||||
dataType = int
|
||||
|
||||
|
||||
class TAG_Short(TAG_Value):
|
||||
tag = 2;
|
||||
fmt = ">h";
|
||||
dataType = int
|
||||
|
||||
|
||||
class TAG_Int(TAG_Value):
|
||||
tag = 3;
|
||||
fmt = ">i";
|
||||
dataType = int
|
||||
|
||||
|
||||
class TAG_Long(TAG_Value):
|
||||
tag = 4;
|
||||
fmt = ">q";
|
||||
@ -146,7 +146,7 @@ class TAG_Float(TAG_Value):
|
||||
fmt = ">f";
|
||||
dataType = float
|
||||
|
||||
|
||||
|
||||
class TAG_Double(TAG_Value):
|
||||
tag = 6;
|
||||
fmt = ">d";
|
||||
@ -162,22 +162,22 @@ class TAG_Byte_Array(TAG_Value):
|
||||
|
||||
def dataType(self, value):
|
||||
return array(value, uint8)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: length %d> ( %s )" % (self.__class__, len(self.value), self.name)
|
||||
|
||||
|
||||
|
||||
|
||||
def pretty_string(self, indent=0):
|
||||
if self.name:
|
||||
return " "*indent + "%s( \"%s\" ): shape=%s dtype=%s %s" % (
|
||||
str(self.__class__.__name__),
|
||||
self.name,
|
||||
return " " * indent + "%s( \"%s\" ): shape=%s dtype=%s %s" % (
|
||||
str(self.__class__.__name__),
|
||||
self.name,
|
||||
str(self.value.shape),
|
||||
str(self.value.dtype),
|
||||
str(self.value.dtype),
|
||||
self.value)
|
||||
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=""):
|
||||
self.name = name
|
||||
if(data == ""):
|
||||
@ -185,21 +185,21 @@ class TAG_Byte_Array(TAG_Value):
|
||||
else:
|
||||
(string_len,) = struct.unpack_from(">I", data);
|
||||
self.value = fromstring(data[4:string_len + 4], 'uint8');
|
||||
|
||||
|
||||
def nbt_length(self) :
|
||||
return len(self.value) + 4;
|
||||
|
||||
|
||||
def write_value(self, buf):
|
||||
#print self.value
|
||||
valuestr = self.value.tostring()
|
||||
buf.write(struct.pack(self.fmt % (len(valuestr),), len(valuestr), valuestr))
|
||||
|
||||
|
||||
class TAG_Int_Array(TAG_Byte_Array):
|
||||
"""An array of ints"""
|
||||
tag = 11;
|
||||
def dataType(self, value):
|
||||
return array(value, '>u4')
|
||||
|
||||
|
||||
def __init__(self, value=zeros(0, ">u4"), name=None, data=""):
|
||||
self.name = name
|
||||
if(data == ""):
|
||||
@ -207,22 +207,22 @@ class TAG_Int_Array(TAG_Byte_Array):
|
||||
else:
|
||||
(string_len,) = struct.unpack_from(">I", data);
|
||||
self.value = fromstring(data[4:string_len * 4 + 4], '>u4')
|
||||
|
||||
|
||||
|
||||
|
||||
def nbt_length(self) :
|
||||
return len(self.value) * 4 + 4;
|
||||
|
||||
|
||||
def write_value(self, buf):
|
||||
#print self.value
|
||||
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):
|
||||
"""An array of ints"""
|
||||
tag = 12;
|
||||
def dataType(self, value):
|
||||
return array(value, '>u2')
|
||||
|
||||
|
||||
def __init__(self, value=zeros(0, ">u2"), name=None, data=""):
|
||||
self.name = name
|
||||
if(data == ""):
|
||||
@ -230,25 +230,25 @@ class TAG_Short_Array(TAG_Int_Array):
|
||||
else:
|
||||
(string_len,) = struct.unpack_from(">I", data);
|
||||
self.value = fromstring(data[4:string_len * 2 + 4], '>u2')
|
||||
|
||||
|
||||
|
||||
|
||||
def nbt_length(self) :
|
||||
return len(self.value) * 2 + 4;
|
||||
|
||||
|
||||
def write_value(self, buf):
|
||||
#print self.value
|
||||
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):
|
||||
"""String in UTF-8
|
||||
The data parameter should either be a 'unicode' or an ascii-encoded 'str'
|
||||
"""
|
||||
|
||||
|
||||
tag = 8;
|
||||
fmt = ">h%ds"
|
||||
dataType = unicode
|
||||
|
||||
|
||||
def __init__(self, value="", name=None, data=""):
|
||||
self.name = name
|
||||
if(data == ""):
|
||||
@ -263,7 +263,7 @@ class TAG_String(TAG_Value):
|
||||
def write_value(self, buf):
|
||||
u8value = self.value.encode('utf-8')
|
||||
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."""
|
||||
|
||||
tag = 10;
|
||||
|
||||
|
||||
def dataType(self, val):
|
||||
for i in val:
|
||||
assert isinstance(i, TAG_Value)
|
||||
assert i.name
|
||||
return list(val)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "%s( %s ): %s" % (str(self.__class__.__name__), self.name, self.value)
|
||||
|
||||
|
||||
def pretty_string(self, indent=0):
|
||||
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:
|
||||
pretty = " "*indent + "%s():\n" % (str(self.__class__.__name__))
|
||||
pretty = " " * indent + "%s():\n" % (str(self.__class__.__name__))
|
||||
indent += 4
|
||||
for tag in self.value:
|
||||
pretty += tag.pretty_string(indent) + "\n"
|
||||
return pretty
|
||||
|
||||
|
||||
|
||||
|
||||
def __init__(self, value=[], name="", data=""):
|
||||
|
||||
|
||||
self.name = name;
|
||||
if value.__class__ == ''.__class__:
|
||||
self.name = value;
|
||||
@ -306,7 +306,7 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
|
||||
else:
|
||||
|
||||
data_cursor = 0;
|
||||
|
||||
|
||||
while data_cursor < len(data):
|
||||
tag_type = data[data_cursor];
|
||||
data_cursor += 1;
|
||||
@ -314,21 +314,21 @@ class TAG_Compound(TAG_Value, collections.MutableMapping):
|
||||
break;
|
||||
|
||||
assert_type(tag_type, data_cursor)
|
||||
|
||||
|
||||
|
||||
|
||||
data_cursor, tag = load_named(data, data_cursor, tag_type)
|
||||
|
||||
|
||||
self.value.append(tag);
|
||||
|
||||
|
||||
|
||||
|
||||
def nbt_length(self):
|
||||
return sum(x.nbt_length() + len(x.name) + 3 for x in self.value) + 1;
|
||||
|
||||
|
||||
def write_value(self, buf):
|
||||
for i in self.value:
|
||||
i.save(buf=buf)
|
||||
buf.write("\x00")
|
||||
|
||||
|
||||
"collection functions"
|
||||
def __getitem__(self, k):
|
||||
#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:
|
||||
if key.name == k: return key
|
||||
raise KeyError("Key {0} not found".format(k));
|
||||
|
||||
|
||||
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 __len__(self): return self.value.__len__()
|
||||
|
||||
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
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)
|
||||
self.value.append(v);
|
||||
v.name = k;
|
||||
|
||||
|
||||
def __delitem__(self, k): self.value.__delitem__(self.value.index(self[k]));
|
||||
|
||||
def add(self, v):
|
||||
self[v.name] = v;
|
||||
|
||||
|
||||
class TAG_List(TAG_Value, collections.MutableSequence):
|
||||
|
||||
|
||||
"""A homogenous list of unnamed data of a single TAG_* type.
|
||||
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,
|
||||
@ -372,53 +372,53 @@ class TAG_List(TAG_Value, collections.MutableSequence):
|
||||
# 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)
|
||||
return list(val)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "%s( %s ): %s" % (self.__class__.__name__, self.name, self.value)
|
||||
|
||||
|
||||
|
||||
|
||||
def pretty_string(self, indent=0):
|
||||
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:
|
||||
pretty = " "*indent + "%s():\n" % (str(self.__class__.__name__), )
|
||||
|
||||
pretty = " " * indent + "%s():\n" % (str(self.__class__.__name__),)
|
||||
|
||||
indent += 4
|
||||
for tag in self.value:
|
||||
pretty += tag.pretty_string(indent) + "\n"
|
||||
return pretty
|
||||
|
||||
|
||||
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
|
||||
#name, or created from raw tag data, or created with list_type
|
||||
#taken from a TAG class or instance
|
||||
|
||||
|
||||
self.name = name
|
||||
self.value = [];
|
||||
self.list_type = list_type.tag
|
||||
|
||||
|
||||
if(data == None):
|
||||
if(len(value)):
|
||||
self.list_type = value[0].tag;
|
||||
value = filter(lambda x:x.__class__ == value[0].__class__, value)
|
||||
|
||||
|
||||
self.value = value
|
||||
|
||||
else:
|
||||
else:
|
||||
data_cursor = 0;
|
||||
|
||||
self.list_type = data[data_cursor];
|
||||
assert_type(self.list_type, data_cursor);
|
||||
|
||||
|
||||
data_cursor += 1;
|
||||
|
||||
list_length = TAG_Int(data=data[data_cursor:])
|
||||
data_cursor += list_length.nbt_length()
|
||||
list_length = list_length.value
|
||||
|
||||
|
||||
|
||||
for i in range(list_length):
|
||||
|
||||
|
||||
tag = tag_handlers[self.list_type](data=data[data_cursor:])
|
||||
self.append(tag);
|
||||
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 __getitem__(self, i): return self.value[i];
|
||||
def __len__(self): return len(self.value)
|
||||
|
||||
|
||||
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]))
|
||||
v.name = ""
|
||||
self.value[i] = v;
|
||||
|
||||
def __delitem__(self, i):
|
||||
|
||||
def __delitem__(self, i):
|
||||
del self.value[i]
|
||||
|
||||
|
||||
def insert(self, i, v):
|
||||
if not v.tag in tag_handlers: raise TypeError("Not a tag type: %s" % (v,))
|
||||
if len(self) == 0:
|
||||
self.list_type = v.tag
|
||||
if len(self) == 0:
|
||||
self.list_type = v.tag
|
||||
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]))
|
||||
|
||||
|
||||
v.name = ""
|
||||
self.value.insert(i, v);
|
||||
|
||||
|
||||
def nbt_length(self):
|
||||
return 5 + sum(x.nbt_length() for x in self.value)
|
||||
|
||||
|
||||
def write_value(self, buf):
|
||||
buf.write(struct.pack(TAGfmt, self.list_type))
|
||||
TAG_Int(len(self)).write_value(buf)
|
||||
for i in self.value:
|
||||
i.write_value(buf)
|
||||
|
||||
|
||||
|
||||
tag_handlers = {
|
||||
1 : TAG_Byte,
|
||||
@ -476,11 +476,11 @@ tag_handlers = {
|
||||
def assert_type(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):
|
||||
#strip off the header and use negative WBITS to tell zlib there's no header
|
||||
return zlib.decompress(data[10:], -zlib.MAX_WBITS)
|
||||
|
||||
|
||||
def loadFile(filename):
|
||||
#sio = StringIO.StringIO();
|
||||
with file(filename, "rb") as f:
|
||||
@ -491,14 +491,14 @@ def loadFile(filename):
|
||||
data = gunzip(inputdata)
|
||||
except IOError:
|
||||
print "File %s not zipped" % filename
|
||||
|
||||
|
||||
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
|
||||
@ -507,7 +507,7 @@ def load(filename="", buf=None):
|
||||
"""Unserialize data from an entire NBT file and return the
|
||||
root TAG_Compound object. Argument can be a string containing a
|
||||
filename or an array of integers containing TAG_Compound data. """
|
||||
|
||||
|
||||
if filename and isinstance(filename, (str, unicode)):
|
||||
return loadFile(filename)
|
||||
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."""
|
||||
print level["Environment"]["SurroundingGroundHeight"].value;
|
||||
|
||||
|
||||
|
||||
|
||||
"""Numeric, string, and bytearray types have a value
|
||||
that can be accessed and changed. """
|
||||
print level["Map"]["Blocks"].value
|
||||
|
||||
|
||||
return level;
|
||||
|
||||
def createtest():
|
||||
"Create an indev level."
|
||||
|
||||
|
||||
"The root of an NBT file is always a TAG_Compound."
|
||||
level = TAG_Compound(name="MinecraftLevel")
|
||||
|
||||
@ -558,52 +558,52 @@ def createtest():
|
||||
level["Environment"] = TAG_Compound()
|
||||
level["Environment"]["SkyBrightness"] = TAG_Byte(16)
|
||||
level["Environment"]["SurroundingWaterHeight"] = TAG_Short(32)
|
||||
|
||||
|
||||
"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.name = "Spawn"
|
||||
|
||||
|
||||
mapTag = TAG_Compound()
|
||||
mapTag.add(spawn);
|
||||
mapTag.name = "Map"
|
||||
level.add(mapTag)
|
||||
|
||||
|
||||
"I think it looks more familiar with [] syntax."
|
||||
|
||||
|
||||
l, w, h = 128, 128, 128
|
||||
mapTag["Height"] = TAG_Short(h) # y dimension
|
||||
mapTag["Length"] = TAG_Short(l) # z dimension
|
||||
mapTag["Width"] = TAG_Short(w) # x dimension
|
||||
|
||||
|
||||
"Byte arrays are stored as numpy.uint8 arrays. "
|
||||
|
||||
|
||||
mapTag["Blocks"] = TAG_Byte_Array()
|
||||
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"
|
||||
mapTag["Blocks"].value.shape = (h, l, w);
|
||||
|
||||
|
||||
"Replace the bottom layer of the indev level with wood"
|
||||
mapTag["Blocks"].value[0, :, :] = 5;
|
||||
|
||||
|
||||
"This is a great way to learn the power of numpy array slicing and indexing."
|
||||
|
||||
|
||||
|
||||
|
||||
return level;
|
||||
|
||||
def modifytest():
|
||||
level = createtest();
|
||||
|
||||
|
||||
"Most of the value types work as expected. Here, we replace the entire tag with a TAG_String"
|
||||
level["About"]["Author"] = TAG_String("YARRR~!");
|
||||
|
||||
|
||||
"Because the tag type usually doesn't change, "
|
||||
"we can replace the string tag's value instead of replacing the entire tag."
|
||||
level["About"]["Author"].value = "Stew Pickles"
|
||||
|
||||
|
||||
"Remove members of a TAG_Compound using del, similar to a python dict."
|
||||
del(level["About"]);
|
||||
|
||||
|
||||
"Replace all of the wood blocks with gold using a boolean index array"
|
||||
blocks = level["Map"]["Blocks"].value
|
||||
blocks[blocks == 5] = 41;
|
||||
@ -613,10 +613,10 @@ def savetest():
|
||||
|
||||
level = createtest()
|
||||
level["Environment"]["SurroundingWaterHeight"].value += 6;
|
||||
|
||||
|
||||
"Save the entire TAG structure to a different file."
|
||||
level.save("atlantis.mclevel")
|
||||
|
||||
|
||||
level = createtest();
|
||||
level.save("synthetic.mclevel");
|
||||
|
||||
@ -626,7 +626,7 @@ def abusetest():
|
||||
named list elements are not allowed by the NBT spec,
|
||||
so we must discard any names when writing a list.
|
||||
"""
|
||||
|
||||
|
||||
level = createtest();
|
||||
level["Map"]["Spawn"][0].name = "Torg Potter"
|
||||
sio = StringIO.StringIO()
|
||||
@ -647,9 +647,9 @@ def abusetest():
|
||||
pass
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
||||
def runtests():
|
||||
|
||||
|
||||
def runtests():
|
||||
loadtest();
|
||||
createtest();
|
||||
modifytest();
|
||||
@ -661,5 +661,5 @@ if(__name__ == "__main__") :
|
||||
runtests()
|
||||
|
||||
__all__ = [a.__name__ for a in tag_handlers.itervalues()] + ["loadFile", "gunzip"]
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ def generate_file_list(directory):
|
||||
yield os.path.join(dirpath, filename)
|
||||
|
||||
def sha1_file(name, checksum=None):
|
||||
CHUNKSIZE=1024
|
||||
CHUNKSIZE = 1024
|
||||
if checksum is None:
|
||||
checksum = hashlib.sha1()
|
||||
if fnmatch.fnmatch(name, "*.dat"):
|
||||
@ -71,17 +71,17 @@ def untared_content(src):
|
||||
f.extractall(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
|
||||
#if sys.platform == "win32":
|
||||
newenv = {}
|
||||
newenv.update(os.environ)
|
||||
newenv.update(env);
|
||||
|
||||
|
||||
proc = subprocess.Popen((["python.exe"] if sys.platform == "win32" else []) + [
|
||||
"./mce.py",
|
||||
directory] + arguments, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=newenv)
|
||||
|
||||
|
||||
return proc
|
||||
|
||||
class RegressionError(Exception): pass
|
||||
@ -129,7 +129,7 @@ def do_test_match_output(test_data, result_check, arguments=[]):
|
||||
proc.stdin.close()
|
||||
output = proc.stdout.read()
|
||||
proc.wait()
|
||||
|
||||
|
||||
if proc.returncode:
|
||||
raise RegressionError("Program execution failed!")
|
||||
|
||||
@ -146,13 +146,13 @@ def do_test_match_output(test_data, result_check, arguments=[]):
|
||||
|
||||
|
||||
alpha_tests = [
|
||||
(do_test, 'baseline', '9e7460d39c8e0456789cf89fee45276db2719aaa', []),
|
||||
(do_test, 'degrief', '403e6c6147cf1f8d73377b18bbf5e4973606a311', ['degrief']),
|
||||
(do_test_match_output, 'analyze', '89ae362dec7f6c0fd743d6ed4e3957459cb3c34d', ['analyze']),
|
||||
(do_test, 'relight', 'e0cf60c62adfdb313f198af5314c31f89d158c12', ['relight']),
|
||||
(do_test, 'replace', 'd73767293e903b6d1c49c1838eb1849b69d83ad8', ['replace', 'Water (active)', 'with', 'Lava (active)']),
|
||||
(do_test, 'fill', 'f4f57c3d902b6894031d416cb9279232e7e24bd7', ['fill', 'Water (active)']),
|
||||
(do_test, 'heightmap', '9e7460d39c8e0456789cf89fee45276db2719aaa', ['heightmap', 'regression_test/mars.png']),
|
||||
(do_test, 'baseline', '9e7460d39c8e0456789cf89fee45276db2719aaa', []),
|
||||
(do_test, 'degrief', '403e6c6147cf1f8d73377b18bbf5e4973606a311', ['degrief']),
|
||||
(do_test_match_output, 'analyze', '89ae362dec7f6c0fd743d6ed4e3957459cb3c34d', ['analyze']),
|
||||
(do_test, 'relight', 'e0cf60c62adfdb313f198af5314c31f89d158c12', ['relight']),
|
||||
(do_test, 'replace', 'd73767293e903b6d1c49c1838eb1849b69d83ad8', ['replace', 'Water (active)', 'with', 'Lava (active)']),
|
||||
(do_test, 'fill', 'f4f57c3d902b6894031d416cb9279232e7e24bd7', ['fill', 'Water (active)']),
|
||||
(do_test, 'heightmap', '9e7460d39c8e0456789cf89fee45276db2719aaa', ['heightmap', 'regression_test/mars.png']),
|
||||
]
|
||||
|
||||
import optparse
|
||||
@ -172,26 +172,26 @@ def main(argv):
|
||||
test_data = os.path.join(directory, "alpha")
|
||||
passes = []
|
||||
fails = []
|
||||
|
||||
|
||||
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 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
|
||||
try:
|
||||
func(test_data, sha, args)
|
||||
except RegressionError, e:
|
||||
fails.append( "Regression {0} failed: {1}".format(name, e) )
|
||||
fails.append("Regression {0} failed: {1}".format(name, e))
|
||||
print fails[-1]
|
||||
else:
|
||||
passes.append( "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__':
|
||||
sys.exit(main(sys.argv))
|
||||
|
@ -468,6 +468,7 @@ def extractSchematicFrom(sourceLevel, box):
|
||||
|
||||
return tempSchematic
|
||||
|
||||
import tempfile
|
||||
def extractZipSchematicFrom(sourceLevel, box, zipfilename):
|
||||
#converts classic blocks to alpha
|
||||
#probably should only apply to alpha levels
|
||||
|
Reference in New Issue
Block a user