def main(): """Builds a region.""" # example: # ./BuildRegion.py --name BlockIsland # parse options and get results parser = argparse.ArgumentParser(description='Builds Minecraft worlds from regions.') parser.add_argument('--name', required=True, type=str, help='name of the region to be built') parser.add_argument('--debug', action='store_true', help='enable debug output') parser.add_argument('--single', action='store_true', help='enable single-threaded mode for debugging or profiling') args = parser.parse_args() # enable debug if (args.debug): print "Do something!" # build the region print "Building region %s..." % args.name yamlfile = file(os.path.join('Regions', args.name, 'Region.yaml')) myRegion = yaml.load(yamlfile) yamlfile.close() # exit if map does not exist if not os.path.exists(myRegion.mapname): raise IOError, "no map file exists" # tree and ore variables treeobjs = dict([(tree.name, tree) for tree in treeObjs]) trees = dict([(name, list()) for name in treeobjs]) oreobjs = dict([(ore.name, ore) for ore in oreObjs]) ores = dict([(name, list()) for name in oreobjs]) # generate overall world worlddir = os.path.join('Worlds', args.name) world = mclevel.MCInfdevOldLevel(worlddir, create=True) peak = [0, 0, 0] # generate individual tiles tilexrange = xrange(myRegion.tiles['xmin'], myRegion.tiles['xmax']) tileyrange = xrange(myRegion.tiles['ymin'], myRegion.tiles['ymax']) name = myRegion.name tiles = [(name, x, y) for x, y in product(tilexrange, tileyrange)] if args.single: # single process version - works for tile in tiles: buildtile(tile) else: # multi-process ... let's see... pool = Pool() pool.map(buildtile, tiles) pool.close() pool.join() # merge individual worlds into it print "Merging %d tiles into one world..." % len(tiles) for tile in tiles: (name, x, y) = tile tiledir = os.path.join('Regions', name, 'Tiles', '%dx%d' % (x, y)) tilefile = file(os.path.join(tiledir, 'Tile.yaml')) newtile = yaml.load(tilefile) tilefile.close() if (newtile.peak[1] > peak[1]): peak = newtile.peak for treetype in newtile.trees: trees.setdefault(treetype, []).extend(newtile.trees[treetype]) if myRegion.doOre: for oretype in newtile.ores: ores.setdefault(oretype, []).extend(newtile.ores[oretype]) tileworld = mclevel.MCInfdevOldLevel(tiledir, create=False) world.copyBlocksFrom(tileworld, tileworld.bounds, tileworld.bounds.origin) tileworld = False # plant trees in our world print "Planting %d trees at the region level..." % sum([len(trees[treetype]) for treetype in trees]) Tree.placetreesinregion(trees, treeobjs, world) # deposit ores in our world if myRegion.doOre: print "Depositing %d ores at the region level..." % sum([len(ores[oretype]) for oretype in ores]) Ore.placeoreinregion(ores, oreobjs, world) # replace all 'end stone' with stone print "Replacing all 'end stone' with stone..." EndStoneID = world.materials["End Stone"].ID StoneID = world.materials["Stone"].ID for xpos, zpos in world.allChunks: chunk = world.getChunk(xpos, zpos) chunk.Blocks[chunk.Blocks == EndStoneID] = StoneID # tie up loose ends setspawnandsave(world, peak)
def __call__(self): """Actually build the Minecraft world that corresponds to a tile.""" if self.skip == True: self.log.log_info("Skipping extant tile %dx%d" % (self.tilex, self.tiley)) self.world = mclevel.MCInfdevOldLevel(self.tiledir) peak = self.world.playerSpawnPosition() self.peak = peak[1] - 2 del self.world return self.peak # calculate offsets ox = (self.tilex-self.tiles['xmin'])*self.size oy = (self.tiley-self.tiles['ymin'])*self.size sx = self.size sy = self.size # load arrays from map file mapds = gdal.Open(self.mapname, GA_ReadOnly) lcarray = mapds.GetRasterBand(Region.rasters['landcover']).ReadAsArray(ox, oy, sx, sy) elarray = mapds.GetRasterBand(Region.rasters['elevation']).ReadAsArray(ox, oy, sx, sy) bathyarray = mapds.GetRasterBand(Region.rasters['bathy']).ReadAsArray(ox, oy, sx, sy) crustarray = mapds.GetRasterBand(Region.rasters['crust']).ReadAsArray(ox, oy, sx, sy) orthor = mapds.GetRasterBand(Region.rasters['orthor']).ReadAsArray(ox, oy, sx, sy) orthog = mapds.GetRasterBand(Region.rasters['orthog']).ReadAsArray(ox, oy, sx, sy) orthob = mapds.GetRasterBand(Region.rasters['orthob']).ReadAsArray(ox, oy, sx, sy) orthoir = mapds.GetRasterBand(Region.rasters['orthoir']).ReadAsArray(ox, oy, sx, sy) # calculate Minecraft corners self.mcoffsetx = self.tilex * self.size self.mcoffsetz = self.tiley * self.size # build a Minecraft world via pymclevel from blocks and data self.world = mclevel.MCInfdevOldLevel(self.tiledir, create=True) tilebox = box.BoundingBox((self.mcoffsetx, 0, self.mcoffsetz), (self.size, self.world.Height, self.size)) self.world.createChunksInBox(tilebox) # do the terrain thing (no trees, ore or building) self.peak = [0, 0, 0] treeobjs = dict([(tree.name, tree) for tree in treeObjs]) self.trees = dict([(name, list()) for name in treeobjs]) for myx, myz in product(xrange(self.size), xrange(self.size)): mcx = int(self.mcoffsetx+myx) mcz = int(self.mcoffsetz+myz) mcy = int(elarray[myz, myx]) lcval = int(lcarray[myz, myx]) bathyval = int(bathyarray[myz, myx]) crustval = int(crustarray[myz, myx]) rval = int(orthor[myz, myx]) gval = int(orthog[myz, myx]) bval = int(orthob[myz, myx]) irval = int(orthoir[myz, myx]) if mcy > self.peak[1]: self.peak = [mcx, mcy, mcz] (blocks, datas, tree) = Terrain.place(mcx, mcy, mcz, lcval, crustval, bathyval, self.doSchematics, rval, gval, bval, irval) [ self.world.setBlockAt(mcx, y, mcz, block) for (y, block) in blocks if block != 0 ] [ self.world.setBlockDataAt(mcx, y, mcz, data) for (y, data) in datas if data != 0 ] # if trees are placed, elevation cannot be changed if tree: Tree.placetreeintile(self, tree, mcx, mcy, mcz) # now that terrain and trees are done, place ore if self.doOre: Ore.placeoreintile(self) # replace all 'end stone' with stone EndStoneID = self.world.materials["End Stone"].ID StoneID = self.world.materials["Stone"].ID for xpos, zpos in self.world.allChunks: chunk = self.world.getChunk(xpos, zpos) chunk.Blocks[chunk.Blocks == EndStoneID] = StoneID # stick the player and the spawn at the peak setspawnandsave(self.world, self.peak) # write Tile.yaml with relevant data (peak at least) # NB: world is not dump-friendly. :-) del self.world stream = file(os.path.join(self.tiledir, 'Tile.yaml'), 'w') yaml.dump(self, stream) stream.close() # return peak return self.peak
def main(): """Builds a region.""" # example: # ./BuildRegion.py --name BlockIsland # parse options and get results parser = argparse.ArgumentParser( description='Builds Minecraft worlds from regions.') parser.add_argument('--name', required=True, type=str, help='name of the region to be built') parser.add_argument('--debug', action='store_true', help='enable debug output') parser.add_argument( '--single', action='store_true', help='enable single-threaded mode for debugging or profiling') args = parser.parse_args() # enable debug if (args.debug): print "Do something!" # build the region print "Building region %s..." % args.name yamlfile = file(os.path.join('regions', args.name, 'Region.yaml')) myRegion = yaml.load(yamlfile) yamlfile.close() # exit if map does not exist if not os.path.exists(myRegion.mapfile): raise IOError('no map file exists') # tree and ore variables treeobjs = dict([(tree.name, tree) for tree in treeObjs]) trees = dict([(name, list()) for name in treeobjs]) oreobjs = dict([(ore.name, ore) for ore in oreObjs]) ores = dict([(name, list()) for name in oreobjs]) # generate overall world worlddir = os.path.join('worlds', args.name) world = mclevel.MCInfdevOldLevel(worlddir, create=True) peak = [0, 0, 0] # generate individual tiles tilexrange = xrange(myRegion.tiles['xmin'], myRegion.tiles['xmax']) tileyrange = xrange(myRegion.tiles['ymin'], myRegion.tiles['ymax']) name = myRegion.name tiles = [(name, x, y) for x, y in product(tilexrange, tileyrange)] if args.single: # single process version - works for tile in tiles: buildtile(tile) else: # multi-process ... let's see... pool = Pool() pool.map(buildtile, tiles) pool.close() pool.join() # merge individual worlds into it print "Merging %d tiles into one world..." % len(tiles) for tile in tiles: (name, x, y) = tile tiledir = os.path.join('regions', name, 'Tiles', '%dx%d' % (x, y)) tilefile = file(os.path.join(tiledir, 'Tile.yaml')) newtile = yaml.load(tilefile) tilefile.close() if (newtile.peak[1] > peak[1]): peak = newtile.peak for treetype in newtile.trees: trees.setdefault(treetype, []).extend(newtile.trees[treetype]) if myRegion.doOre: for oretype in newtile.ores: ores.setdefault(oretype, []).extend(newtile.ores[oretype]) tileworld = mclevel.MCInfdevOldLevel(tiledir, create=False) world.copyBlocksFrom(tileworld, tileworld.bounds, tileworld.bounds.origin) tileworld = False # plant trees in our world print "Planting %d trees at the region level..." % sum( [len(trees[treetype]) for treetype in trees]) Tree.placetreesinregion(trees, treeobjs, world) # deposit ores in our world if myRegion.doOre: print "Depositing %d ores at the region level..." % sum( [len(ores[oretype]) for oretype in ores]) Ore.placeoreinregion(ores, oreobjs, world) # replace all 'end stone' with stone print "Replacing all 'end stone' with stone..." EndStoneID = world.materials["End Stone"].ID StoneID = world.materials["Stone"].ID for xpos, zpos in world.allChunks: chunk = world.getChunk(xpos, zpos) chunk.Blocks[chunk.Blocks == EndStoneID] = StoneID # tie up loose ends setspawnandsave(world, peak)
def __call__(self): """Actually build the Minecraft world that corresponds to a tile.""" # calculate offsets ox = (self.tilex - self.tiles['xmin']) * self.size oy = (self.tiley - self.tiles['ymin']) * self.size sx = self.size sy = self.size # load arrays from map file mapds = gdal.Open(self.mapfile, GA_ReadOnly) lcarray = mapds.GetRasterBand(Region.rasters['landcover']).ReadAsArray( ox, oy, sx, sy) elarray = mapds.GetRasterBand(Region.rasters['elevation']).ReadAsArray( ox, oy, sx, sy) bathyarray = mapds.GetRasterBand(Region.rasters['bathy']).ReadAsArray( ox, oy, sx, sy) crustarray = mapds.GetRasterBand(Region.rasters['crust']).ReadAsArray( ox, oy, sx, sy) # calculate Minecraft corners self.mcoffsetx = self.tilex * self.size self.mcoffsetz = self.tiley * self.size # build a Minecraft world via pymclevel from blocks and data self.world = mclevel.MCInfdevOldLevel(self.tiledir, create=True) tilebox = box.BoundingBox((self.mcoffsetx, 0, self.mcoffsetz), (self.size, self.world.Height, self.size)) self.world.createChunksInBox(tilebox) # do the terrain thing (no trees, ore or building) self.peak = [0, 0, 0] treeobjs = dict([(tree.name, tree) for tree in treeObjs]) self.trees = dict([(name, list()) for name in treeobjs]) for myx, myz in product(xrange(self.size), xrange(self.size)): mcx = int(self.mcoffsetx + myx) mcz = int(self.mcoffsetz + myz) mcy = int(elarray[myz, myx]) lcval = int(lcarray[myz, myx]) bathyval = int(bathyarray[myz, myx]) crustval = int(crustarray[myz, myx]) if mcy > self.peak[1]: self.peak = [mcx, mcy, mcz] (blocks, datas, tree) = Terrain.place(mcx, mcy, mcz, lcval, crustval, bathyval, self.doSchematics) [ self.world.setBlockAt(mcx, y, mcz, block) for (y, block) in blocks if block != 0 ] [ self.world.setBlockDataAt(mcx, y, mcz, data) for (y, data) in datas if data != 0 ] # if trees are placed, elevation cannot be changed if tree: Tree.placetreeintile(self, tree, mcx, mcy, mcz) # now that terrain and trees are done, place ore if self.doOre: Ore.placeoreintile(self) # stick the player and the spawn at the peak setspawnandsave(self.world, self.peak) # write Tile.yaml with relevant data (peak at least) # NB: world is not dump-friendly. :-) del self.world stream = file(os.path.join(self.tiledir, 'Tile.yaml'), 'w') yaml.dump(self, stream) stream.close() # return peak return self.peak
def main(): """Builds a region.""" # example: # ./BuildRegion.py --name BlockIsland # parse options and get results parser = argparse.ArgumentParser(description='Builds Minecraft worlds from regions.') parser.add_argument('--name', required=True, type=str, \ help='name of the region to be built') parser.add_argument('--single', action='store_true', \ help='enable single-threaded mode for debugging or profiling') parser.add_argument('--safemerge', action='store_true', \ help='use \"safer\" method of merging tiles together') parser.add_argument("-v", "--verbosity", action="count", \ help="increase output verbosity") parser.add_argument("-q", "--quiet", action="store_true", \ help="suppress informational output") args = parser.parse_args() # set up logging log_level = klog_levels.LOG_INFO if args.quiet: log_level = klog_levels.LOG_ERROR if args.verbosity: # v=1 is DEBUG 1, v=2 is DEBUG 2, and so on log_level += args.verbosity log = klogger(log_level) # build the region log.log_info("Building region %s..." % args.name) yamlfile = file(os.path.join('Regions', args.name, 'Region.yaml')) myRegion = yaml.load(yamlfile) yamlfile.close() # exit if map does not exist if not os.path.exists(myRegion.mapname): log.log_fatal("No map file exists!") # tree and ore variables treeobjs = dict([(tree.name, tree) for tree in treeObjs]) trees = dict([(name, list()) for name in treeobjs]) oreobjs = dict([(ore.name, ore) for ore in oreObjs]) ores = dict([(name, list()) for name in oreobjs]) # generate overall world worlddir = os.path.join('Worlds', args.name) world = mclevel.MCInfdevOldLevel(worlddir, create=True) peak = [0, 0, 0] save(world) world = None # generate individual tiles tilexrange = xrange(myRegion.tiles['xmin'], myRegion.tiles['xmax']) tileyrange = xrange(myRegion.tiles['ymin'], myRegion.tiles['ymax']) name = myRegion.name tiles = [(log, name, x, y) for x, y in product(tilexrange, tileyrange)] if args.single: # single process version log.log_warn("Single-threaded region merge") for tile in tiles: buildtile(tile) else: # multi-process version pool = Pool() rs = pool.map_async(buildtile, tiles) pool.close() while not(rs.ready()): remaining = rs._number_left log.log_info("Waiting for %s buildtile tasks to complete..." % remaining) time.sleep(10) pool.join() # Just as a precaution. # Necessary for tile-welding -> regions cleanmkdir(worlddir) cleanmkdir(os.path.join(worlddir, 'region')) # Generate regions if not(args.safemerge): regionsize = 32 * 16 regionxrange = xrange(int(floor(myRegion.tiles['xmin'] * (myRegion.tilesize / float(regionsize)))), \ int(ceil(myRegion.tiles['xmax'] * (myRegion.tilesize / float(regionsize))))) regionyrange = xrange(int(floor(myRegion.tiles['ymin'] * (myRegion.tilesize / float(regionsize)))), \ int(ceil(myRegion.tiles['ymax'] * (myRegion.tilesize / float(regionsize))))) regions = [(log, name, x, y) for x, y in product(regionxrange, regionyrange)] # merge individual tiles into regions log.log_info("Merging %d tiles into one world..." % len(tiles)) for tile in tiles: (dummy, name, x, y) = tile tiledir = os.path.join('Regions', name, 'Tiles', '%dx%d' % (x, y)) if not(os.path.isfile(os.path.join(tiledir, 'Tile.yaml'))): log.log_fatal("The following tile is missing. Please re-run this script:\n%s" % \ os.path.join(tiledir, 'Tile.yaml')) if args.single: # single process version log.log_warn("Single-threaded region merge") for region in regions: buildregion(region) else: # multi-process version pool = Pool() rs = pool.map_async(buildregion, regions) pool.close() while not(rs.ready()): remaining = rs._number_left log.log_info("Waiting for %s buildregion tasks to complete..." % remaining) time.sleep(10) pool.join() # Just as a precaution. world = mclevel.MCInfdevOldLevel(worlddir, create=True) if not(args.safemerge): mcoffsetx = myRegion.tiles['xmin'] * myRegion.tilesize mcoffsetz = myRegion.tiles['ymin'] * myRegion.tilesize mcsizex = (myRegion.tiles['xmax'] - myRegion.tiles['xmin']) * myRegion.tilesize mcsizez = (myRegion.tiles['ymax'] - myRegion.tiles['ymin']) * myRegion.tilesize tilebox = box.BoundingBox((mcoffsetx, 0, mcoffsetz), (mcsizex, world.Height, mcsizez)) world.createChunksInBox(tilebox) for tile in tiles: (dummy, name, x, y) = tile tiledir = os.path.join('Regions', name, 'Tiles', '%dx%d' % (x, y)) tilefile = file(os.path.join(tiledir, 'Tile.yaml')) newtile = yaml.load(tilefile) tilefile.close() if (newtile.peak[1] > peak[1]): peak = newtile.peak for treetype in newtile.trees: trees.setdefault(treetype, []).extend(newtile.trees[treetype]) if myRegion.doOre: for oretype in newtile.ores: ores.setdefault(oretype, []).extend(newtile.ores[oretype]) if args.safemerge: tileworld = mclevel.MCInfdevOldLevel(tiledir, create=False) world.copyBlocksFrom(tileworld, tileworld.bounds, tileworld.bounds.origin) tileworld = False # plant trees in our world log.log_info("Planting %d trees at the region level..." % \ sum([len(trees[treetype]) for treetype in trees])) Tree.placetreesinregion(trees, treeobjs, world) # deposit ores in our world if myRegion.doOre: log.log_info("Depositing %d ores at the region level..." % \ sum([len(ores[oretype]) for oretype in ores])) Ore.placeoreinregion(ores, oreobjs, world) # tie up loose ends world.setPlayerGameType(1) setspawnandsave(world, peak) oldyamlpath = os.path.join('Regions', args.name, 'Region.yaml') newyamlpath = os.path.join('Worlds', args.name, 'Region.yaml') shutil.copy(oldyamlpath, newyamlpath) shutil.rmtree(os.path.join('Regions', name, 'Tiles'))