Last active
October 2, 2016 21:33
-
-
Save Marcono1234/c1a84917f667dbe109291de36e9859b1 to your computer and use it in GitHub Desktop.
MCEdit 1.x (http://www.mcedit-unified.net/) filter which creates a Minecraft structure from a selection in MCEdit. Latest MCEdit version is recommended
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Created by Marcono1234 | |
# Feel free to modify this code and use it for your own, you don't have to mention me as creator (only for this filter) | |
#from pymclevel import TAG_Compound, TAG_List, TAG_Int_Array, TAG_Byte_Array, TAG_String, TAG_Long, TAG_Int, TAG_Short, TAG_Byte, TAG_Double, TAG_Float | |
from pymclevel import TAG_Compound, TAG_List, TAG_String, TAG_Int, TAG_Double | |
from pymclevel import materials | |
import directories | |
import mcplatform | |
import albow | |
import os | |
import ast | |
import copy | |
import math | |
displayName = "Selection to structure" | |
lastStructureDirectory = directories.docsFolder | |
inputValues = [ | |
"Author: ", | |
"Include entities: ", | |
"Skip unknown blocks: ", | |
"Restrict written size to vanilla boundaries: ", | |
"Structure void id: ", | |
"Position tags entity: ", | |
"Tags to remove entity: ", | |
"Tags to remove tile entity: " | |
] | |
inputs = ( | |
(inputValues[0], "string"), | |
(inputValues[1], True), | |
(inputValues[2], True), | |
(inputValues[3], True), | |
(inputValues[4], ("string", "value=\"minecraft:structure_void\"")), | |
(inputValues[5], ("string", "value=[\"Pos\"]")), | |
(inputValues[6], ("string", "value=[\"x\", \"y\", \"z\", \"UUIDLeast\", \"UUIDMost\"]")), | |
(inputValues[7], ("string", "value=[\"Pos\"]")) | |
) | |
def perform(level, box, options): | |
global lastStructureDirectory | |
structureAuthor = options[inputValues[0]] | |
structureIncludeEntities = options[inputValues[1]] | |
skipUnknownBlocks = options[inputValues[2]] | |
# Makes sure that you can use the "Load" button to load the structure | |
restrictSizeToVanillaBoundaries = options[inputValues[3]] | |
# Uses numeric id | |
structureVoidId = materials.alphaMaterials.blockstate_api.blockstateToID(ast.literal_eval(options[inputValues[4]]), {})[0] | |
if structureVoidId == -1: | |
raise Exception("Invalid structure void id or MCEdit does not support it. Please use a newer version of MCEdit.") | |
positionTagsEntity = ast.literal_eval(options[inputValues[5]]) | |
tagsToRemoveEntity = ast.literal_eval(options[inputValues[6]]) | |
tagsToRemoveTileEntity = ast.literal_eval(options[inputValues[7]]) | |
entityPositionGetter = PositionGetter(positionTagsEntity) | |
structureCompound = TAG_Compound() | |
# Assumes all chunks are in the latest version | |
structureCompound["DataVersion"] = copy.deepcopy(level.root_tag["Data"]["Version"]["Id"]) | |
structureCompound["author"] = TAG_String(structureAuthor) | |
writtenStructureSize = [box.maxx - box.minx, box.maxy - box.miny, box.maxz - box.minz] | |
if restrictSizeToVanillaBoundaries: | |
for index in xrange(0, len(writtenStructureSize)): | |
writtenStructureSize[index] = min(writtenStructureSize[index], 32) | |
structureCompound["size"] = TAG_List([ | |
TAG_Int(writtenStructureSize[0]), | |
TAG_Int(writtenStructureSize[1]), | |
TAG_Int(writtenStructureSize[2]) | |
]) | |
palette = Palette() | |
blockList = [] | |
unknownBlocks = [] | |
for x in xrange(box.minx, box.maxx): | |
for y in xrange(box.miny, box.maxy): | |
for z in xrange(box.minz, box.maxz): | |
if not level.containsPoint(x, y, z): | |
continue | |
blockId = level.blockAt(x, y, z) | |
if (blockId == structureVoidId): | |
continue | |
else: | |
blockCompound = TAG_Compound() | |
blockState = BlockState(materials.alphaMaterials.blockstate_api.idToBlockstate(blockId, level.blockDataAt(x, y, z))) | |
if blockState.blockId == "<Unknown>": | |
if skipUnknownBlocks: | |
if not blockId in unknownBlocks: | |
unknownBlocks.append(blockId) | |
continue | |
else: | |
raise Exception("Cannot get id and / or state for unknown block " + str(blockId)) | |
stateIndex = palette.getStateIndex(blockState) | |
blockCompound["state"] = TAG_Int(stateIndex) | |
blockCompound["pos"] = TAG_List([ | |
TAG_Int(x - box.minx), | |
TAG_Int(y - box.miny), | |
TAG_Int(z - box.minz), | |
]) | |
tileEntity = level.tileEntityAt(x, y, z) | |
if tileEntity != None: | |
tileEntity = copy.deepcopy(tileEntity) | |
removeTagsFromNbt(tileEntity, tagsToRemoveTileEntity) | |
blockCompound["nbt"] = tileEntity | |
blockList.append(blockCompound) | |
structureCompound["palette"] = palette.getNbtRepresentation() | |
structureCompound["blocks"] = TAG_List(blockList) | |
if structureIncludeEntities: | |
entities = level.getEntitiesInBox(box) | |
entityList = [] | |
for entity in entities: | |
entity = copy.deepcopy(entity) | |
positionList = entityPositionGetter.getPosition(entity) | |
removeTagsFromNbt(entity, tagsToRemoveEntity) | |
entityCompound = TAG_Compound() | |
offsetX = positionList[0].value - box.minx | |
offsetY = positionList[1].value - box.miny | |
offsetZ = positionList[2].value - box.minz | |
entityCompound["blockPos"] = TAG_List([ | |
TAG_Int(math.floor(offsetX)), | |
TAG_Int(math.floor(offsetY)), | |
TAG_Int(math.floor(offsetZ)) | |
]) | |
entityCompound["pos"] = TAG_List([ | |
TAG_Double(offsetX), | |
TAG_Double(offsetY), | |
TAG_Double(offsetZ) | |
]) | |
entityCompound["nbt"] = entity | |
entityList.append(entityCompound) | |
if len(entityList) > 0: | |
structureCompound["entities"] = TAG_List(entityList) | |
fileFormat = mcplatform.buildFileTypes(({"Minecraft Structure NBT": ["nbt"]}, [])) | |
structureFilePath = mcplatform.askSaveFile( | |
lastStructureDirectory, | |
"Save structure", | |
"structure", | |
fileFormat, | |
fileFormat | |
) | |
if structureFilePath == None: | |
raise Exception("Saving dialog was closed, structure was not saved") | |
lastStructureDirectory = os.path.dirname(structureFilePath) | |
structureCompound.save(structureFilePath) | |
unknownBlocks = sorted(unknownBlocks) | |
skippedBlocksMessage = "" | |
if len(unknownBlocks) > 0: | |
skippedBlocksMessage = "\n\nSkipped blocks:\n" + ", ".join([str(blockId) for blockId in unknownBlocks]) | |
raise Exception("Structure was saved as\n\n" + structureFilePath + skippedBlocksMessage) | |
def addPrefixIfMissing(stringValue): | |
if ":" in stringValue: | |
return stringValue | |
else: | |
return "minecraft:" + stringValue | |
def removeTagsFromNbt(nbtCompound, keyList): | |
for key in keyList: | |
if key in nbtCompound: | |
del nbtCompound[key] | |
class BlockState: | |
blockId = None | |
properties = {} | |
def __init__(self, stateTuple): | |
self.blockId = addPrefixIfMissing(stateTuple[0]) | |
self.properties = stateTuple[1] | |
def __eq__(self, other): | |
return self.blockId == other.blockId and self.properties == other.properties | |
def getNbtRepresentation(self): | |
stateCompound = TAG_Compound() | |
stateCompound["Name"] = TAG_String(self.blockId) | |
if len(self.properties) > 0: | |
propertiesCompound = TAG_Compound() | |
for stateProperty in self.properties: | |
propertiesCompound[stateProperty] = TAG_String(self.properties[stateProperty]) | |
stateCompound["Properties"] = propertiesCompound | |
return stateCompound | |
class Palette: | |
stateIndex = 0 | |
stateList = [] | |
def getStateIndex(self, blockState): | |
if blockState in self.stateList: | |
return self.stateList.index(blockState) | |
else: | |
self.stateList.append(blockState) | |
return len(self.stateList) - 1 | |
def getNbtRepresentation(self): | |
return TAG_List([blockState.getNbtRepresentation() for blockState in self.stateList]) | |
class PositionGetter: | |
isPositionList = False | |
positionKeys = None | |
def __init__(self, keyList): | |
if len(keyList) == 1: | |
self.isPositionList = True | |
self.positionKeys = keyList[0] | |
else: | |
self.positionKeys = keyList | |
def getPosition(self, nbt): | |
if self.isPositionList: | |
return copy.deepcopy(nbt[self.positionKeys]) | |
else: | |
position = [] | |
for key in self.positionKeys: | |
position.append(nbt[key]) | |
return position |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment