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:
parent
00c3514e36
commit
1bf1cfa8b6
666
materials.py
666
materials.py
File diff suppressed because it is too large
Load Diff
83
mce.py
83
mce.py
@ -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
|
||||
data = 0
|
||||
if ":" in keyword:
|
||||
blockID, data = map(int, keyword.split(":"))
|
||||
else:
|
||||
blockID = int(keyword)
|
||||
blockInfo = self.level.materials.blockWithID(blockID, data)
|
||||
|
||||
except ValueError:
|
||||
blockType = None;
|
||||
blockInfo = None;
|
||||
|
||||
if blockType is 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;
|
||||
@ -1109,16 +1105,19 @@ class mce(object):
|
||||
else:
|
||||
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:
|
||||
|
84
mclevel.py
84
mclevel.py
@ -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))
|
||||
|
||||
blocks[mask] = blockType;
|
||||
blocktable = self.blockReplaceTable(blocksToReplace)
|
||||
|
||||
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:
|
||||
mask = blocktable[blocks,0]
|
||||
|
||||
blocks[mask] = blockInfo.ID;
|
||||
|
||||
else:
|
||||
blocks[:] = blockType;
|
||||
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;
|
||||
|
Reference in New Issue
Block a user