forked from mathuin/TopoMC
/
tile.py
executable file
·135 lines (113 loc) · 5.64 KB
/
tile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python
# tile class
from __future__ import division
import yaml
from region import Region
import os
from itertools import product
from utils import cleanmkdir, setspawnandsave
from osgeo import gdal
from osgeo.gdalconst import GA_ReadOnly
from pymclevel import mclevel, box
from terrain import Terrain
from tree import Tree, treeObjs
from ore import Ore
class Tile:
"""Tiles are the base render object. or something."""
def __init__(self, region, tilex, tiley):
"""Create a tile based on the region and the tile's coordinates."""
# NB: smart people check that files have been gotten.
# today we assume that's already been done.
# snag stuff from the region first
self.name = region.name
self.size = region.tilesize
self.mapname = region.mapname
self.tilex = int(tilex)
self.tiley = int(tiley)
self.tiles = region.tiles
self.doOre = region.doOre
self.doSchematics = region.doSchematics
if (self.tilex < self.tiles['xmin']) or (self.tilex >= self.tiles['xmax']):
raise AttributeError, "tilex (%d) must be between %d and %d" % (self.tilex, self.tiles['xmin'], self.tiles['xmax'])
if (self.tiley < self.tiles['ymin']) or (self.tiley >= self.tiles['ymax']):
raise AttributeError, "tiley (%d) must be between %d and %d" % (self.tiley, self.tiles['ymin'], self.tiles['ymax'])
# create the tile directory if necessary
self.tiledir = os.path.join(region.regiondir, 'Tiles', '%dx%d' % (self.tilex, self.tiley))
self.skip = False
if os.path.isfile(os.path.join(self.tiledir, 'Tile.yaml')):
self.skip = True
else:
cleanmkdir(self.tiledir)
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