def applyToSelections(self, command, selections): """ :type command: BrushCommand """ fill = command.editorSession.currentDimension.fillBlocksIter(selections[0], command.options['blockInfo']) showProgress("Applying brush...", fill)
def applyToSelections(self, command, selections): """ :type command: BrushCommand """ fill = command.editorSession.currentDimension.fillBlocksIter(selections[0], command.blockInfo) showProgress("Applying brush...", fill)
def generateClicked(self): if self.currentGenerator is None: return if self.schematicBounds is None: log.info("schematicBounds is None, not generating") return if self.currentSchematic is None: log.info("Generating new schematic for import") currentSchematic = self.currentGenerator.generate(self.schematicBounds, self.editorSession.worldEditor.blocktypes) else: log.info("Importing previously generated schematic.") currentSchematic = self.currentSchematic command = GenerateCommand(self, self.schematicBounds) try: with command.begin(): if currentSchematic is not None: task = self.editorSession.currentDimension.importSchematicIter(currentSchematic, self.schematicBounds.origin) showProgress(self.tr("Importing generated object..."), task) else: task = self.currentGenerator.generateInWorld(self.schematicBounds, self.editorSession.currentDimension) showProgress(self.tr("Generating object in world..."), task) except Exception as e: log.exception("Error while importing or generating in world: %r" % e) command.undo() else: self.editorSession.pushCommand(command)
def replaceEntries(self, entries): shouldReplaceName = self.widget.replaceNameCheckbox.isChecked() newName = self.widget.replaceNameField.text() shouldReplaceValue = self.widget.replaceValueCheckbox.isChecked() newValue = self.widget.replaceValueField.text() # newTagType = self.widget.replaceTagTypeComboBox.currentIndex() def _replaceInTag(result, tag): for component in result.path: tag = tag[component] if shouldReplaceName: subtag = tag.pop(result.tagName) tag[newName] = subtag result.setTagName(newName) if shouldReplaceValue: subtag = tag[result.tagName] # xxx newTagType if subtag.tagID in (nbt.ID_BYTE, nbt.ID_SHORT, nbt.ID_INT, nbt.ID_LONG): try: value = int(newValue) except ValueError: log.warn("Could not assign value %s to tag %s (could not convert to int)", newValue, subtag) return elif subtag.tagID in (nbt.ID_FLOAT, nbt.ID_DOUBLE): try: value = float(newValue) except ValueError: log.warn("Could not assign value %s to tag %s (could not convert to float)", newValue, subtag) return else: value = newValue subtag.value = value def _replace(): for result in entries: if result.resultType == result.TileEntityResult: tileEntity = self.editorSession.currentDimension.getTileEntity(result.position) if tileEntity: tag = tileEntity.raw_tag() _replaceInTag(result, tag) tileEntity.dirty() if result.resultType == result.EntityResult: entity = result.getEntity(self.editorSession.currentDimension) # xxx put dimension in result!!!! if entity: tag = entity.raw_tag() _replaceInTag(result, tag) entity.dirty() # if result.resultType == result.ItemResult: # xxx yield command = NBTReplaceCommand(self.editorSession, "Replace NBT data") # xxx replace details with command.begin(): replacer = _replace() showProgress("Replacing NBT data...", replacer) self.editorSession.pushCommand(command)
def deleteBlocks(self): command = SimpleRevisionCommand(self, "Delete Blocks") with command.begin(): fillTask = self.currentDimension.fillBlocksIter( self.currentSelection, "air") showProgress("Deleting...", fillTask) self.pushCommand(command)
def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) destDim = self.editorSession.currentDimension with command.begin(): log.info("Move: starting") sourceDim, selection = self.currentImport.getSourceForDim(destDim) # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter(sourceDim, selection, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task) log.info("Move: clearing") # Clear source if self.currentImport.isMove: fill = destDim.fillBlocksIter(self.currentImport.selection, "air") showProgress(self.tr("Clearing..."), fill) self.editorSession.pushCommand(command)
def confirmClone(self): if self.mainPendingClone is None: return command = CloneFinishCommand(self, self.mainPendingClone, self.originPoint) with command.begin(): tasks = [] for clone in self.pendingClones: # TODO don't use intermediate schematic... destDim = self.editorSession.currentDimension dim, selection = clone.getSourceForDim(destDim) task = destDim.copyBlocksIter(dim, selection, clone.importPos, biomes=True, create=True, copyAir=False) tasks.append(task) showProgress(self.tr("Pasting..."), *tasks) self.editorSession.pushCommand(command)
def deleteEntities(self): command = SimpleRevisionCommand(self, "Delete Entities") with command.begin(): entitiesTask = RemoveEntitiesOperation(self.currentDimension, self.currentSelection) showProgress("Deleting...", entitiesTask) self.pushCommand(command)
def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) destDim = self.editorSession.currentDimension with command.begin(): log.info("Move: starting") sourceDim, selection = self.currentImport.getSourceForDim(destDim) # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter( sourceDim, selection, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task) log.info("Move: clearing") # Clear source if self.currentImport.isMove: fill = destDim.fillBlocksIter(self.currentImport.selection, "air") showProgress(self.tr("Clearing..."), fill) self.editorSession.pushCommand(command)
def _clear(): log.info("Move: clearing") # Clear source if self.currentImport.isMove: fill = destDim.fillBlocksIter(self.currentImport.selection, "air") showProgress(self.tr("Clearing..."), fill)
def begin(self): self.previousRevision = self.editorSession.currentRevision self.editorSession.beginUndo() yield task = self.editorSession.commitUndoIter() showProgress(QtGui.qApp.tr("Writing undo history"), task) self.currentRevision = self.editorSession.currentRevision
def cut(self): command = SimpleRevisionCommand(self, "Cut") with command.begin(): task = self.currentDimension.exportSchematicIter(self.currentSelection) self.copiedSchematic = showProgress("Cutting...", task) task = self.currentDimension.fillBlocksIter(self.currentSelection, "air") showProgress("Cutting...", task) self.undoStack.push(command)
def deleteSelection(self): command = SimpleRevisionCommand(self, "Delete") with command.begin(): fillTask = self.currentDimension.fillBlocksIter(self.currentSelection, "air") entitiesTask = RemoveEntitiesOperation(self.currentDimension, self.currentSelection) task = ComposeOperations(fillTask, entitiesTask) showProgress("Deleting...", task) self.pushCommand(command)
def replaceEntries(self, entries): shouldReplaceName = self.replaceNameCheckbox.isChecked() newName = self.replaceNameField.text() shouldReplaceValue = self.replaceValueCheckbox.isChecked() newValue = self.replaceValueField.text() # newTagType = self.replaceTagTypeComboBox.currentIndex() def _replaceInTag(result, tag): for component in result.path: tag = tag[component] if shouldReplaceName: subtag = tag.pop(result.tagName) tag[newName] = subtag result.setTagName(newName) if shouldReplaceValue: subtag = tag[result.tagName] # xxx newTagType if subtag.tagID in (nbt.ID_BYTE, nbt.ID_SHORT, nbt.ID_INT, nbt.ID_LONG): try: value = int(newValue) except ValueError: log.warn( "Could not assign value %s to tag %s (could not convert to int)", newValue, subtag) return elif subtag.tagID in (nbt.ID_FLOAT, nbt.ID_DOUBLE): try: value = float(newValue) except ValueError: log.warn( "Could not assign value %s to tag %s (could not convert to float)", newValue, subtag) return else: value = newValue subtag.value = value result.value = value def _replace(): for result in entries: ref = result.getTargetRef() tag = ref.raw_tag() _replaceInTag(result, tag) ref.dirty = True yield command = NBTReplaceCommand(self.editorSession, "Replace NBT data") # xxx replace details with command.begin(): showProgress("Replacing NBT data...", _replace()) self.editorSession.pushCommand(command)
def replaceCommand(editorSession): dialog = ReplaceDialog(editorSession) if dialog.exec_(): replacements = dialog.getReplacements() command = SimpleRevisionCommand(editorSession, "Replace") with command.begin(): task = editorSession.currentDimension.fillBlocksIter(editorSession.currentSelection, replacements) showProgress("Replacing...", task) editorSession.pushCommand(command)
def analyze(self): if self.currentSelection is None: return task = self.currentDimension.analyzeIter(self.currentSelection) showProgress("Analyzing...", task) outputDialog = AnalyzeOutputDialog(self, task.blocks, task.entityCounts, task.tileEntityCounts, task.dimension.worldEditor.displayName)
def redo(self): if not self.performed: self.editorSession.beginUndo() self.perform() task = self.editorSession.commitUndoIter() showProgress(QtGui.qApp.tr("Writing undo history"), task) else: self.editorSession.undoForward()
def _copy(): # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter(sourceDim, selection, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task)
def doReplace(self): replacements = self.getReplacements() command = SimpleRevisionCommand(self.editorSession, "Replace") selection = self.editorSession.currentDimension.bounds # selection = self.editorSession.currentSelection with command.begin(): task = self.editorSession.currentDimension.fillBlocksIter(selection, replacements, updateLights=False) showProgress("Replacing...", task) self.editorSession.pushCommand(command)
def perform(self): dim = self.editorSession.currentDimension point = self.point doomedBlock = dim.getBlockID(*point) doomedBlockData = dim.getBlockData(*point) checkData = (doomedBlock not in (8, 9, 10, 11)) indiscriminate = self.indiscriminate if doomedBlock == self.blockInfo.ID: return if indiscriminate: checkData = False if doomedBlock == 2: # grass doomedBlock = 3 # dirt x, y, z = point dim.setBlockID(x, y, z, self.blockInfo.ID) dim.setBlockData(x, y, z, self.blockInfo.meta) def processCoords(coords): newcoords = collections.deque() for (x, y, z) in coords: for face, offsets in faces.faceDirections: dx, dy, dz = offsets p = (x + dx, y + dy, z + dz) nx, ny, nz = p b = dim.getBlockID(nx, ny, nz) if indiscriminate: if b == 2: b = 3 if b == doomedBlock: if checkData: if dim.getBlockData(nx, ny, nz) != doomedBlockData: continue dim.setBlockID(nx, ny, nz, self.blockInfo.ID) dim.setBlockData(nx, ny, nz, self.blockInfo.meta) newcoords.append(p) return newcoords def spread(coords): start = time.time() num = 0 while len(coords): num += len(coords) coords = processCoords(coords) d = time.time() - start progress = "Did {0} coords in {1}".format(num, d) log.debug(progress) yield progress showProgress("Flood fill...", spread([point]), cancel=True)
def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) with command.begin(): task = self.editorSession.currentDimension.importSchematicIter(self.currentImport.schematic, self.currentImport.pos) showProgress(self.tr("Pasting..."), task) self.editorSession.pushCommand(command)
def doReplace(self): replacements = self.widget.replacementList.getReplacements() command = SimpleRevisionCommand(self.editorSession, "Replace") if self.widget.replaceBlocksInSelectionCheckbox.isChecked(): selection = self.editorSession.currentSelection else: selection = self.editorSession.currentDimension.bounds with command.begin(): task = self.editorSession.currentDimension.fillBlocksIter(selection, replacements, updateLights=False) showProgress("Replacing...", task) self.editorSession.pushCommand(command)
def applyToSelections(self, command, selections): """ :type command: BrushCommand """ fill = command.editorSession.currentDimension.fillBlocksIter( selections[0], command.blockInfo) if selections[0].chunkCount > 32: showProgress("Applying brush...", fill) else: for _ in fill: pass
def _copy(): # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter( sourceDim, selection, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task)
def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) with command.begin(): task = self.editorSession.currentDimension.importSchematicIter( self.currentImport.schematic, self.currentImport.pos) showProgress(self.tr("Pasting..."), task) self.editorSession.pushCommand(command)
def doReplace(self): replacements = self.widget.replacementList.getReplacements() command = SimpleRevisionCommand(self.editorSession, "Replace") if self.widget.replaceBlocksInSelectionCheckbox.isChecked(): selection = self.editorSession.currentSelection else: selection = self.editorSession.currentDimension.bounds with command.begin(): task = self.editorSession.currentDimension.fillBlocksIter( selection, replacements) showProgress("Replacing...", task) self.editorSession.pushCommand(command)
def replaceEntries(self, entries): shouldReplaceName = nbtReplaceSettings.replaceNameEnabled.value() newName = nbtReplaceSettings.replaceNameField.value() shouldReplaceValue = nbtReplaceSettings.replaceValueEnabled.value() newValue = nbtReplaceSettings.replaceValueField.value() # newTagType = self.replaceTagTypeComboBox.currentIndex() def _replaceInTag(result, tag): for component in result.path: tag = tag[component] if shouldReplaceName: subtag = tag.pop(result.tagName) tag[newName] = subtag result.setTagName(newName) if shouldReplaceValue: subtag = tag[result.tagName] # xxx newTagType if subtag.tagID in (nbt.ID_BYTE, nbt.ID_SHORT, nbt.ID_INT, nbt.ID_LONG): try: value = int(newValue) except ValueError: log.warn("Could not assign value %s to tag %s (could not convert to int)", newValue, subtag) return elif subtag.tagID in (nbt.ID_FLOAT, nbt.ID_DOUBLE): try: value = float(newValue) except ValueError: log.warn("Could not assign value %s to tag %s (could not convert to float)", newValue, subtag) return else: value = newValue subtag.value = value result.value = value def _replace(): for result in entries: ref = result.getTargetRef() tag = result.getTargetTag() _replaceInTag(result, tag) ref.dirty = True yield with self.editorSession.beginSimpleCommand(self.tr("Replace NBT data")): showProgress("Replacing NBT data...", _replace())
def generate(self, bounds, blocktypes): # self.systemsBox.value() schematic = createSchematic(bounds.size, blocktypes) dim = schematic.getDimension() system = koch.Snowflake(dim.bounds, blocktype=self.blocktypeButton.block) symbol_list = [system] max_iterations = self.iterationsSlider.value() def process(_symbol_list): for iteration, _symbol_list in applyReplacementsIterated(_symbol_list, max_iterations): yield iteration, max_iterations yield _symbol_list symbol_list = showProgress("Generating...", process(symbol_list), cancel=True) if symbol_list is False: return import pprint pprint.pprint(symbol_list) rendering = renderBlocks(symbol_list) print("Rendering %d blocks" % len(rendering)) for x, y, z, blockType in rendering: dim.setBlock(x, y, z, blockType) return schematic
def fillCommand(editorSession): """ :type editorSession: mcedit2.editorsession.EditorSession """ box = editorSession.currentSelection if box is None or box.volume == 0: return widget = getFillWidget(editorSession) if widget.exec_(): command = SimpleRevisionCommand(editorSession, "Fill") with command.begin(): task = editorSession.currentDimension.fillBlocksIter(box, widget.blockTypeInput.block) showProgress("Filling...", task) editorSession.pushCommand(command)
def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) destDim = self.editorSession.currentDimension with command.begin(): log.info("Move: starting") if self.currentImport.isMove: sourceDim = self.currentImport.importDim destBox = BoundingBox(self.currentImport.importPos, sourceDim.bounds.size) # Use intermediate schematic only if source and destination overlap. if sourceDim.bounds.intersect(destBox).volume: log.info("Move: using temporary") export = extractSchematicFromIter( sourceDim, self.currentImport.selection) schematic = showProgress(self.tr("Copying..."), export) sourceDim = schematic.getDimension() else: # Use source as-is sourceDim = self.currentImport.importDim # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter( sourceDim, sourceDim.bounds, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task) log.info("Move: clearing") # Clear source if self.currentImport.isMove: fill = destDim.fillBlocksIter(self.currentImport.selection, "air") showProgress(self.tr("Clearing..."), fill) self.editorSession.pushCommand(command)
def removeEntries(self, entries): def _remove(): for result in entries: ref = result.getTargetRef() tag = result.getTargetTag() for component in result.path[:-1]: tag = tag[component] del tag[result.tagName] ref.dirty = True yield self.resultsModel.removeEntries(entries) with self.editorSession.beginSimpleCommand(self.tr("Remove NBT tags")): showProgress("Removing NBT tags...", _remove())
def toolActive(self): self.editorSession.selectionTool.hideSelectionWalls = True if self.currentImport is None: # Need to cut out selection # xxxx for huge selections, don't cut, just do everything at the end? if self.editorSession.currentSelection is None: return export = self.editorSession.currentDimension.exportSchematicIter(self.editorSession.currentSelection) schematic = showProgress("Copying...", export) pos = self.editorSession.currentSelection.origin pendingImport = PendingImport(schematic, pos, self.tr("<Moved Object>")) moveCommand = MoveSelectionCommand(self, pendingImport) with moveCommand.begin(): fill = self.editorSession.currentDimension.fillBlocksIter(self.editorSession.currentSelection, "air") showProgress("Clearing...", fill) self.editorSession.pushCommand(moveCommand)
def removeEntries(self, entries): def _remove(): for result in entries: ref = result.getTargetRef() tag = ref.raw_tag() for component in result.path[:-1]: tag = tag[component] del tag[result.tagName] ref.dirty = True yield self.resultsModel.removeEntries(entries) command = NBTReplaceCommand(self.editorSession, "Remove NBT tags") with command.begin(): showProgress("Removing NBT tags...", _remove()) self.editorSession.pushCommand(command)
def toolActive(self): self.editorSession.selectionTool.hideSelectionWalls = True if self.currentImport is None: # Need to cut out selection # xxxx for huge selections, don't cut, just do everything at the end? if self.editorSession.currentSelection is None: return export = self.editorSession.currentDimension.exportSchematicIter( self.editorSession.currentSelection) schematic = showProgress("Copying...", export) pos = self.editorSession.currentSelection.origin pendingImport = PendingImport(schematic, pos, self.tr("<Moved Object>")) moveCommand = MoveSelectionCommand(self, pendingImport) with moveCommand.begin(): fill = self.editorSession.currentDimension.fillBlocksIter( self.editorSession.currentSelection, "air") showProgress("Clearing...", fill) self.editorSession.pushCommand(moveCommand)
def confirmClone(self): if self.pendingClone is None: return command = CloneFinishCommand(self, self.pendingClone) with command.begin(): # TODO don't use intermediate schematic... export = self.pendingClone.sourceDim.exportSchematicIter(self.pendingClone.selection) schematic = showProgress("Copying...", export) dim = schematic.getDimension() tasks = [] for pos in self.getTilingPositions(): task = self.editorSession.currentDimension.copyBlocksIter(dim, dim.bounds, pos, biomes=True, create=True) tasks.append(task) showProgress(self.tr("Pasting..."), *tasks) self.editorSession.pushCommand(command) self.originPoint = None
def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) destDim = self.editorSession.currentDimension with command.begin(): log.info("Move: starting") if self.currentImport.isMove: sourceDim = self.currentImport.importDim destBox = BoundingBox(self.currentImport.importPos, sourceDim.bounds.size) # Use intermediate schematic only if source and destination overlap. if sourceDim.bounds.intersect(destBox).volume: log.info("Move: using temporary") export = extractSchematicFromIter(sourceDim, self.currentImport.selection) schematic = showProgress(self.tr("Copying..."), export) sourceDim = schematic.getDimension() else: # Use source as-is sourceDim = self.currentImport.importDim # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter(sourceDim, sourceDim.bounds, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task) log.info("Move: clearing") # Clear source if self.currentImport.isMove: fill = destDim.fillBlocksIter(self.currentImport.selection, "air") showProgress(self.tr("Clearing..."), fill) self.editorSession.pushCommand(command)
def export(self): # prompt for filename and format. maybe use custom browser to save to export library?? startingDir = Settings().value("import_dialog/starting_dir", getUserSchematicsDirectory()) result = QtGui.QFileDialog.getSaveFileName(QtGui.qApp.mainWindow, self.tr("Export Schematic"), startingDir, "Schematic files (*.schematic)") if result: filename = result[0] if filename: task = self.currentDimension.exportSchematicIter(self.currentSelection) schematic = showProgress("Copying...", task) schematic.saveToFile(filename)
def confirmClone(self): if self.pendingClone is None: return command = CloneFinishCommand(self, self.pendingClone) with command.begin(): # TODO don't use intermediate schematic... export = self.pendingClone.sourceDim.exportSchematicIter( self.pendingClone.selection) schematic = showProgress("Copying...", export) dim = schematic.getDimension() tasks = [] for pos in self.getTilingPositions(): task = self.editorSession.currentDimension.copyBlocksIter( dim, dim.bounds, pos, biomes=True, create=True) tasks.append(task) showProgress(self.tr("Pasting..."), *tasks) self.editorSession.pushCommand(command) self.originPoint = None
def getPreviewNode(self, bounds): system = koch.Snowflake(bounds, blocktype=self.blocktypeButton.block) symbol_list = [system] max_iterations = self.iterationsSlider.value() def process(_symbol_list): for iteration, _symbol_list in applyReplacementsIterated(_symbol_list, max_iterations): yield iteration, max_iterations yield _symbol_list symbol_list = showProgress("Generating...", process(symbol_list), cancel=True) if symbol_list is False: return sceneNodes = renderSceneNodes(symbol_list) return sceneNodes
def createSymbolList(self, bounds, indefinite=False): system = self.createInitialSymbol(bounds) symbol_list = [system] if indefinite: max_iterations = self.MAX_ITERATIONS else: max_iterations = self.iterationsSlider.value() def process(_symbol_list): for iteration, _symbol_list in applyReplacementsIterated(_symbol_list, max_iterations): yield iteration, max_iterations yield _symbol_list symbol_list = showProgress("Generating...", process(symbol_list), cancel=True) if symbol_list is False: return None return symbol_list
def getSourceForDim(self, destDim): if destDim is self.sourceDim: sourceDim = self.importDim destBox = self.importBounds if self.transformedDim is not None: sourceBounds = sourceDim.bounds else: sourceBounds = self.selection # Use intermediate schematic only if source and destination overlap. if sourceBounds.intersect(destBox).volume: log.info("Move: using temporary") export = extractSchematicFromIter(sourceDim, self.selection) schematic = showProgress(self.tr("Copying..."), export) tempDim = schematic.getDimension() return tempDim, tempDim.bounds # Use source as-is if self.transformedDim is not None: selection = self.transformedDim.bounds else: selection = self.selection return self.importDim, selection
def createSymbolList(self, bounds, indefinite=False): system = self.createInitialSymbol(bounds) symbol_list = [system] if indefinite: max_iterations = self.MAX_ITERATIONS else: max_iterations = self.iterationsSlider.value() def process(_symbol_list): for iteration, _symbol_list in applyReplacementsIterated( _symbol_list, max_iterations): yield iteration, max_iterations yield _symbol_list symbol_list = showProgress("Generating...", process(symbol_list), cancel=True) if symbol_list is False: return None return symbol_list
def perform(self): if len(self.points) > 10: showProgress("Performing brush...", self._perform(), cancel=True) else: exhaust(self._perform())
def deleteBlocks(self): command = SimpleRevisionCommand(self, "Delete Blocks") with command.begin(): fillTask = self.currentDimension.fillBlocksIter(self.currentSelection, "air") showProgress("Deleting...", fillTask) self.pushCommand(command)
def copy(self): task = self.currentDimension.exportSchematicIter(self.currentSelection) self.copiedSchematic = showProgress("Copying...", task)
def save(self): self.undoStack.clearUndoBlock() saveTask = self.worldEditor.saveChangesIter() showProgress("Saving...", saveTask) self.dirty = False