forked from mcedit/pymclevel
-
Notifications
You must be signed in to change notification settings - Fork 1
/
block_fill.py
105 lines (81 loc) · 3.38 KB
/
block_fill.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
import logging
import materials
log = logging.getLogger(__name__)
import numpy
from mclevelbase import exhaust
import blockrotation
from entity import TileEntity
def blockReplaceTable(blocksToReplace):
blocktable = numpy.zeros((materials.id_limit, 16), dtype='bool')
for b in blocksToReplace:
if b.hasVariants:
blocktable[b.ID, b.blockData] = True
else:
blocktable[b.ID] = True
return blocktable
def fillBlocks(level, box, blockInfo, blocksToReplace=()):
return exhaust(level.fillBlocksIter(box, blockInfo, blocksToReplace))
def fillBlocksIter(level, box, blockInfo, blocksToReplace=()):
if box is None:
chunkIterator = level.getAllChunkSlices()
box = level.bounds
else:
chunkIterator = level.getChunkSlices(box)
# shouldRetainData = (not blockInfo.hasVariants and not any([b.hasVariants for b in blocksToReplace]))
# if shouldRetainData:
# log.info( "Preserving data bytes" )
shouldRetainData = False # xxx old behavior overwrote blockdata with 0 when e.g. replacing water with lava
log.info("Replacing {0} with {1}".format(blocksToReplace, blockInfo))
changesLighting = True
blocktable = None
if len(blocksToReplace):
blocktable = blockReplaceTable(blocksToReplace)
shouldRetainData = all([blockrotation.SameRotationType(blockInfo, b) for b in 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
i = 0
skipped = 0
replaced = 0
for (chunk, slices, point) in chunkIterator:
i += 1
if i % 100 == 0:
log.info("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 shouldRetainData:
data[mask] = blockInfo.blockData
else:
skipped += 1
needsLighting = False
def include(tileEntity):
p = TileEntity.pos(tileEntity)
x, y, z = list(map(lambda a, b, c: (a - b) - c, p, point, box.origin))
return not ((p in box) and mask[x, z, y])
chunk.TileEntities[:] = list(filter(include, chunk.TileEntities))
else:
blocks[:] = blockInfo.ID
if not shouldRetainData:
data[:] = blockInfo.blockData
chunk.removeTileEntitiesInBox(box)
chunk.chunkChanged(needsLighting)
if len(blocksToReplace):
log.info("Replace: Skipped {0} chunks, replaced {1} blocks".format(skipped, replaced))