diff --git a/entity.py b/entity.py index 46d7664..48d66a6 100644 --- a/entity.py +++ b/entity.py @@ -7,7 +7,22 @@ from mclevelbase import * __all__ = "Entity, TileEntity".split(", ") +EntityId = "EntityId" +id = "id" + +Motion = "Motion" +Pos = "Pos" +Rotation = "Rotation" + class TileEntity(object): + knownIDs = "Furnace, Sign, MonsterSpawner, Chest, Music, Trap, RecordPlayer".split(", ") + @classmethod + def Create(cls, tileEntityID, **kw): + tileEntityTag = TAG_Compound() + tileEntityTag[id] = TAG_String(tileEntityID) + cls.setpos(tileEntityTag, (0, 0, 0)) + return tileEntityTag + @classmethod def pos(cls, tag): return [tag[a].value for a in 'xyz'] @@ -17,12 +32,28 @@ class TileEntity(object): for a, p in zip('xyz', pos): tag[a] = TAG_Int(p) + @classmethod + def copyWithOffset(cls, tileEntity, copyOffset): + eTag = deepcopy(tileEntity) + eTag['x'] = TAG_Int(tileEntity['x'].value + copyOffset[0]) + eTag['y'] = TAG_Int(tileEntity['y'].value + copyOffset[1]) + eTag['z'] = TAG_Int(tileEntity['z'].value + copyOffset[2]) + return eTag + + class Entity(object): + @classmethod + def Create(cls, entityID, **kw): + entityTag = TAG_Compound() + entityTag[EntityId] = TAG_String(entityID) + entityTag[Pos] = [TAG_Int(0) for i in range(3)] + return entityTag + @classmethod def pos(cls, tag): - if "Pos" not in tag: - print tag - return [a.value for a in tag["Pos"]] + if Pos not in tag: + raise InvalidEntity, tag + return [a.value for a in tag[Pos]] @classmethod def setpos(cls, tag, pos): @@ -41,3 +72,6 @@ class Entity(object): eTag["TileZ"].value += copyOffset[2] return eTag + +class InvalidEntity(ValueError): pass +class InvalidTileEntity(ValueError): pass diff --git a/infiniteworld.py b/infiniteworld.py index 85253cf..928ba59 100644 --- a/infiniteworld.py +++ b/infiniteworld.py @@ -1896,22 +1896,21 @@ class MCInfdevOldLevel(MCLevel): entities = []; if chunk.Entities is None: return entities; for entity in chunk.Entities: - if map(lambda x:int(x.value), entity[Pos]) == [x, y, z]: + if map(lambda x:int(floor(x)), Entity.pos(entity)) == [x, y, z]: entities.append(entity); return entities; - def addEntity(self, entity): - assert isinstance(entity, TAG_Compound) - x = int(entity[Pos][0].value) - z = int(entity[Pos][2].value) + def addEntity(self, entityTag): + assert isinstance(entityTag, TAG_Compound) + x, y, z = map(lambda x:int(floor(x)), Entity.pos(entityTag)) try: chunk = self.getChunk(x >> 4, z >> 4) except (ChunkNotPresent, ChunkMalformed), e: return None # raise Error, can't find a chunk? - chunk.Entities.append(entity); + chunk.Entities.append(entityTag); chunk.dirty = True def tileEntityAt(self, x, y, z): @@ -1931,13 +1930,10 @@ class MCInfdevOldLevel(MCLevel): return entities[0]; - def addTileEntity(self, entity): - assert isinstance(entity, TAG_Compound) - if not 'x' in entity: return - - x = int(entity['x'].value) - y = int(entity['y'].value) - z = int(entity['z'].value) + def addTileEntity(self, tileEntityTag): + assert isinstance(tileEntityTag, TAG_Compound) + if not 'x' in tileEntityTag: return + x, y, z = TileEntity.pos(tileEntityTag) try: chunk = self.getChunk(x >> 4, z >> 4) @@ -1945,11 +1941,11 @@ class MCInfdevOldLevel(MCLevel): return # raise Error, can't find a chunk? def differentPosition(a): - return not ((entity is a) or ('x' in a and (a['x'].value == x and a['y'].value == y and a['z'].value == z))) + return not ((tileEntityTag is a) or ('x' in a and (a['x'].value == x and a['y'].value == y and a['z'].value == z))) chunk.TileEntities.value[:] = filter(differentPosition, chunk.TileEntities); - chunk.TileEntities.append(entity); + chunk.TileEntities.append(tileEntityTag); chunk.dirty = True def removeEntitiesInBox(self, box): diff --git a/level.py b/level.py index 3416198..9ee1bd0 100644 --- a/level.py +++ b/level.py @@ -569,16 +569,6 @@ class MCLevel(object): def playerOrientation(self, player="Player"): return (-45., 0.) - def copyEntityWithOffset(self, entity, copyOffset): - return Entity.copyWithOffset(entity, copyOffset) - - - def copyTileEntityWithOffset(self, tileEntity, copyOffset): - eTag = deepcopy(tileEntity) - eTag['x'] = TAG_Int(tileEntity['x'].value + copyOffset[0]) - eTag['y'] = TAG_Int(tileEntity['y'].value + copyOffset[1]) - eTag['z'] = TAG_Int(tileEntity['z'].value + copyOffset[2]) - return eTag def copyEntitiesFromInfinite(self, sourceLevel, sourceBox, destinationPoint): chunkIterator = sourceLevel.getChunkSlices(sourceBox); @@ -586,29 +576,24 @@ class MCLevel(object): for (chunk, slices, point) in chunkIterator: #remember, slices are ordered x,z,y so you can subscript them like so: chunk.Blocks[slices] cx, cz = chunk.chunkPosition - wx, wz = cx << 4, cz << 4 + #wx, wz = cx << 4, cz << 4 copyOffset = map(lambda x, y:x - y, destinationPoint, sourceBox.origin) - for entity in chunk.Entities: - x, y, z = map(lambda x:x.value, entity[Pos]) + for entityTag in chunk.Entities: + x, y, z = Entity.pos(entityTag) + if (x, y, z) not in sourceBox: continue - if x - wx < slices[0].start or x - wx >= slices[0].stop: continue - if y < slices[2].start or y >= slices[2].stop: continue - if z - wz < slices[1].start or z - wz >= slices[1].stop: continue - - eTag = self.copyEntityWithOffset(entity, copyOffset) + eTag = Entity.copyWithOffset(entityTag, copyOffset) self.addEntity(eTag); - for tileEntity in chunk.TileEntities: - if not 'x' in tileEntity: continue + for tileEntityTag in chunk.TileEntities: + if not 'x' in tileEntityTag: continue - x, y, z = tileEntity['x'].value, tileEntity['y'].value, tileEntity['z'].value - if x - wx < slices[0].start or x - wx >= slices[0].stop: continue - if y < slices[2].start or y >= slices[2].stop: continue - if z - wz < slices[1].start or z - wz >= slices[1].stop: continue + x, y, z = TileEntity.pos(tileEntityTag) + if (x, y, z) not in sourceBox: continue - eTag = self.copyTileEntityWithOffset(tileEntity, copyOffset) + eTag = TileEntity.copyWithOffset(tileEntityTag, copyOffset) self.addTileEntity(eTag) @@ -628,7 +613,7 @@ class MCLevel(object): tileEntsCopied = 0; copyOffset = map(lambda x, y:x - y, destinationPoint, sourcePoint0) for entity in getEntitiesInRange(sourceBox, sourceLevel.Entities): - eTag = self.copyEntityWithOffset(entity, copyOffset) + eTag = Entity.copyWithOffset(entity, copyOffset) self.addEntity(eTag) entsCopied += 1; @@ -636,13 +621,8 @@ class MCLevel(object): for entity in getTileEntitiesInRange(sourceBox, sourceLevel.TileEntities): if not 'x' in entity: continue + eTag = TileEntity.copyWithOffset(entity, copyOffset) - x, y, z = entity['x'].value, entity['y'].value, entity['z'].value - - eTag = deepcopy(entity) - eTag['x'] = TAG_Int(x + copyOffset[0]) - eTag['y'] = TAG_Int(y + copyOffset[1]) - eTag['z'] = TAG_Int(z + copyOffset[2]) try: self.addTileEntity(eTag) tileEntsCopied += 1; diff --git a/mclevelbase.py b/mclevelbase.py index 7d46c91..8d36082 100644 --- a/mclevelbase.py +++ b/mclevelbase.py @@ -41,12 +41,9 @@ Height = "Height" Length = "Length" Blocks = "Blocks" Data = "Data" +Inventory = 'Inventory' #entities -Inventory = 'Inventory' -Motion = "Motion" -Pos = "Pos" -Rotation = "Rotation" def decompress_first(func): def dec_first(self, *args, **kw): diff --git a/tests.py b/tests.py index 5cf8f3b..91a5cc5 100644 --- a/tests.py +++ b/tests.py @@ -3,9 +3,10 @@ Created on Jul 23, 2011 @author: Rio ''' -from mclevel import fromFile, loadWorldNumber, BoundingBox -from infiniteworld import MCInfdevOldLevel -from schematic import MCSchematic +#from mclevel import fromFile, loadWorldNumber, BoundingBox +#from infiniteworld import MCInfdevOldLevel +#from schematic import MCSchematic +from pymclevel import * import itertools import traceback @@ -54,6 +55,16 @@ class TestIndevLevel(unittest.TestCase): self.srclevel = TempLevel("hell.mclevel") self.indevlevel = TempLevel("hueg.mclevel") + def testEntities(self): + level = self.indevlevel.level + entityTag = Entity.Create("Zombie") + tileEntityTag = TileEntity.Create("Painting") + level.addEntity(entityTag) + level.addTileEntity(tileEntityTag) + schem = level.extractSchematic(level.bounds) + level.copyBlocksFrom(schem, schem.bounds, (0, 0, 0)) + + #raise Failure def testCopy(self): info("Indev level") @@ -96,19 +107,25 @@ class TestAlphaLevel(unittest.TestCase): self.alphalevel = TempLevel("PyTestWorld") - def testAlphaLevels(self): - info("Alpha level") - + def testCreateChunks(self): indevlevel = self.indevlevel.level - level = self.alphalevel.level + for ch in list(level.allChunks): level.deleteChunk(*ch) level.createChunksInBox(BoundingBox((0, 0, 0), (32, 0, 32))) + + def testCopyConvertBlocks(self): + indevlevel = self.indevlevel.level + level = self.alphalevel.level level.copyBlocksFrom(indevlevel, BoundingBox((0, 0, 0), (256, 128, 256)), (-0, 0, 0)) convertedSourceBlocks, convertedSourceData = indevlevel.convertBlocksFromLevel(level, indevlevel.Blocks[0:16, 0:16, 0:indevlevel.Height], indevlevel.Data[0:16, 0:16, 0:indevlevel.Height]) assert (level.getChunk(0, 0).Blocks[0:16, 0:16, 0:indevlevel.Height] == convertedSourceBlocks).all() + def testImportSchematic(self): + indevlevel = self.indevlevel.level + level = self.alphalevel.level + schem = fromFile("schematics\\CreativeInABox.schematic"); level.copyBlocksFrom(schem, BoundingBox((0, 0, 0), (1, 1, 3)), (0, 64, 0)); schem = MCSchematic(shape=(1, 1, 3)) @@ -116,32 +133,37 @@ class TestAlphaLevel(unittest.TestCase): convertedSourceBlocks, convertedSourceData = schem.convertBlocksFromLevel(level, schem.Blocks, schem.Data) assert (level.getChunk(0, 0).Blocks[0:1, 0:3, 64:65] == convertedSourceBlocks).all() - try: - for x, z in itertools.product(xrange(-1, 3), xrange(-1, 2)): - level.deleteChunk(x, z); - level.createChunk(x, z) - except Exception, e: - traceback.print_exc(); - print e; - level.fillBlocks(BoundingBox((-11, 0, -7), (38, 128, 25)) , indevlevel.materials.WoodPlanks); + def testRecreateChunks(self): + level = self.alphalevel.level + + for x, z in itertools.product(xrange(-1, 3), xrange(-1, 2)): + level.deleteChunk(x, z); + level.createChunk(x, z) + + def testFill(self): + level = self.alphalevel.level + + level.fillBlocks(BoundingBox((-11, 0, -7), (38, 128, 25)) , level.materials.WoodPlanks); c = level.getChunk(0, 0) assert (c.Blocks == 5).all() - level.fillBlocks(BoundingBox((-11, 0, -7), (38, 128, 25)) , indevlevel.materials.WoodPlanks, [indevlevel.materials.Dirt, indevlevel.materials.Grass]); - #print b.shape - #raise SystemExit + + def testReplace(self): + level = self.alphalevel.level + + level.fillBlocks(BoundingBox((-11, 0, -7), (38, 128, 25)) , level.materials.WoodPlanks, [level.materials.Dirt, level.materials.Grass]); + + def testSaveRelight(self): + indevlevel = self.indevlevel.level + level = self.alphalevel.level + cx, cz = -3, -1; - try: - level.deleteChunk(cx, cz); - except KeyError:pass + level.deleteChunk(cx, cz); + level.createChunk(cx, cz); level.copyBlocksFrom(indevlevel, BoundingBox((0, 0, 0), (64, 64, 64,)), (-96, 32, 0)) - #blocks = zeros((16,16,128), 'uint8'); - #blocks[:,:,:] = level.getChunk(cx, cz).Blocks[:,:,:] - #level.getChunk(cx, cz).Blocks[:,:,:] = blocks[:,:,:] - level.generateLights(); - level.saveInPlace(); + level.generateLights(); level.saveInPlace(); @@ -157,11 +179,10 @@ class TestSchematics(unittest.TestCase): schematic = MCSchematic(shape=size, filename="hell.schematic", mats='Classic'); level = self.indevlevel.level schematic.rotateLeft(); - try: - schematic.copyBlocksFrom(level, BoundingBox((-32, -32, -32), (64, 64, 64,)), (0, 0, 0)) - except ValueError: - pass; + self.failUnlessRaises(ValueError, lambda:( + schematic.copyBlocksFrom(level, BoundingBox((-32, -32, -32), (64, 64, 64,)), (0, 0, 0)) + )) schematic.copyBlocksFrom(level, BoundingBox((0, 0, 0), (64, 64, 64,)), (0, 0, 0)) assert((schematic.Blocks[0:64, 0:64, 0:64] == level.Blocks[0:64, 0:64, 0:64]).all())