Skip to content

Instantly share code, notes, and snippets.

@Marcono1234
Last active October 2, 2016 21:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Marcono1234/c1a84917f667dbe109291de36e9859b1 to your computer and use it in GitHub Desktop.
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
# 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