def copyEntitiesFromInfiniteIter(self, sourceLevel, sourceBox, destinationPoint, entities): chunkCount = sourceBox.chunkCount i = 0 copyOffset = map(lambda x, y: x - y, destinationPoint, sourceBox.origin) e = t = 0 for (chunk, slices, point) in sourceLevel.getChunkSlices(sourceBox): yield (i, chunkCount) i += 1 if entities: e += len(chunk.Entities) for entityTag in chunk.Entities: x, y, z = Entity.pos(entityTag) if (x, y, z) not in sourceBox: continue eTag = Entity.copyWithOffset(entityTag, copyOffset) self.addEntity(eTag) t += len(chunk.TileEntities) for tileEntityTag in chunk.TileEntities: x, y, z = TileEntity.pos(tileEntityTag) if (x, y, z) not in sourceBox: continue eTag = TileEntity.copyWithOffset(tileEntityTag, copyOffset) self.addTileEntity(eTag) info("Copied {0} entities, {1} tile entities".format(e, t))
def tileEntityAt(self, x, y, z, print_stuff=False): entities = [] if print_stuff: print "len(self.TileEntities)", len(self.TileEntities) for entityTag in self.TileEntities: if print_stuff: print entityTag["id"].value, TileEntity.pos(entityTag), x, y, z if TileEntity.pos(entityTag) == [x, y, z]: entities.append(entityTag) if len(entities) > 1: log.info("Multiple tile entities found: {0}".format(entities)) if len(entities) == 0: return None return entities[0]
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))
def tileEntityAt(self, x, y, z): entities = [] for entityTag in self.TileEntities: if TileEntity.pos(entityTag) == [x, y, z]: entities.append(entityTag) if len(entities) > 1: log.info("Multiple tile entities found: {0}".format(entities)) if len(entities) == 0: return None return entities[0]
def removeTileEntities(self, func): if not hasattr(self, "TileEntities"): return newEnts = [] for ent in self.TileEntities: if func(TileEntity.pos(ent)): continue newEnts.append(ent) entsRemoved = len(self.TileEntities) - len(newEnts) log.debug("Removed {0} tile entities".format(entsRemoved)) self.TileEntities.value[:] = newEnts return entsRemoved
def removeTileEntitiesInBox(self, box): if not hasattr(self, "TileEntities"): return newEnts = [] for ent in self.TileEntities: if TileEntity.pos(ent) in box: continue newEnts.append(ent) entsRemoved = len(self.TileEntities) - len(newEnts) debug("Removed {0} tile entities".format(entsRemoved)) self.TileEntities.value[:] = newEnts return entsRemoved
def copyEntitiesFromIter(self, sourceLevel, sourceBox, destinationPoint, entities=True): # assume coords have already been adjusted by copyBlocks # if not self.hasEntities or not sourceLevel.hasEntities: # return sourcePoint0 = sourceBox.origin if sourceLevel.isInfinite: for i in self.copyEntitiesFromInfiniteIter(sourceLevel, sourceBox, destinationPoint, entities): yield i else: entsCopied = 0 tileEntsCopied = 0 copyOffset = map(lambda x, y: x - y, destinationPoint, sourcePoint0) if entities: for entity in sourceLevel.getEntitiesInBox(sourceBox): eTag = Entity.copyWithOffset(entity, copyOffset) self.addEntity(eTag) entsCopied += 1 i = 0 for entity in sourceLevel.getTileEntitiesInBox(sourceBox): i += 1 if i % 100 == 0: yield if not 'x' in entity: continue eTag = TileEntity.copyWithOffset(entity, copyOffset) try: self.addTileEntity(eTag) tileEntsCopied += 1 except ChunkNotPresent: pass yield info(u"Copied {0} entities, {1} tile entities".format( entsCopied, tileEntsCopied))
def _add_block(self, position, block): if position in self: self._remove_block(position, sync=True) if hasattr(block, 'entity_type'): # in world_server we have to create its entity to handle some tasks(growing, etc.) # but in client's world, we only create a TileEntity that contains the position # and the world to allow the block update itself and server will handle the task # and tell us self[position] = type(block)() self[position].entity = TileEntity(self, position) elif block.sub_id_as_metadata: self[position] = type(block)() self[position].set_metadata(block.get_metadata()) else: self[position] = block self.sectors[sectorize(position)].append(position) if self.is_exposed(position): self.show_block(position) self.inform_neighbors_of_block_change(position)
def copyEntitiesFromIter(self, sourceLevel, sourceBox, destinationPoint, entities=True): # assume coords have already been adjusted by copyBlocks # if not self.hasEntities or not sourceLevel.hasEntities: # return sourcePoint0 = sourceBox.origin if sourceLevel.isInfinite: for i in self.copyEntitiesFromInfiniteIter(sourceLevel, sourceBox, destinationPoint, entities): yield i else: entsCopied = 0 tileEntsCopied = 0 copyOffset = map(lambda x, y: x - y, destinationPoint, sourcePoint0) if entities: for entity in sourceLevel.getEntitiesInBox(sourceBox): eTag = Entity.copyWithOffset(entity, copyOffset) self.addEntity(eTag) entsCopied += 1 i = 0 for entity in sourceLevel.getTileEntitiesInBox(sourceBox): i += 1 if i % 100 == 0: yield if not 'x' in entity: continue eTag = TileEntity.copyWithOffset(entity, copyOffset) try: self.addTileEntity(eTag) tileEntsCopied += 1 except ChunkNotPresent: pass yield info(u"Copied {0} entities, {1} tile entities".format(entsCopied, tileEntsCopied))
def copyBlocksFromIter(destLevel, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True, create=False, biomes=False, tileTicks=True, staticCommands=False, moveSpawnerPos=False, regenerateUUID=False, first=False, cancelCommandBlockOffset=False): """ copy blocks between two infinite levels by looping through the destination's chunks. make a sub-box of the source level for each chunk and copy block and entities in the sub box to the dest chunk.""" (lx, ly, lz) = sourceBox.size sourceBox, destinationPoint = adjustCopyParameters(destLevel, sourceLevel, sourceBox, destinationPoint) # needs work xxx log.info(u"Copying {0} blocks from {1} to {2}".format(ly * lz * lx, sourceBox, destinationPoint)) startTime = datetime.now() destBox = BoundingBox(destinationPoint, sourceBox.size) chunkCount = destBox.chunkCount i = 0 e = 0 t = 0 tt = 0 sourceMask = sourceMaskFunc(blocksToCopy) copyOffset = [d - s for s, d in zip(sourceBox.origin, destinationPoint)] # Visit each chunk in the destination area. # Get the region of the source area corresponding to that chunk # Visit each chunk of the region of the source area # Get the slices of the destination chunk # Get the slices of the source chunk # Copy blocks and data for destCpos in destBox.chunkPositions: cx, cz = destCpos destChunkBox = BoundingBox((cx << 4, 0, cz << 4), (16, destLevel.Height, 16)).intersect(destBox) destChunkBoxInSourceLevel = BoundingBox([d - o for o, d in zip(copyOffset, destChunkBox.origin)], destChunkBox.size) if not destLevel.containsChunk(*destCpos): if create and any(sourceLevel.containsChunk(*c) for c in destChunkBoxInSourceLevel.chunkPositions): # Only create chunks in the destination level if the source level has chunks covering them. destLevel.createChunk(*destCpos) else: continue destChunk = destLevel.getChunk(*destCpos) i += 1 yield (i, chunkCount) if i % 100 == 0: log.info("Chunk {0}...".format(i)) for srcCpos in destChunkBoxInSourceLevel.chunkPositions: if not sourceLevel.containsChunk(*srcCpos): continue sourceChunk = sourceLevel.getChunk(*srcCpos) sourceChunkBox, sourceSlices = sourceChunk.getChunkSlicesForBox(destChunkBoxInSourceLevel) if sourceChunkBox.volume == 0: continue sourceChunkBoxInDestLevel = BoundingBox([d + o for o, d in zip(copyOffset, sourceChunkBox.origin)], sourceChunkBox.size) _, destSlices = destChunk.getChunkSlicesForBox(sourceChunkBoxInDestLevel) sourceBlocks = sourceChunk.Blocks[sourceSlices] sourceData = sourceChunk.Data[sourceSlices] mask = sourceMask(sourceBlocks) convertedSourceBlocks, convertedSourceData = convertBlocks(destLevel, sourceLevel, sourceBlocks, sourceData) destChunk.Blocks[destSlices][mask] = convertedSourceBlocks[mask] if convertedSourceData is not None: destChunk.Data[destSlices][mask] = convertedSourceData[mask] def copy(p): return p in sourceChunkBoxInDestLevel and (blocksToCopy is None or mask[ int(p[0] - sourceChunkBoxInDestLevel.minx), int(p[2] - sourceChunkBoxInDestLevel.minz), int(p[1] - sourceChunkBoxInDestLevel.miny), ]) if entities: destChunk.removeEntities(copy) ents = sourceChunk.getEntitiesInBox(destChunkBoxInSourceLevel) e += len(ents) for entityTag in ents: eTag = Entity.copyWithOffset(entityTag, copyOffset, regenerateUUID) destLevel.addEntity(eTag) destChunk.removeTileEntities(copy) tileEntities = sourceChunk.getTileEntitiesInBox(destChunkBoxInSourceLevel) t += len(tileEntities) for tileEntityTag in tileEntities: eTag = TileEntity.copyWithOffset(tileEntityTag, copyOffset, staticCommands, moveSpawnerPos, first, cancelCommandBlockOffset) destLevel.addTileEntity(eTag) destChunk.removeTileTicks(copy) tileTicksList = sourceChunk.getTileTicksInBox(destChunkBoxInSourceLevel) tt += len(tileTicksList) for tileTick in tileTicksList: eTag = deepcopy(tileTick) eTag['x'].value = tileTick['x'].value + copyOffset[0] eTag['y'].value = tileTick['y'].value + copyOffset[1] eTag['z'].value = tileTick['z'].value + copyOffset[2] destLevel.addTileTick(eTag) if biomes and hasattr(destChunk, 'Biomes') and hasattr(sourceChunk, 'Biomes'): destChunk.Biomes[destSlices[:2]] = sourceChunk.Biomes[sourceSlices[:2]] destChunk.chunkChanged() log.info("Duration: {0}".format(datetime.now() - startTime)) log.info("Copied {0} entities and {1} tile entities and {2} tile ticks".format(e, t, tt))
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.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) self.BlockLight = self.Data & 0xf self.Data >>= 4 self.Spawn = [mapTag[Spawn][i].value for i in range(3)] if "Entities" not in root_tag: root_tag["Entities"] = nbt.TAG_List() self.Entities = root_tag["Entities"] # xxx fixup Motion and Pos to match infdev format def numbersToDoubles(ent): for attr in "Motion", "Pos": if attr in ent: ent[attr] = nbt.TAG_List([nbt.TAG_Double(t.value) for t in ent[attr]]) for ent in self.Entities: numbersToDoubles(ent) if "TileEntities" not in root_tag: root_tag["TileEntities"] = nbt.TAG_List() self.TileEntities = root_tag["TileEntities"] # xxx fixup TileEntities positions to match infdev format for te in self.TileEntities: pos = te["Pos"].value (x, y, z) = self.decodePos(pos) TileEntity.setpos(te, (x, y, z)) localPlayerList = [tag for tag in root_tag["Entities"] if tag['id'].value == 'LocalPlayer'] if len(localPlayerList) == 0: # omen doesn't make a player entity playerTag = nbt.TAG_Compound() playerTag['id'] = nbt.TAG_String('LocalPlayer') playerTag['Pos'] = nbt.TAG_List([nbt.TAG_Float(0.), nbt.TAG_Float(64.), nbt.TAG_Float(0.)]) playerTag['Rotation'] = nbt.TAG_List([nbt.TAG_Float(0.), nbt.TAG_Float(45.)]) self.LocalPlayer = playerTag else: self.LocalPlayer = localPlayerList[0] else: log.info(u"Creating new Indev levels is not yet implemented.!") raise ValueError("Can't do that yet")
def fillBlocksIter(level, box, blockInfo, blocksToReplace=(), noData=False): if box is None: chunkIterator = level.getAllChunkSlices() box = level.bounds else: chunkIterator = level.getChunkSlices(box) log.info("Replacing {0} with {1}".format(blocksToReplace, blockInfo)) changesLighting = True blocktable = None if len(blocksToReplace): blocktable = blockReplaceTable(blocksToReplace) newAbsorption = level.materials.lightAbsorption[blockInfo.ID] oldAbsorptions = [level.materials.lightAbsorption[b.ID] for b in blocksToReplace] changesLighting = False for a in oldAbsorptions: if a != newAbsorption: changesLighting = True newEmission = level.materials.lightEmission[blockInfo.ID] oldEmissions = [level.materials.lightEmission[b.ID] for b in blocksToReplace] for a in oldEmissions: if a != newEmission: changesLighting = True tileEntity = None if blockInfo.stringID in TileEntity.stringNames.keys(): split_ver = level.gameVersion.split('.') if 'Unknown' not in split_ver and "PE" not in split_ver and int(split_ver[0]) >= 1 and int(split_ver[1]) >= 11: tileEntity = "minecraft:{}".format(blockInfo.stringID) else: tileEntity = TileEntity.stringNames[blockInfo.stringID] blocksIdToReplace = [block.ID for block in blocksToReplace] blocksList = [] append = blocksList.append defsIds = level.defsIds if tileEntity and box is not None: for (boxX, boxY, boxZ) in box.positions: if blocktable is None or level.blockAt(boxX, boxY, boxZ) in blocksIdToReplace: tileEntityObject = TileEntity.Create(tileEntity, defsIds=defsIds) TileEntity.setpos(tileEntityObject, (boxX, boxY, boxZ)) append(tileEntityObject) i = 0 skipped = 0 replaced = 0 for (chunk, slices, point) in chunkIterator: i += 1 if i % 100 == 0: log.info(u"Chunk {0}...".format(i)) yield i, box.chunkCount blocks = chunk.Blocks[slices] data = chunk.Data[slices] mask = slice(None) needsLighting = changesLighting if blocktable is not None: mask = blocktable[blocks, data] blockCount = mask.sum() replaced += blockCount # don't waste time relighting and copying if the mask is empty if blockCount: blocks[:][mask] = blockInfo.ID if not noData: data[mask] = blockInfo.blockData else: skipped += 1 needsLighting = False def include(tileEntity): p = TileEntity.pos(tileEntity) x, y, z = map(lambda a, b, c: (a - b) - c, p, point, box.origin) return not ((p in box) and mask[x, z, y]) chunk.TileEntities[:] = filter(include, chunk.TileEntities) else: blocks[:] = blockInfo.ID if not noData: data[:] = blockInfo.blockData chunk.removeTileEntitiesInBox(box) chunkBounds = chunk.bounds smallBoxSize = (1, 1, 1) tileEntitiesToEdit = [t for t in blocksList if chunkBounds.intersect(BoundingBox(TileEntity.pos(t), smallBoxSize)).volume > 0] for tileEntityObject in tileEntitiesToEdit: chunk.addTileEntity(tileEntityObject) blocksList.remove(tileEntityObject) chunk.chunkChanged(needsLighting) if len(blocksToReplace): log.info(u"Replace: Skipped {0} chunks, replaced {1} blocks".format(skipped, replaced))
def include(tileEntity): p = TileEntity.pos(tileEntity) x, y, z = map(lambda a, b, c: (a - b) - c, p, point, box.origin) return not ((p in box) and mask[x, z, y])
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.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) 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: root_tag[Entities] = nbt.TAG_List() self.Entities = root_tag[Entities] # xxx fixup Motion and Pos to match infdev format def numbersToDoubles(ent): for attr in "Motion", "Pos": if attr in ent: ent[attr] = nbt.TAG_List( [nbt.TAG_Double(t.value) for t in ent[attr]]) for ent in self.Entities: numbersToDoubles(ent) if not TileEntities in root_tag: root_tag[TileEntities] = nbt.TAG_List() self.TileEntities = root_tag[TileEntities] # xxx fixup TileEntities positions to match infdev format for te in self.TileEntities: pos = te["Pos"].value (x, y, z) = self.decodePos(pos) TileEntity.setpos(te, (x, y, z)) if len( filter(lambda x: x['id'].value == 'LocalPlayer', root_tag[Entities]) ) == 0: # omen doesn't make a player entity p = nbt.TAG_Compound() p['id'] = nbt.TAG_String('LocalPlayer') p['Pos'] = nbt.TAG_List( [nbt.TAG_Float(0.), nbt.TAG_Float(64.), nbt.TAG_Float(0.)]) p['Rotation'] = nbt.TAG_List( [nbt.TAG_Float(0.), nbt.TAG_Float(45.)]) root_tag[Entities].append(p) # self.saveInPlace() else: info(u"Creating new Indev levels is not yet implemented.!") raise ValueError("Can't do that yet")
def copyBlocksFromIter(destLevel, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True, create=False, biomes=False, tileTicks=True, staticCommands=False, moveSpawnerPos=False, regenerateUUID=False, first=False): """ copy blocks between two infinite levels by looping through the destination's chunks. make a sub-box of the source level for each chunk and copy block and entities in the sub box to the dest chunk.""" (lx, ly, lz) = sourceBox.size sourceBox, destinationPoint = adjustCopyParameters(destLevel, sourceLevel, sourceBox, destinationPoint) # needs work xxx log.info(u"Copying {0} blocks from {1} to {2}".format( ly * lz * lx, sourceBox, destinationPoint)) startTime = datetime.now() destBox = BoundingBox(destinationPoint, sourceBox.size) chunkCount = destBox.chunkCount i = 0 e = 0 t = 0 tt = 0 sourceMask = sourceMaskFunc(blocksToCopy) copyOffset = [d - s for s, d in zip(sourceBox.origin, destinationPoint)] # Visit each chunk in the destination area. # Get the region of the source area corresponding to that chunk # Visit each chunk of the region of the source area # Get the slices of the destination chunk # Get the slices of the source chunk # Copy blocks and data for destCpos in destBox.chunkPositions: cx, cz = destCpos destChunkBox = BoundingBox( (cx << 4, 0, cz << 4), (16, destLevel.Height, 16)).intersect(destBox) destChunkBoxInSourceLevel = BoundingBox( [d - o for o, d in zip(copyOffset, destChunkBox.origin)], destChunkBox.size) if not destLevel.containsChunk(*destCpos): if create and any( sourceLevel.containsChunk(*c) for c in destChunkBoxInSourceLevel.chunkPositions): # Only create chunks in the destination level if the source level has chunks covering them. destLevel.createChunk(*destCpos) else: continue destChunk = destLevel.getChunk(*destCpos) i += 1 yield (i, chunkCount) if i % 100 == 0: log.info("Chunk {0}...".format(i)) for srcCpos in destChunkBoxInSourceLevel.chunkPositions: if not sourceLevel.containsChunk(*srcCpos): continue sourceChunk = sourceLevel.getChunk(*srcCpos) sourceChunkBox, sourceSlices = sourceChunk.getChunkSlicesForBox( destChunkBoxInSourceLevel) if sourceChunkBox.volume == 0: continue sourceChunkBoxInDestLevel = BoundingBox( [d + o for o, d in zip(copyOffset, sourceChunkBox.origin)], sourceChunkBox.size) _, destSlices = destChunk.getChunkSlicesForBox( sourceChunkBoxInDestLevel) sourceBlocks = sourceChunk.Blocks[sourceSlices] sourceData = sourceChunk.Data[sourceSlices] mask = sourceMask(sourceBlocks) convertedSourceBlocks, convertedSourceData = convertBlocks( destLevel, sourceLevel, sourceBlocks, sourceData) destChunk.Blocks[destSlices][mask] = convertedSourceBlocks[mask] if convertedSourceData is not None: destChunk.Data[destSlices][mask] = convertedSourceData[mask] def copy(p): return p in sourceChunkBoxInDestLevel and ( blocksToCopy is None or mask[p[0] - sourceChunkBoxInDestLevel.minx, p[2] - sourceChunkBoxInDestLevel.minz, p[1] - sourceChunkBoxInDestLevel.miny, ]) if entities: destChunk.removeEntities(copy) ents = sourceChunk.getEntitiesInBox(destChunkBoxInSourceLevel) e += len(ents) for entityTag in ents: eTag = Entity.copyWithOffset(entityTag, copyOffset, regenerateUUID) destLevel.addEntity(eTag) destChunk.removeTileEntities(copy) tileEntities = sourceChunk.getTileEntitiesInBox( destChunkBoxInSourceLevel) t += len(tileEntities) for tileEntityTag in tileEntities: eTag = TileEntity.copyWithOffset(tileEntityTag, copyOffset, staticCommands, moveSpawnerPos, first) destLevel.addTileEntity(eTag) destChunk.removeTileTicks(copy) tileTicksList = sourceChunk.getTileTicksInBox( destChunkBoxInSourceLevel) tt += len(tileTicksList) for tileTick in tileTicksList: eTag = deepcopy(tileTick) eTag['x'].value = tileTick['x'].value + copyOffset[0] eTag['y'].value = tileTick['y'].value + copyOffset[1] eTag['z'].value = tileTick['z'].value + copyOffset[2] destLevel.addTileTick(eTag) if biomes and hasattr(destChunk, 'Biomes') and hasattr( sourceChunk, 'Biomes'): destChunk.Biomes[destSlices[:2]] = sourceChunk.Biomes[ sourceSlices[:2]] destChunk.chunkChanged() log.info("Duration: {0}".format(datetime.now() - startTime)) log.info( "Copied {0} entities and {1} tile entities and {2} tile ticks".format( e, t, tt))
def fillBlocksIter(level, box, blockInfo, blocksToReplace=(), noData=False): if box is None: chunkIterator = level.getAllChunkSlices() box = level.bounds else: chunkIterator = level.getChunkSlices(box) log.info("Replacing {0} with {1}".format(blocksToReplace, blockInfo)) changesLighting = True blocktable = None if len(blocksToReplace): blocktable = blockReplaceTable(blocksToReplace) newAbsorption = level.materials.lightAbsorption[blockInfo.ID] oldAbsorptions = [ level.materials.lightAbsorption[b.ID] for b in blocksToReplace ] changesLighting = False for a in oldAbsorptions: if a != newAbsorption: changesLighting = True newEmission = level.materials.lightEmission[blockInfo.ID] oldEmissions = [ level.materials.lightEmission[b.ID] for b in blocksToReplace ] for a in oldEmissions: if a != newEmission: changesLighting = True tileEntity = None if blockInfo.stringID in TileEntity.stringNames.keys(): split_ver = level.gameVersion.split('.') if 'Unknown' not in split_ver and int(split_ver[0]) >= 1 and int( split_ver[1]) >= 11: tileEntity = "minecraft:{}".format(blockInfo.stringID) else: tileEntity = TileEntity.stringNames[blockInfo.stringID] blocksIdToReplace = [block.ID for block in blocksToReplace] blocksList = [] append = blocksList.append defsIds = level.defsIds if tileEntity and box is not None: for (boxX, boxY, boxZ) in box.positions: if blocktable is None or level.blockAt(boxX, boxY, boxZ) in blocksIdToReplace: tileEntityObject = TileEntity.Create(tileEntity, defsIds=defsIds) TileEntity.setpos(tileEntityObject, (boxX, boxY, boxZ)) append(tileEntityObject) i = 0 skipped = 0 replaced = 0 for (chunk, slices, point) in chunkIterator: i += 1 if i % 100 == 0: log.info(u"Chunk {0}...".format(i)) yield i, box.chunkCount blocks = chunk.Blocks[slices] data = chunk.Data[slices] mask = slice(None) needsLighting = changesLighting if blocktable is not None: mask = blocktable[blocks, data] blockCount = mask.sum() replaced += blockCount # don't waste time relighting and copying if the mask is empty if blockCount: blocks[:][mask] = blockInfo.ID if not noData: data[mask] = blockInfo.blockData else: skipped += 1 needsLighting = False def include(tileEntity): p = TileEntity.pos(tileEntity) x, y, z = map(lambda a, b, c: (a - b) - c, p, point, box.origin) return not ((p in box) and mask[x, z, y]) chunk.TileEntities[:] = filter(include, chunk.TileEntities) else: blocks[:] = blockInfo.ID if not noData: data[:] = blockInfo.blockData chunk.removeTileEntitiesInBox(box) chunkBounds = chunk.bounds smallBoxSize = (1, 1, 1) tileEntitiesToEdit = [ t for t in blocksList if chunkBounds.intersect( BoundingBox(TileEntity.pos(t), smallBoxSize)).volume > 0 ] for tileEntityObject in tileEntitiesToEdit: chunk.addTileEntity(tileEntityObject) blocksList.remove(tileEntityObject) chunk.chunkChanged(needsLighting) if len(blocksToReplace): log.info(u"Replace: Skipped {0} chunks, replaced {1} blocks".format( skipped, replaced))
def getTileEntitiesInBox(self, box): """Returns a list of references to tile entities in this chunk, whose positions are within box""" return [ent for ent in self.TileEntities if TileEntity.pos(ent) in box]
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.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) 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: root_tag[Entities] = nbt.TAG_List() self.Entities = root_tag[Entities] # xxx fixup Motion and Pos to match infdev format def numbersToDoubles(ent): for attr in "Motion", "Pos": if attr in ent: ent[attr] = nbt.TAG_List([nbt.TAG_Double(t.value) for t in ent[attr]]) for ent in self.Entities: numbersToDoubles(ent) if not TileEntities in root_tag: root_tag[TileEntities] = nbt.TAG_List() self.TileEntities = root_tag[TileEntities] # xxx fixup TileEntities positions to match infdev format for te in self.TileEntities: pos = te["Pos"].value (x, y, z) = self.decodePos(pos) TileEntity.setpos(te, (x, y, z)) if len(filter(lambda x: x['id'].value == 'LocalPlayer', root_tag[Entities])) == 0: # omen doesn't make a player entity p = nbt.TAG_Compound() p['id'] = nbt.TAG_String('LocalPlayer') p['Pos'] = nbt.TAG_List([nbt.TAG_Float(0.), nbt.TAG_Float(64.), nbt.TAG_Float(0.)]) p['Rotation'] = nbt.TAG_List([nbt.TAG_Float(0.), nbt.TAG_Float(45.)]) root_tag[Entities].append(p) # self.saveInPlace() else: info(u"Creating new Indev levels is not yet implemented.!") raise ValueError("Can't do that yet")
def fillBlocksIter(level, box, blockInfo, blocksToReplace=(), noData=False): if box is None: chunkIterator = level.getAllChunkSlices() box = level.bounds else: chunkIterator = level.getChunkSlices(box) log.info("Replacing {0} with {1}".format(blocksToReplace, blockInfo)) changesLighting = True blocktable = None if len(blocksToReplace): blocktable = blockReplaceTable(blocksToReplace) newAbsorption = level.materials.lightAbsorption[blockInfo.ID] oldAbsorptions = [level.materials.lightAbsorption[b.ID] for b in blocksToReplace] changesLighting = False for a in oldAbsorptions: if a != newAbsorption: changesLighting = True newEmission = level.materials.lightEmission[blockInfo.ID] oldEmissions = [level.materials.lightEmission[b.ID] for b in blocksToReplace] for a in oldEmissions: if a != newEmission: changesLighting = True tileEntity = None for tileEntityName in TileEntity.otherNames.keys(): if tileEntityName in blockInfo.name: tileEntity = TileEntity.otherNames[tileEntityName] blocksIdToReplace = [block.ID for block in blocksToReplace] blocksList = [] if tileEntity and box is not None: for (boxX, boxY, boxZ) in box.positions: if blocktable is None or level.blockAt(boxX, boxY, boxZ) in blocksIdToReplace: blocksList.append((boxX, boxY, boxZ)) i = 0 skipped = 0 replaced = 0 for (chunk, slices, point) in chunkIterator: i += 1 if i % 100 == 0: log.info(u"Chunk {0}...".format(i)) yield i, box.chunkCount blocks = chunk.Blocks[slices] data = chunk.Data[slices] mask = slice(None) needsLighting = changesLighting if blocktable is not None: mask = blocktable[blocks, data] blockCount = mask.sum() replaced += blockCount # don't waste time relighting and copying if the mask is empty if blockCount: blocks[:][mask] = blockInfo.ID if not noData: data[mask] = blockInfo.blockData else: skipped += 1 needsLighting = False def include(tileEntity): p = TileEntity.pos(tileEntity) x, y, z = map(lambda a, b, c: (a - b) - c, p, point, box.origin) return not ((p in box) and mask[x, z, y]) chunk.TileEntities[:] = filter(include, chunk.TileEntities) else: blocks[:] = blockInfo.ID if not noData: data[:] = blockInfo.blockData chunk.removeTileEntitiesInBox(box) if blocksList: for position in blocksList: tileEntityObject = TileEntity.Create(tileEntity) TileEntity.setpos(tileEntityObject, position) chunk.addTileEntity(tileEntityObject) chunk.chunkChanged(needsLighting) if len(blocksToReplace): log.info(u"Replace: Skipped {0} chunks, replaced {1} blocks".format(skipped, replaced))
def differentPosition(a): return not ((tileEntityTag is a) or TileEntity.pos(a) == TileEntity.pos(tileEntityTag))
def copyBlocksFromIter(destLevel, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True, create=False): """ copy blocks between two infinite levels by looping through the destination's chunks. make a sub-box of the source level for each chunk and copy block and entities in the sub box to the dest chunk.""" (lx, ly, lz) = sourceBox.size sourceBox, destinationPoint = adjustCopyParameters(destLevel, sourceLevel, sourceBox, destinationPoint) # needs work xxx log.info(u"Copying {0} blocks from {1} to {2}".format( ly * lz * lx, sourceBox, destinationPoint)) startTime = datetime.now() destBox = BoundingBox(destinationPoint, sourceBox.size) chunkCount = destBox.chunkCount i = 0 e = 0 t = 0 sourceMask = sourceMaskFunc(blocksToCopy) copyOffset = [d - s for s, d in zip(sourceBox.origin, destinationPoint)] # Visit each chunk in the destination area. # Get the region of the source area corresponding to that chunk # Visit each chunk of the region of the source area # Get the slices of the destination chunk # Get the slices of the source chunk # Copy blocks and data for destCpos in destBox.chunkPositions: cx, cz = destCpos destChunkBox = BoundingBox( (cx << 4, 0, cz << 4), (16, destLevel.Height, 16)).intersect(destBox) destChunkBoxInSourceLevel = BoundingBox( [d - o for o, d in zip(copyOffset, destChunkBox.origin)], destChunkBox.size) if not destLevel.containsChunk(*destCpos): if create and any( sourceLevel.containsChunk(*c) for c in destChunkBoxInSourceLevel.chunkPositions): # Only create chunks in the destination level if the source level has chunks covering them. destLevel.createChunk(*destCpos) else: continue destChunk = destLevel.getChunk(*destCpos) i += 1 yield (i, chunkCount) if i % 100 == 0: log.info("Chunk {0}...".format(i)) for srcCpos in destChunkBoxInSourceLevel.chunkPositions: if not sourceLevel.containsChunk(*srcCpos): continue sourceChunk = sourceLevel.getChunk(*srcCpos) sourceChunkBox, sourceSlices = sourceChunk.getChunkSlicesForBox( destChunkBoxInSourceLevel) sourceChunkBoxInDestLevel = BoundingBox( [d + o for o, d in zip(copyOffset, sourceChunkBox.origin)], sourceChunkBox.size) _, destSlices = destChunk.getChunkSlicesForBox( sourceChunkBoxInDestLevel) sourceBlocks = sourceChunk.Blocks[sourceSlices] sourceData = sourceChunk.Data[sourceSlices] mask = sourceMask(sourceBlocks) convertedSourceBlocks, convertedSourceData = convertBlocks( destLevel, sourceLevel, sourceBlocks, sourceData) destChunk.Blocks[destSlices][mask] = convertedSourceBlocks[mask] if convertedSourceData is not None: destChunk.Data[destSlices][mask] = convertedSourceData[mask] if entities: ents = sourceChunk.getEntitiesInBox(destChunkBoxInSourceLevel) e += len(ents) for entityTag in ents: eTag = Entity.copyWithOffset(entityTag, copyOffset) destLevel.addEntity(eTag) tileEntities = sourceChunk.getTileEntitiesInBox( destChunkBoxInSourceLevel) t += len(tileEntities) for tileEntityTag in tileEntities: eTag = TileEntity.copyWithOffset(tileEntityTag, copyOffset) destLevel.addTileEntity(eTag) destChunk.chunkChanged() log.info("Duration: {0}".format(datetime.now() - startTime)) log.info("Copied {0} entities and {1} tile entities".format(e, t))
def copyBlocksFromIter(destLevel, sourceLevel, sourceBox, destinationPoint, blocksToCopy=None, entities=True, create=False): """ copy blocks between two infinite levels by looping through the destination's chunks. make a sub-box of the source level for each chunk and copy block and entities in the sub box to the dest chunk.""" (lx, ly, lz) = sourceBox.size sourceBox, destinationPoint = adjustCopyParameters(destLevel, sourceLevel, sourceBox, destinationPoint) # needs work xxx log.info(u"Copying {0} blocks from {1} to {2}" .format(ly * lz * lx, sourceBox, destinationPoint)) startTime = datetime.now() destBox = BoundingBox(destinationPoint, sourceBox.size) chunkCount = destBox.chunkCount i = 0 e = 0 t = 0 sourceMask = sourceMaskFunc(blocksToCopy) copyOffset = [d - s for s, d in zip(sourceBox.origin, destinationPoint)] # Visit each chunk in the destination area. # Get the region of the source area corresponding to that chunk # Visit each chunk of the region of the source area # Get the slices of the destination chunk # Get the slices of the source chunk # Copy blocks and data for destCpos in destBox.chunkPositions: cx, cz = destCpos destChunkBox = BoundingBox((cx << 4, 0, cz << 4), (16, destLevel.Height, 16)).intersect(destBox) destChunkBoxInSourceLevel = BoundingBox([d - o for o, d in zip(copyOffset, destChunkBox.origin)], destChunkBox.size) if not destLevel.containsChunk(*destCpos): if create and any(sourceLevel.containsChunk(*c) for c in destChunkBoxInSourceLevel.chunkPositions): # Only create chunks in the destination level if the source level has chunks covering them. destLevel.createChunk(*destCpos) else: continue destChunk = destLevel.getChunk(*destCpos) i += 1 yield (i, chunkCount) if i % 100 == 0: log.info("Chunk {0}...".format(i)) for srcCpos in destChunkBoxInSourceLevel.chunkPositions: if not sourceLevel.containsChunk(*srcCpos): continue sourceChunk = sourceLevel.getChunk(*srcCpos) sourceChunkBox, sourceSlices = sourceChunk.getChunkSlicesForBox(destChunkBoxInSourceLevel) if sourceChunkBox.volume == 0: continue sourceChunkBoxInDestLevel = BoundingBox([d + o for o, d in zip(copyOffset, sourceChunkBox.origin)], sourceChunkBox.size) _, destSlices = destChunk.getChunkSlicesForBox(sourceChunkBoxInDestLevel) sourceBlocks = sourceChunk.Blocks[sourceSlices] sourceData = sourceChunk.Data[sourceSlices] mask = sourceMask(sourceBlocks) convertedSourceBlocks, convertedSourceData = convertBlocks(destLevel, sourceLevel, sourceBlocks, sourceData) destChunk.Blocks[destSlices][mask] = convertedSourceBlocks[mask] if convertedSourceData is not None: destChunk.Data[destSlices][mask] = convertedSourceData[mask] if entities: ents = sourceChunk.getEntitiesInBox(destChunkBoxInSourceLevel) e += len(ents) for entityTag in ents: eTag = Entity.copyWithOffset(entityTag, copyOffset) destLevel.addEntity(eTag) tileEntities = sourceChunk.getTileEntitiesInBox(destChunkBoxInSourceLevel) t += len(tileEntities) for tileEntityTag in tileEntities: eTag = TileEntity.copyWithOffset(tileEntityTag, copyOffset) destLevel.addTileEntity(eTag) destChunk.chunkChanged() log.info("Duration: {0}".format(datetime.now() - startTime)) log.info("Copied {0} entities and {1} tile entities".format(e, t))