expanded block definitions to support blockData for colored wool and varied trees

textures are given as a pair of 0-255 pixel coordinates instead of combining them into one byte. the first coordinate of the pair is left-to-right on the terrain.png

added flat color definitions for low-detail rendering. color codes borrowed from c10t

block defs are now attrs of the MCMaterials objects.

fillBlocks now takes Block objects instead of block ID numbers
This commit is contained in:
David Vierra 2011-03-09 13:05:23 -10:00
parent 00c3514e36
commit 1bf1cfa8b6
3 changed files with 580 additions and 253 deletions

File diff suppressed because it is too large Load Diff

81
mce.py
View File

@ -201,29 +201,23 @@ class mce(object):
return (x,y,z)
def readBlockType(self, command):
def readBlockInfo(self, command):
keyword = command.pop(0)
def blocksMatching(search):
if search in self.level.materials.names:
#exact match
return [search]
return filter(lambda x:search.lower() in x.lower(), self.level.materials.names)
matches = blocksMatching(keyword)
blockType = None
matches = self.level.materials.blocksMatching(keyword)
blockInfo = None
if len(matches):
if len(matches) == 1:
blockType = self.level.materials.materialNamed(matches[0])
blockInfo = matches[0]
#eat up more words that possibly specify a block. stop eating when 0 matching blocks.
while len(command):
newMatches = blocksMatching(keyword + " " + command[0]);
newMatches = self.level.materials.blocksMatching(keyword + " " + command[0]);
if len(newMatches) == 1:
blockType = self.level.materials.materialNamed(newMatches[0])
blockInfo = newMatches[0]
if len(newMatches) > 0:
matches = newMatches
keyword = keyword + " " + command.pop(0)
@ -234,23 +228,28 @@ class mce(object):
else:
try:
blockType = int(keyword);
blockType = blockType & 0xff
except ValueError:
blockType = None;
data = 0
if ":" in keyword:
blockID, data = map(int, keyword.split(":"))
else:
blockID = int(keyword)
blockInfo = self.level.materials.blockWithID(blockID, data)
if blockType is None:
except ValueError:
blockInfo = None;
if blockInfo is None:
print "Ambiguous block specifier: ", keyword
if len(matches):
print "Matches: "
for m in matches:
if m == "Future Block!": continue
print "{0:3}: {1}".format(self.level.materials.materialNamed(m),m)
if m == self.level.materials.defaultName: continue
print "{0:3}:{1:<2} : {2}".format(m.ID, m.blockData, m.name)
else:
print "No blocks matched."
raise BlockMatchError
return blockType
return blockInfo
def readBlocksToCopy(self, command):
blocksToCopy = range(256);
@ -357,17 +356,16 @@ class mce(object):
self.printUsage("fill")
return;
blockType = self.readBlockType(command)
assert blockType >=0 and blockType < 256
blockInfo = self.readBlockInfo(command)
if len(command):
box = self.readBox(command)
else:
box = None
print "Filling with {0}".format(self.level.materials.names[blockType])
print "Filling with {0}".format(blockInfo.name)
self.level.fillBlocks(box, blockType)
self.level.fillBlocks(box, blockInfo)
self.needsSave = True;
@ -387,12 +385,11 @@ class mce(object):
self.printUsage("replace")
return;
blockType = self.readBlockType(command)
assert blockType >=0 and blockType < 256
blockInfo = self.readBlockInfo(command)
if command[0].lower() == "with":
command.pop(0)
newBlockType = self.readBlockType(command)
assert newBlockType >=0 and newBlockType < 256
newBlockInfo = self.readBlockInfo(command)
if len(command):
box = self.readBox(command)
@ -400,10 +397,9 @@ class mce(object):
box = None
print "Replacing {0} with {1}".format(self.level.materials.names[blockType],
self.level.materials.names[newBlockType])
print "Replacing {0} with {1}".format(blockInfo.name, newBlockInfo.name)
self.level.fillBlocks(box, newBlockType, blockData = 0, blocksToReplace = [blockType])
self.level.fillBlocks(box, newBlockInfo, blocksToReplace = [blockInfo])
self.needsSave = True;
print "Done."
@ -807,12 +803,12 @@ class mce(object):
print "Removing grief matter and surface lava above height {0}...".format(box.miny)
self.level.fillBlocks(box,
self.level.materials.materialNamed("Air"),
blocksToReplace=[7,
self.level.materials.materialNamed("Obsidian"),
self.level.materials.materialNamed("Fire"),
self.level.materials.materialNamed("Lava (active)"),
self.level.materials.materialNamed("Lava (still)"),
self.level.materials.Air,
blocksToReplace=[self.level.materials.Bedrock,
self.level.materials.Obsidian,
self.level.materials.Fire,
self.level.materials.LavaActive,
self.level.materials.LavaStill,
]
)
self.needsSave = True;
@ -1110,15 +1106,18 @@ class mce(object):
print "{0:3}: {1}".format(searchNumber, self.level.materials.names[searchNumber])
return
for i in range(len(self.level.materials.names)):
name = self.level.materials.names[i];
if name == "Future Block!": return;
matches = []
for name,b in self.level.materials.blocksByName.iteritems():
if name is self.level.materials.defaultName: return;
if searchName:
if not (searchName.lower() in name.lower()):
#don't print blocks that don't match the given name or number
continue
print "{0:3}: {1}".format(i, name)
matches.append(b)
for b in sorted(matches):
print "{ID:3}:{data:<2} : \"{name}\"".format(ID=b.ID, data=b.blockData, name=b.name)
def printUsage(self, command = ""):
if command.lower() in self.commands:

View File

@ -29,7 +29,7 @@ level = mclevel.fromFile("server_level.dat");
blocks = level.Blocks
# Sand to glass.
blocks[blocks == level.materials.materialNamed("Sand")] = level.materials.materialNamed("Glass")
blocks[blocks == level.materials.Sand.ID] = level.materials.Glass.ID
# Save the file with another name. This only works for non-Alpha levels.
level.saveToFile("server_level_glassy.dat");
@ -661,27 +661,45 @@ class MCLevel(object):
# end = tuple([o+s for o,s in zip(origin,size)])
return self.Blocks[x:x+w,z:z+l,y:y+h]
def fillBlocks(self, box, blockType, blockData = 0, blocksToReplace = None):
def blockReplaceTable(self, blocksToReplace):
blocktable = zeros( (256, 16), dtype='bool')
for b in blocksToReplace:
if b.hasAlternate:
blocktable[b.ID,b.blockData] = True
else:
blocktable[b.ID] = True
return blocktable
def fillBlocks(self, box, blockInfo, blocksToReplace = None):
if box is None:
box = self.bounds
else:
box = box.intersect(self.bounds)
info( u"Filling blocks in {0} with {1}, data={2} replacing{3}".format(box, blockType, blockData, blocksToReplace) )
info( u"Filling blocks in {0} with {1}, replacing{2}".format(box, blockInfo, blocksToReplace) )
slices = map(slice, box.origin, box.maximum)
blocks = self.Blocks[slices[0],slices[2],slices[1]]
if blocksToReplace != None:
mask = functools.reduce(operator.or_, (blocks==x for x in blocksToReplace))
blocktable = self.blockReplaceTable(blocksToReplace)
blocks[mask] = blockType;
if hasattr(self, "Data"):
self.Data[slices[0],slices[2],slices[1]][mask] = blockData;
data = self.Data[slices[0],slices[2],slices[1]]
mask = blocktable[blocks,data]
data[mask] = blockInfo.blockData;
else:
blocks[:] = blockType;
mask = blocktable[blocks,0]
blocks[mask] = blockInfo.ID;
else:
blocks[:] = blockInfo.ID;
if hasattr(self, "Data"):
self.Data[slices[0],slices[2],slices[1]] = blockData;
self.Data[slices[0],slices[2],slices[1]] = blockInfo.blockData;
#self.saveInPlace();
classicWoolMask = zeros((256,), dtype='bool')
@ -1617,7 +1635,7 @@ class INVEditChest(MCSchematic):
Width = 1
Height = 1
Length = 1
Blocks = array([[[materials.materialNamed("Chest")]]], 'uint8');
Blocks = array([[[materials.Chest.ID]]], 'uint8');
Data = array([[[0]]], 'uint8');
Entities = TAG_List();
@ -3426,23 +3444,32 @@ class MCInfdevOldLevel(MCLevel):
info( "Removed {0} tile entities".format(count) )
return count;
def fillBlocks(self, box, blockType, blockData = 0, blocksToReplace = None):
def fillBlocks(self, box, blockInfo, blocksToReplace = []):
if box is None:
chunkIterator = self.getAllChunkSlices()
else:
chunkIterator = self.getChunkSlices(box)
#shouldRetainData = (not blockInfo.hasAlternate and not any([b.hasAlternate for b in blocksToReplace]))
#if shouldRetainData:
# info( "Preserving data bytes" )
shouldRetainData = False #xxx old behavior overwrote blockdata with 0 when e.g. replacing water with lava
info("Replacing {0} with {1}".format(blocksToReplace, blockInfo))
changesLighting = True
if blocksToReplace != None:
newAbsorption = self.materials.lightAbsorption[blockType]
oldAbsorptions = map(self.materials.lightAbsorption.__getitem__, blocksToReplace)
blocktable = self.blockReplaceTable(blocksToReplace)
newAbsorption = self.materials.lightAbsorption[blockInfo.ID]
oldAbsorptions = [self.materials.lightAbsorption[b.ID] for b in blocksToReplace]
changesLighting = False
for a in oldAbsorptions:
if a != newAbsorption: changesLighting = True;
newEmission = self.materials.lightEmission[blockType]
oldEmissions = map(self.materials.lightEmission.__getitem__, blocksToReplace)
newEmission = self.materials.lightEmission[blockInfo.ID]
oldEmissions = [self.materials.lightEmission[b.ID] for b in blocksToReplace]
for a in oldEmissions:
if a != newEmission: changesLighting = True;
@ -3457,27 +3484,30 @@ class MCInfdevOldLevel(MCLevel):
info( u"Chunk {0}...".format(i) )
blocks = chunk.Blocks[slices]
mask = None
data = chunk.Data[slices]
mask = slice(None)
needsLighting = changesLighting;
if blocksToReplace != None:
mask = functools.reduce(operator.or_, (blocks==x for x in blocksToReplace))
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] = blockType
chunk.Data[slices][mask] = blockData
blocks[:][mask] = blockInfo.ID
if not shouldRetainData:
data[mask] = blockInfo.blockData
else:
skipped += 1;
needsLighting = False;
else:
blocks[:] = blockType
chunk.Data[slices] = blockData
blocks[:] = blockInfo.ID
if not shouldRetainData:
data[:] = blockInfo.blockData
chunk.chunkChanged(needsLighting);
chunk.compress();
@ -4102,7 +4132,7 @@ class MCIndevLevel(MCLevel):
8, 9, 10, 11, 12, 13, 14, 15]);
torchIndexes = (self.Blocks == self.materials.materialNamed("Torch"))
torchIndexes = (self.Blocks == self.materials.Torch.ID)
info( u"Rotating torches: {0}".format( len(torchIndexes.nonzero()[0]) ) )
self.Data[torchIndexes] = torchRotation[self.Data[torchIndexes]]
@ -4337,7 +4367,7 @@ def testIndevLevels():
indevlevel = MCLevel.fromFile("hueg.mclevel")
indevlevel.copyBlocksFrom(srclevel, BoundingBox((0,0,0), (64,64,64,)), (0,0,0) )
assert(all(indevlevel.Blocks[0:64,0:64,0:64] == srclevel.Blocks[0:64,0:64,0:64]))
indevlevel.fillBlocks(BoundingBox((0,0,0), (64,64,64,)), 12, 0, [1,2])
indevlevel.fillBlocks(BoundingBox((0,0,0), (64,64,64,)), indevlevel.materials.Sand, [indevlevel.materials.Stone, indevlevel.materials.Dirt])
indevlevel.saveInPlace()
def testAlphaLevels():
@ -4366,10 +4396,10 @@ def testAlphaLevels():
except Exception, e:
traceback.print_exc();
print e;
level.fillBlocks( BoundingBox((-11, 0, -7), (38, 128, 25)) , 5);
level.fillBlocks( BoundingBox((-11, 0, -7), (38, 128, 25)) , indevlevel.materials.WoodPlanks);
c = level.getChunk( 0, 0)
assert all(c.Blocks == 5)
level.fillBlocks( BoundingBox((-11, 0, -7), (38, 128, 25)) , 5, 0, [2,3]);
level.fillBlocks( BoundingBox((-11, 0, -7), (38, 128, 25)) , indevlevel.materials.WoodPlanks, [indevlevel.materials.Dirt, indevlevel.materials.Grass]);
#print b.shape
#raise SystemExit
cx, cz = -3,-1;