class FindReplaceNBT(QtCore.QObject): def __init__(self, editorSession, dialog): super(FindReplaceNBT, self).__init__() self.editorSession = editorSession self.widget = load_ui("find_replace_nbt.ui") self.dialog = dialog self.resultsWidget = load_ui("find_replace_nbt_results.ui") self.resultsDockWidget = MCEDockWidget("NBT Search", objectName="nbtSearch") self.resultsDockWidget.setWidget(self.resultsWidget) self.resultsDockWidget.hide() self.resultsModel = NBTResultsModel() self.resultsWidget.resultsView.setModel(self.resultsModel) self.resultsWidget.resultsView.clicked.connect(self.resultsViewIndexClicked) # --- Buttons --- self.widget.findButton.clicked.connect(self.find) self.resultsWidget.stopButton.clicked.connect(self.stop) self.resultsWidget.findAgainButton.clicked.connect(dialog.exec_) self.resultsWidget.replaceSelectedButton.clicked.connect(self.replaceSelected) self.resultsWidget.replaceAllButton.clicked.connect(self.replaceAll) self.widget.searchNameCheckbox.toggled.connect(self.searchForToggled) self.widget.searchValueCheckbox.toggled.connect(self.searchForToggled) self.findTimer = None self.finder = None # --- Search for... --- self.widget.nameField.setText(nbtReplaceSettings.nameField.value("")) self.widget.searchNameCheckbox.setChecked(len(self.widget.nameField.text()) > 0) self.widget.nameField.textChanged.connect(self.nameFieldChanged) self.widget.valueField.setText(nbtReplaceSettings.valueField.value("")) self.widget.searchValueCheckbox.setChecked(len(self.widget.valueField.text()) > 0) self.widget.valueField.textChanged.connect(self.valueFieldChanged) # --- Search in... --- self.widget.searchEntitiesCheckbox.setChecked(nbtReplaceSettings.searchEntitiesChecked.value()) self.widget.searchEntitiesCheckbox.toggled.connect(nbtReplaceSettings.searchEntitiesChecked.setValue) self.widget.entityIDField.setText(nbtReplaceSettings.entityIDField.value()) self.widget.entityIDField.textChanged.connect(self.entityIDFieldChanged) self.widget.searchTileEntitiesCheckbox.setChecked(nbtReplaceSettings.searchTileEntitiesChecked.value()) self.widget.searchTileEntitiesCheckbox.toggled.connect(nbtReplaceSettings.searchTileEntitiesChecked.setValue) self.widget.tileEntityIDField.setText(nbtReplaceSettings.tileEntityIDField.value()) self.widget.tileEntityIDField.textChanged.connect(self.tileEntityIDFieldChanged) # --- Replace with... --- self.widget.replaceNameField.setText(nbtReplaceSettings.replaceNameField.value()) self.resultsWidget.replaceNameField.setText(nbtReplaceSettings.replaceNameField.value()) self.widget.replaceNameField.textChanged.connect(self.replaceNameFieldChanged) self.widget.replaceNameCheckbox.setChecked(len(self.widget.replaceNameField.text())) self.resultsWidget.replaceNameCheckbox.setChecked(len(self.widget.replaceNameField.text())) self.widget.replaceValueField.setText(nbtReplaceSettings.replaceValueField.value()) self.resultsWidget.replaceValueField.setText(nbtReplaceSettings.replaceValueField.value()) self.widget.replaceValueField.textChanged.connect(self.replaceValueFieldChanged) self.widget.replaceValueCheckbox.setChecked(len(self.widget.replaceValueField.text())) self.resultsWidget.replaceValueCheckbox.setChecked(len(self.widget.replaceValueField.text())) self.widget.replaceValueTagTypeComboBox.setCurrentIndex(nbtReplaceSettings.replaceValueTagType.value()) self.widget.replaceValueTagTypeComboBox.currentIndexChanged[int].connect(self.valueTagTypeChanged) def dialogOpened(self): currentSelection = self.editorSession.currentSelection self.widget.inSelectionCheckbox.setChecked(currentSelection is not None and currentSelection.volume > 0) def searchForToggled(self): #canSearch = self.widget.searchNameCheckbox.isChecked() or self.widget.searchValueCheckbox.isChecked() #self.widget.findButton.setEnabled(canSearch) pass def nameFieldChanged(self, value): nbtReplaceSettings.nameField.setValue(value) self.widget.searchNameCheckbox.setChecked(len(value) > 0) def valueFieldChanged(self, value): nbtReplaceSettings.valueField.setValue(value) self.widget.searchValueCheckbox.setChecked(len(value) > 0) def entityIDFieldChanged(self, value): nbtReplaceSettings.entityIDField.setValue(value) if len(value): self.widget.searchEntitiesCheckbox.setChecked(True) def tileEntityIDFieldChanged(self, value): nbtReplaceSettings.tileEntityIDField.setValue(value) if len(value): self.widget.searchTileEntitiesCheckbox.setChecked(True) def replaceNameFieldChanged(self, value): if value != nbtReplaceSettings.replaceNameField.value(): nbtReplaceSettings.replaceNameField.setValue(value) self.widget.replaceNameCheckbox.setChecked(len(value) > 0) self.widget.replaceNameField.setText(value) self.resultsWidget.replaceNameCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceNameField.setText(value) def replaceValueFieldChanged(self, value): if value != nbtReplaceSettings.replaceValueField.value(): nbtReplaceSettings.replaceValueField.setValue(value) self.widget.replaceValueCheckbox.setChecked(len(value) > 0) self.widget.replaceValueField.setText(value) self.resultsWidget.replaceValueCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceValueField.setText(value) def valueTagTypeChanged(self, index): if index != nbtReplaceSettings.replaceValueTagType.value(): nbtReplaceSettings.replaceValueTagType.setValue(index) self.widget.replaceValueTagTypeComboBox.setCurrentIndex(index) self.resultsWidget.replaceValueTagTypeComboBox.setCurrentIndex(index) def resultsViewIndexClicked(self, modelIndex): row = modelIndex.row() result = self.resultsModel.results[row] if result.resultType == result.EntityResult: entity = result.getEntity(self.editorSession.currentDimension) if entity is not None: self.editorSession.zoomAndInspectEntity(entity) # xxxxxxx!!! else: log.error("Entity not found for result %s", str(result)) if result.resultType == result.TileEntityResult: self.editorSession.zoomAndInspectBlock(result.position) def find(self): searchNames = self.widget.searchNameCheckbox.isChecked() targetName = self.widget.nameField.text() searchValues = self.widget.searchValueCheckbox.isChecked() targetValue = self.widget.valueField.text() searchEntities = self.widget.searchEntitiesCheckbox.isChecked() targetEntityIDs = self.widget.entityIDField.text() if len(targetEntityIDs): targetEntityIDs = targetEntityIDs.split(';') searchTileEntities = self.widget.searchTileEntitiesCheckbox.isChecked() targetTileEntityIDs = self.widget.tileEntityIDField.text() if len(targetTileEntityIDs): targetTileEntityIDs = targetTileEntityIDs.split(';') if not any((searchNames, searchValues, searchEntities, searchTileEntities)): # Nothing to find return dim = self.editorSession.currentDimension inSelection = self.widget.inSelectionCheckbox.isChecked() if inSelection: selection = self.editorSession.currentSelection if selection is None: return else: selection = dim.bounds def _matchTag(name_or_index, tag): if searchValues and not tag.isCompound() and not tag.isList(): if tag.tagID == nbt.ID_STRING and targetValue in tag.value: return True elif targetValue == tag.value: return True if searchNames and isinstance(name_or_index, basestring) and targetName in name_or_index: return True return False def _findTag(name_or_index, tag, path): if _matchTag(name_or_index, tag): if tag.isCompound(): value = "Compound" # describeCompound elif tag.isList(): value = "List" # describeList else: value = str(tag.value) return str(name_or_index), path, value def _findEntitiesInChunk(chunk): for entity in chunk.Entities: if entity.Position not in selection: continue if len(targetEntityIDs) and entity.id not in targetEntityIDs: continue try: uuid = entity.UUID except KeyError: uuid = None # Don't want to use find/replace on entities without UUIDs if not searchNames and not searchValues: # Finding entities only self.resultsModel.addEntry(tagName="id", value=entity.id, id=entity.id, path=[], position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult) continue tag = entity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry(tagName=name, value=value, id=entity.id, path=path, position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult) def _findTileEntitiesInChunk(chunk): for tileEntity in chunk.TileEntities: if tileEntity.Position not in selection: continue if len(targetTileEntityIDs) and tileEntity.id not in targetTileEntityIDs: continue if not searchNames and not searchValues: # Finding tile entities only self.resultsModel.addEntry(tagName="id", value=tileEntity.id, id=tileEntity.id, path=[], position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult) continue tag = tileEntity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry(tagName=name, value=value, id=tileEntity.id, path=path, position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult) def _find(): self.resultsDockWidget.show() self.resultsModel.clear() self.dialog.accept() self.resultsWidget.findAgainButton.setEnabled(False) self.resultsWidget.progressBar.setMaximum(selection.chunkCount-1) for i, cPos in enumerate(selection.chunkPositions()): if dim.containsChunk(*cPos): chunk = dim.getChunk(*cPos) if searchEntities: _findEntitiesInChunk(chunk) if searchTileEntities: _findTileEntitiesInChunk(chunk) yield self.resultsWidget.progressBar.setValue(i) self.stop() finder = _find() def find(): try: finder.next() except StopIteration: pass self.findTimer = QtCore.QTimer(timeout=find, interval=1.0) self.findTimer.start() self.resultsWidget.stopButton.setEnabled(True) def stop(self): if self.findTimer: self.findTimer.stop() self.widget.findButton.setEnabled(True) self.resultsWidget.stopButton.setEnabled(False) self.resultsWidget.findAgainButton.setEnabled(True) 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 replaceAll(self): self.replaceEntries(self.resultsModel.results) def replaceSelected(self): pass
class FindReplaceNBT(QtCore.QObject): def __init__(self, editorSession, dialog): super(FindReplaceNBT, self).__init__() self.editorSession = editorSession self.widget = load_ui("find_replace_nbt.ui") self.dialog = dialog self.resultsWidget = load_ui("find_replace_nbt_results.ui") self.resultsDockWidget = MCEDockWidget("NBT Search", objectName="nbtSearch") self.resultsDockWidget.setWidget(self.resultsWidget) self.resultsDockWidget.hide() self.resultsModel = NBTResultsModel() self.resultsWidget.resultsView.setModel(self.resultsModel) self.resultsWidget.resultsView.clicked.connect( self.resultsViewIndexClicked) # --- Buttons --- self.widget.findButton.clicked.connect(self.find) self.resultsWidget.stopButton.clicked.connect(self.stop) self.resultsWidget.findAgainButton.clicked.connect(dialog.exec_) self.resultsWidget.replaceSelectedButton.clicked.connect( self.replaceSelected) self.resultsWidget.replaceAllButton.clicked.connect(self.replaceAll) self.widget.searchNameCheckbox.toggled.connect(self.searchForToggled) self.widget.searchValueCheckbox.toggled.connect(self.searchForToggled) self.findTimer = None self.finder = None # --- Search for... --- self.widget.nameField.setText(nbtReplaceSettings.nameField.value("")) self.widget.searchNameCheckbox.setChecked( len(self.widget.nameField.text()) > 0) self.widget.nameField.textChanged.connect(self.nameFieldChanged) self.widget.valueField.setText(nbtReplaceSettings.valueField.value("")) self.widget.searchValueCheckbox.setChecked( len(self.widget.valueField.text()) > 0) self.widget.valueField.textChanged.connect(self.valueFieldChanged) # --- Search in... --- self.widget.searchEntitiesCheckbox.setChecked( nbtReplaceSettings.searchEntitiesChecked.value()) self.widget.searchEntitiesCheckbox.toggled.connect( nbtReplaceSettings.searchEntitiesChecked.setValue) self.widget.entityIDField.setText( nbtReplaceSettings.entityIDField.value()) self.widget.entityIDField.textChanged.connect( self.entityIDFieldChanged) self.widget.searchTileEntitiesCheckbox.setChecked( nbtReplaceSettings.searchTileEntitiesChecked.value()) self.widget.searchTileEntitiesCheckbox.toggled.connect( nbtReplaceSettings.searchTileEntitiesChecked.setValue) self.widget.tileEntityIDField.setText( nbtReplaceSettings.tileEntityIDField.value()) self.widget.tileEntityIDField.textChanged.connect( self.tileEntityIDFieldChanged) # --- Replace with... --- self.widget.replaceNameField.setText( nbtReplaceSettings.replaceNameField.value()) self.resultsWidget.replaceNameField.setText( nbtReplaceSettings.replaceNameField.value()) self.widget.replaceNameField.textChanged.connect( self.replaceNameFieldChanged) self.widget.replaceNameCheckbox.setChecked( len(self.widget.replaceNameField.text())) self.resultsWidget.replaceNameCheckbox.setChecked( len(self.widget.replaceNameField.text())) self.widget.replaceValueField.setText( nbtReplaceSettings.replaceValueField.value()) self.resultsWidget.replaceValueField.setText( nbtReplaceSettings.replaceValueField.value()) self.widget.replaceValueField.textChanged.connect( self.replaceValueFieldChanged) self.widget.replaceValueCheckbox.setChecked( len(self.widget.replaceValueField.text())) self.resultsWidget.replaceValueCheckbox.setChecked( len(self.widget.replaceValueField.text())) self.widget.replaceValueTagTypeComboBox.setCurrentIndex( nbtReplaceSettings.replaceValueTagType.value()) self.widget.replaceValueTagTypeComboBox.currentIndexChanged[ int].connect(self.valueTagTypeChanged) def dialogOpened(self): currentSelection = self.editorSession.currentSelection self.widget.inSelectionCheckbox.setChecked( currentSelection is not None and currentSelection.volume > 0) def searchForToggled(self): #canSearch = self.widget.searchNameCheckbox.isChecked() or self.widget.searchValueCheckbox.isChecked() #self.widget.findButton.setEnabled(canSearch) pass def nameFieldChanged(self, value): nbtReplaceSettings.nameField.setValue(value) self.widget.searchNameCheckbox.setChecked(len(value) > 0) def valueFieldChanged(self, value): nbtReplaceSettings.valueField.setValue(value) self.widget.searchValueCheckbox.setChecked(len(value) > 0) def entityIDFieldChanged(self, value): nbtReplaceSettings.entityIDField.setValue(value) if len(value): self.widget.searchEntitiesCheckbox.setChecked(True) def tileEntityIDFieldChanged(self, value): nbtReplaceSettings.tileEntityIDField.setValue(value) if len(value): self.widget.searchTileEntitiesCheckbox.setChecked(True) def replaceNameFieldChanged(self, value): if value != nbtReplaceSettings.replaceNameField.value(): nbtReplaceSettings.replaceNameField.setValue(value) self.widget.replaceNameCheckbox.setChecked(len(value) > 0) self.widget.replaceNameField.setText(value) self.resultsWidget.replaceNameCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceNameField.setText(value) def replaceValueFieldChanged(self, value): if value != nbtReplaceSettings.replaceValueField.value(): nbtReplaceSettings.replaceValueField.setValue(value) self.widget.replaceValueCheckbox.setChecked(len(value) > 0) self.widget.replaceValueField.setText(value) self.resultsWidget.replaceValueCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceValueField.setText(value) def valueTagTypeChanged(self, index): if index != nbtReplaceSettings.replaceValueTagType.value(): nbtReplaceSettings.replaceValueTagType.setValue(index) self.widget.replaceValueTagTypeComboBox.setCurrentIndex(index) self.resultsWidget.replaceValueTagTypeComboBox.setCurrentIndex( index) def resultsViewIndexClicked(self, modelIndex): row = modelIndex.row() result = self.resultsModel.results[row] if result.resultType == result.EntityResult: entity = result.getEntity(self.editorSession.currentDimension) if entity is not None: self.editorSession.zoomAndInspectEntity(entity) # xxxxxxx!!! else: log.error("Entity not found for result %s", str(result)) if result.resultType == result.TileEntityResult: self.editorSession.zoomAndInspectBlock(result.position) def find(self): searchNames = self.widget.searchNameCheckbox.isChecked() targetName = self.widget.nameField.text() searchValues = self.widget.searchValueCheckbox.isChecked() targetValue = self.widget.valueField.text() searchEntities = self.widget.searchEntitiesCheckbox.isChecked() targetEntityIDs = self.widget.entityIDField.text() if len(targetEntityIDs): targetEntityIDs = targetEntityIDs.split(';') searchTileEntities = self.widget.searchTileEntitiesCheckbox.isChecked() targetTileEntityIDs = self.widget.tileEntityIDField.text() if len(targetTileEntityIDs): targetTileEntityIDs = targetTileEntityIDs.split(';') if not any( (searchNames, searchValues, searchEntities, searchTileEntities)): # Nothing to find return dim = self.editorSession.currentDimension inSelection = self.widget.inSelectionCheckbox.isChecked() if inSelection: selection = self.editorSession.currentSelection if selection is None: return else: selection = dim.bounds def _matchTag(name_or_index, tag): if searchValues and not tag.isCompound() and not tag.isList(): if tag.tagID == nbt.ID_STRING and targetValue in tag.value: return True elif targetValue == tag.value: return True if searchNames and isinstance( name_or_index, basestring) and targetName in name_or_index: return True return False def _findTag(name_or_index, tag, path): if _matchTag(name_or_index, tag): if tag.isCompound(): value = "Compound" # describeCompound elif tag.isList(): value = "List" # describeList else: value = str(tag.value) return str(name_or_index), path, value def _findEntitiesInChunk(chunk): for entity in chunk.Entities: if entity.Position not in selection: continue if len(targetEntityIDs) and entity.id not in targetEntityIDs: continue try: uuid = entity.UUID except KeyError: uuid = None # Don't want to use find/replace on entities without UUIDs if not searchNames and not searchValues: # Finding entities only self.resultsModel.addEntry( tagName="id", value=entity.id, id=entity.id, path=[], position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult) continue tag = entity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry( tagName=name, value=value, id=entity.id, path=path, position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult) def _findTileEntitiesInChunk(chunk): for tileEntity in chunk.TileEntities: if tileEntity.Position not in selection: continue if len(targetTileEntityIDs ) and tileEntity.id not in targetTileEntityIDs: continue if not searchNames and not searchValues: # Finding tile entities only self.resultsModel.addEntry( tagName="id", value=tileEntity.id, id=tileEntity.id, path=[], position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult) continue tag = tileEntity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry( tagName=name, value=value, id=tileEntity.id, path=path, position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult) def _find(): self.resultsDockWidget.show() self.resultsModel.clear() self.dialog.accept() self.resultsWidget.findAgainButton.setEnabled(False) self.resultsWidget.progressBar.setMaximum(selection.chunkCount - 1) for i, cPos in enumerate(selection.chunkPositions()): if dim.containsChunk(*cPos): chunk = dim.getChunk(*cPos) if searchEntities: _findEntitiesInChunk(chunk) if searchTileEntities: _findTileEntitiesInChunk(chunk) yield self.resultsWidget.progressBar.setValue(i) self.stop() finder = _find() def find(): try: finder.next() except StopIteration: pass self.findTimer = QtCore.QTimer(timeout=find, interval=1.0) self.findTimer.start() self.resultsWidget.stopButton.setEnabled(True) def stop(self): if self.findTimer: self.findTimer.stop() self.widget.findButton.setEnabled(True) self.resultsWidget.stopButton.setEnabled(False) self.resultsWidget.findAgainButton.setEnabled(True) 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 replaceAll(self): self.replaceEntries(self.resultsModel.results) def replaceSelected(self): pass
class FindReplaceNBT(QtGui.QWidget, Ui_findNBTWidget): def __init__(self, editorSession, dialog): super(FindReplaceNBT, self).__init__() self.editorSession = editorSession self.setupUi(self) self.dialog = dialog self.resultsWidget = FindReplaceNBTResults() self.resultsWidget.setupUi(self.resultsWidget) self.resultsDockWidget = MCEDockWidget("NBT Search", objectName="nbtSearch") self.resultsDockWidget.setWidget(self.resultsWidget) self.resultsDockWidget.hide() self.resultsModel = NBTResultsModel() self.resultsWidget.resultsView.setModel(self.resultsModel) self.resultsWidget.resultsView.clicked.connect( self.resultsViewIndexClicked) # --- Buttons --- self.findButton.clicked.connect(self.find) self.resultsWidget.stopButton.clicked.connect(self.stop) self.resultsWidget.findAgainButton.clicked.connect(dialog.exec_) self.resultsWidget.replaceSelectedButton.clicked.connect( self.replaceSelected) self.resultsWidget.replaceAllButton.clicked.connect(self.replaceAll) self.resultsWidget.removeSelectedButton.clicked.connect( self.removeSelected) self.resultsWidget.removeAllButton.clicked.connect(self.removeAll) self.resultsWidget.replaceSelectedButton.setEnabled( not self.editorSession.readonly) self.resultsWidget.replaceAllButton.setEnabled( not self.editorSession.readonly) self.resultsWidget.removeSelectedButton.setEnabled( not self.editorSession.readonly) self.resultsWidget.removeAllButton.setEnabled( not self.editorSession.readonly) self.searchNameCheckbox.toggled.connect(self.searchForToggled) self.searchValueCheckbox.toggled.connect(self.searchForToggled) self.findTimer = None self.finder = None # --- Search for... --- self.nameField.setText(nbtReplaceSettings.nameField.value("")) self.searchNameCheckbox.setChecked(len(self.nameField.text()) > 0) self.nameField.textChanged.connect(self.nameFieldChanged) self.valueField.setText(nbtReplaceSettings.valueField.value("")) self.searchValueCheckbox.setChecked(len(self.valueField.text()) > 0) self.valueField.textChanged.connect(self.valueFieldChanged) # --- Search in... --- self.searchEntitiesCheckbox.setChecked( nbtReplaceSettings.searchEntitiesChecked.value()) self.searchEntitiesCheckbox.toggled.connect( nbtReplaceSettings.searchEntitiesChecked.setValue) self.entityIDField.setText(nbtReplaceSettings.entityIDField.value()) self.entityIDField.textChanged.connect(self.entityIDFieldChanged) self.searchTileEntitiesCheckbox.setChecked( nbtReplaceSettings.searchTileEntitiesChecked.value()) self.searchTileEntitiesCheckbox.toggled.connect( nbtReplaceSettings.searchTileEntitiesChecked.setValue) self.tileEntityIDField.setText( nbtReplaceSettings.tileEntityIDField.value()) self.tileEntityIDField.textChanged.connect( self.tileEntityIDFieldChanged) self.searchPlayersCheckbox.setChecked( nbtReplaceSettings.searchPlayersChecked.value()) self.searchPlayersCheckbox.toggled.connect( nbtReplaceSettings.searchPlayersChecked.setValue) self.searchChunksCheckbox.setChecked( nbtReplaceSettings.searchChunksChecked.value()) self.searchChunksCheckbox.toggled.connect( nbtReplaceSettings.searchChunksChecked.setValue) # --- Replace with... --- self.replaceNameField.setText( nbtReplaceSettings.replaceNameField.value()) self.resultsWidget.replaceNameField.setText( nbtReplaceSettings.replaceNameField.value()) self.replaceNameField.textChanged.connect(self.replaceNameFieldChanged) self.resultsWidget.replaceNameField.textChanged.connect( self.replaceNameFieldChanged) self.replaceNameCheckbox.setChecked(len(self.replaceNameField.text())) self.resultsWidget.replaceNameCheckbox.setChecked( len(self.replaceNameField.text())) self.replaceNameCheckbox.toggled.connect(self.replaceNameToggled) self.resultsWidget.replaceNameCheckbox.toggled.connect( self.replaceNameToggled) self.replaceValueField.setText( nbtReplaceSettings.replaceValueField.value()) self.resultsWidget.replaceValueField.setText( nbtReplaceSettings.replaceValueField.value()) self.replaceValueField.textChanged.connect( self.replaceValueFieldChanged) self.resultsWidget.replaceValueField.textChanged.connect( self.replaceValueFieldChanged) self.replaceValueCheckbox.setChecked(len( self.replaceValueField.text())) self.resultsWidget.replaceValueCheckbox.setChecked( len(self.replaceValueField.text())) self.replaceValueCheckbox.toggled.connect(self.replaceValueToggled) self.resultsWidget.replaceValueCheckbox.toggled.connect( self.replaceValueToggled) self.replaceValueTagTypeComboBox.setCurrentIndex( nbtReplaceSettings.replaceValueTagType.value()) self.replaceValueTagTypeComboBox.currentIndexChanged[int].connect( self.valueTagTypeChanged) def dialogOpened(self): currentSelection = self.editorSession.currentSelection self.inSelectionCheckbox.setChecked(currentSelection is not None and currentSelection.volume > 0) def searchForToggled(self): #canSearch = self.searchNameCheckbox.isChecked() or self.searchValueCheckbox.isChecked() #self.findButton.setEnabled(canSearch) pass def nameFieldChanged(self, value): nbtReplaceSettings.nameField.setValue(value) self.searchNameCheckbox.setChecked(len(value) > 0) def valueFieldChanged(self, value): nbtReplaceSettings.valueField.setValue(value) self.searchValueCheckbox.setChecked(len(value) > 0) def entityIDFieldChanged(self, value): nbtReplaceSettings.entityIDField.setValue(value) if len(value): self.searchEntitiesCheckbox.setChecked(True) def tileEntityIDFieldChanged(self, value): nbtReplaceSettings.tileEntityIDField.setValue(value) if len(value): self.searchTileEntitiesCheckbox.setChecked(True) def replaceNameFieldChanged(self, value): if value != nbtReplaceSettings.replaceNameField.value(): nbtReplaceSettings.replaceNameField.setValue(value) self.resultsWidget.replaceNameCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceNameField.setText(value) self.replaceNameCheckbox.setChecked(len(value) > 0) self.replaceNameField.setText(value) def replaceValueFieldChanged(self, value): if value != nbtReplaceSettings.replaceValueField.value(): nbtReplaceSettings.replaceValueField.setValue(value) self.resultsWidget.replaceValueCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceValueField.setText(value) self.replaceValueCheckbox.setChecked(len(value) > 0) self.replaceValueField.setText(value) def replaceNameToggled(self, enabled): if enabled != nbtReplaceSettings.replaceNameEnabled.Name(): nbtReplaceSettings.replaceNameEnabled.setName(enabled) self.resultsWidget.replaceNameCheckbox.setChecked(enabled) self.replaceNameCheckbox.setChecked(enabled) def replaceValueToggled(self, enabled): if enabled != nbtReplaceSettings.replaceValueEnabled.value(): nbtReplaceSettings.replaceValueEnabled.setValue(enabled) self.resultsWidget.replaceValueCheckbox.setChecked(enabled) self.replaceValueCheckbox.setChecked(enabled) def valueTagTypeChanged(self, index): if index != nbtReplaceSettings.replaceValueTagType.value(): nbtReplaceSettings.replaceValueTagType.setValue(index) self.replaceValueTagTypeComboBox.setCurrentIndex(index) self.replaceValueTagTypeComboBox.setCurrentIndex(index) def resultsViewIndexClicked(self, modelIndex): row = modelIndex.row() result = self.resultsModel.results[row] if result.resultType == result.EntityResult: entityPtr = result.getEntityPtr() self.editorSession.zoomAndInspectEntity(entityPtr) if result.resultType == result.TileEntityResult: self.editorSession.zoomAndInspectBlock(result.position) if result.resultType == result.ChunkResult: self.editorSession.zoomAndInspectChunk(result.position) def find(self): searchNames = self.searchNameCheckbox.isChecked() targetName = self.nameField.text() searchValues = self.searchValueCheckbox.isChecked() targetValue = self.valueField.text() searchEntities = self.searchEntitiesCheckbox.isChecked() targetEntityIDs = self.entityIDField.text() if len(targetEntityIDs): targetEntityIDs = targetEntityIDs.split(';') searchTileEntities = self.searchTileEntitiesCheckbox.isChecked() targetTileEntityIDs = self.tileEntityIDField.text() if len(targetTileEntityIDs): targetTileEntityIDs = targetTileEntityIDs.split(';') searchChunks = self.searchChunksCheckbox.isChecked() if not any((searchNames, searchValues, searchEntities, searchTileEntities, searchChunks)): # Nothing to find return dim = self.editorSession.currentDimension inSelection = self.inSelectionCheckbox.isChecked() if inSelection: selection = self.editorSession.currentSelection if selection is None: return else: selection = dim.bounds def _matchTag(name_or_index, tag): ok = True if searchValues and not tag.isCompound() and not tag.isList(): if not (tag.tagID == nbt.ID_STRING and targetValue in tag.value): ok = False elif not (targetValue == tag.value): ok = False if searchNames and isinstance( name_or_index, basestring) and not (targetName == name_or_index): ok = False return ok def _findTag(name_or_index, tag, path): if _matchTag(name_or_index, tag): if tag.isCompound(): value = "Compound" # describeCompound elif tag.isList(): value = "List" # describeList else: value = unicode(tag.value) return str(name_or_index), path, value def _findEntitiesInChunk(chunk): for entity in chunk.Entities: if entity.Position not in selection: continue if len(targetEntityIDs) and entity.id not in targetEntityIDs: continue try: uuid = entity.UUID except KeyError: uuid = None # Don't want to use find/replace on entities without UUIDs if not searchNames and not searchValues: # Finding entities only self.resultsModel.addEntry( tagName="id", value=entity.id, ID=entity.id, path=[], position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult, dimension=self.editorSession.currentDimension) continue tag = entity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry( tagName=name, value=value, ID=entity.id, path=path, position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult, dimension=self.editorSession.currentDimension) def _findTileEntitiesInChunk(chunk): for tileEntity in chunk.TileEntities: if tileEntity.Position not in selection: continue if len(targetTileEntityIDs ) and tileEntity.id not in targetTileEntityIDs: continue if not searchNames and not searchValues: # Finding tile entities only self.resultsModel.addEntry( tagName="id", value=tileEntity.id, ID=tileEntity.id, path=[], position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult, dimension=self.editorSession.currentDimension) continue tag = tileEntity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry( tagName=name, value=value, ID=tileEntity.id, path=path, position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult, dimension=self.editorSession.currentDimension) def _findInChunk(chunk): tag = chunk.rootTag for name, subtag, path in nbt.walk(tag): if len(path) >= 2 and path[0] == "Level": if path[1] in ("Entities", "TileEntities"): continue result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry( tagName=name, value=value, ID="chunk", path=path, position=chunk.chunkPosition, uuid=None, resultType=NBTResultsEntry.ChunkResult, dimension=self.editorSession.currentDimension) def _find(): self.resultsDockWidget.show() self.resultsModel.clear() self.dialog.accept() self.resultsWidget.findAgainButton.setEnabled(False) self.resultsWidget.progressBar.setMaximum(selection.chunkCount - 1) for i, cPos in enumerate(selection.chunkPositions()): if dim.containsChunk(*cPos): chunk = dim.getChunk(*cPos) if searchEntities: _findEntitiesInChunk(chunk) if searchTileEntities: _findTileEntitiesInChunk(chunk) if searchChunks: _findInChunk(chunk) yield self.resultsWidget.progressBar.setValue(i) self.stop() finder = _find() def find(): try: finder.next() except StopIteration: pass self.findTimer = QtCore.QTimer(timeout=find, interval=1.0) self.findTimer.start() self.resultsWidget.stopButton.setEnabled(True) def stop(self): if self.findTimer: self.findTimer.stop() self.findButton.setEnabled(True) self.resultsWidget.stopButton.setEnabled(False) self.resultsWidget.findAgainButton.setEnabled(True) 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 replaceAll(self): self.replaceEntries(self.resultsModel.results) def replaceSelected(self): entries = [] for index in self.resultsWidget.resultsView.selectedIndexes(): entries.append(self.resultsModel.data(index, role=Qt.UserRole)) self.replaceEntries(entries) 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 removeAll(self): self.removeEntries(self.resultsModel.results) def removeSelected(self): entries = [] for index in self.resultsWidget.resultsView.selectedIndexes(): entries.append(self.resultsModel.data(index, role=Qt.UserRole)) self.removeEntries(entries)
class FindReplaceNBT(QtGui.QWidget, Ui_findNBTWidget): def __init__(self, editorSession, dialog): super(FindReplaceNBT, self).__init__() self.editorSession = editorSession self.setupUi(self) self.dialog = dialog self.resultsWidget = FindReplaceNBTResults() self.resultsWidget.setupUi(self.resultsWidget) self.resultsDockWidget = MCEDockWidget("NBT Search", objectName="nbtSearch") self.resultsDockWidget.setWidget(self.resultsWidget) self.resultsDockWidget.hide() self.resultsModel = NBTResultsModel() self.resultsWidget.resultsView.setModel(self.resultsModel) self.resultsWidget.resultsView.clicked.connect(self.resultsViewIndexClicked) # --- Buttons --- self.findButton.clicked.connect(self.find) self.resultsWidget.stopButton.clicked.connect(self.stop) self.resultsWidget.findAgainButton.clicked.connect(dialog.exec_) self.resultsWidget.replaceSelectedButton.clicked.connect(self.replaceSelected) self.resultsWidget.replaceAllButton.clicked.connect(self.replaceAll) self.resultsWidget.removeSelectedButton.clicked.connect(self.removeSelected) self.resultsWidget.removeAllButton.clicked.connect(self.removeAll) self.resultsWidget.replaceSelectedButton.setEnabled(not self.editorSession.readonly) self.resultsWidget.replaceAllButton.setEnabled(not self.editorSession.readonly) self.resultsWidget.removeSelectedButton.setEnabled(not self.editorSession.readonly) self.resultsWidget.removeAllButton.setEnabled(not self.editorSession.readonly) self.searchNameCheckbox.toggled.connect(self.searchForToggled) self.searchValueCheckbox.toggled.connect(self.searchForToggled) self.findTimer = None self.finder = None # --- Search for... --- self.nameField.setText(nbtReplaceSettings.nameField.value("")) self.searchNameCheckbox.setChecked(len(self.nameField.text()) > 0) self.nameField.textChanged.connect(self.nameFieldChanged) self.valueField.setText(nbtReplaceSettings.valueField.value("")) self.searchValueCheckbox.setChecked(len(self.valueField.text()) > 0) self.valueField.textChanged.connect(self.valueFieldChanged) # --- Search in... --- self.searchEntitiesCheckbox.setChecked(nbtReplaceSettings.searchEntitiesChecked.value()) self.searchEntitiesCheckbox.toggled.connect(nbtReplaceSettings.searchEntitiesChecked.setValue) self.entityIDField.setText(nbtReplaceSettings.entityIDField.value()) self.entityIDField.textChanged.connect(self.entityIDFieldChanged) self.searchTileEntitiesCheckbox.setChecked(nbtReplaceSettings.searchTileEntitiesChecked.value()) self.searchTileEntitiesCheckbox.toggled.connect(nbtReplaceSettings.searchTileEntitiesChecked.setValue) self.tileEntityIDField.setText(nbtReplaceSettings.tileEntityIDField.value()) self.tileEntityIDField.textChanged.connect(self.tileEntityIDFieldChanged) self.searchPlayersCheckbox.setChecked(nbtReplaceSettings.searchPlayersChecked.value()) self.searchPlayersCheckbox.toggled.connect(nbtReplaceSettings.searchPlayersChecked.setValue) self.searchChunksCheckbox.setChecked(nbtReplaceSettings.searchChunksChecked.value()) self.searchChunksCheckbox.toggled.connect(nbtReplaceSettings.searchChunksChecked.setValue) # --- Replace with... --- self.replaceNameField.setText(nbtReplaceSettings.replaceNameField.value()) self.resultsWidget.replaceNameField.setText(nbtReplaceSettings.replaceNameField.value()) self.replaceNameField.textChanged.connect(self.replaceNameFieldChanged) self.resultsWidget.replaceNameField.textChanged.connect(self.replaceNameFieldChanged) self.replaceNameCheckbox.setChecked(len(self.replaceNameField.text())) self.resultsWidget.replaceNameCheckbox.setChecked(len(self.replaceNameField.text())) self.replaceNameCheckbox.toggled.connect(self.replaceNameToggled) self.resultsWidget.replaceNameCheckbox.toggled.connect(self.replaceNameToggled) self.replaceValueField.setText(nbtReplaceSettings.replaceValueField.value()) self.resultsWidget.replaceValueField.setText(nbtReplaceSettings.replaceValueField.value()) self.replaceValueField.textChanged.connect(self.replaceValueFieldChanged) self.resultsWidget.replaceValueField.textChanged.connect(self.replaceValueFieldChanged) self.replaceValueCheckbox.setChecked(len(self.replaceValueField.text())) self.resultsWidget.replaceValueCheckbox.setChecked(len(self.replaceValueField.text())) self.replaceValueCheckbox.toggled.connect(self.replaceValueToggled) self.resultsWidget.replaceValueCheckbox.toggled.connect(self.replaceValueToggled) self.replaceValueTagTypeComboBox.setCurrentIndex(nbtReplaceSettings.replaceValueTagType.value()) self.replaceValueTagTypeComboBox.currentIndexChanged[int].connect(self.valueTagTypeChanged) def dialogOpened(self): currentSelection = self.editorSession.currentSelection self.inSelectionCheckbox.setChecked(currentSelection is not None and currentSelection.volume > 0) def searchForToggled(self): #canSearch = self.searchNameCheckbox.isChecked() or self.searchValueCheckbox.isChecked() #self.findButton.setEnabled(canSearch) pass def nameFieldChanged(self, value): nbtReplaceSettings.nameField.setValue(value) self.searchNameCheckbox.setChecked(len(value) > 0) def valueFieldChanged(self, value): nbtReplaceSettings.valueField.setValue(value) self.searchValueCheckbox.setChecked(len(value) > 0) def entityIDFieldChanged(self, value): nbtReplaceSettings.entityIDField.setValue(value) if len(value): self.searchEntitiesCheckbox.setChecked(True) def tileEntityIDFieldChanged(self, value): nbtReplaceSettings.tileEntityIDField.setValue(value) if len(value): self.searchTileEntitiesCheckbox.setChecked(True) def replaceNameFieldChanged(self, value): if value != nbtReplaceSettings.replaceNameField.value(): nbtReplaceSettings.replaceNameField.setValue(value) self.resultsWidget.replaceNameCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceNameField.setText(value) self.replaceNameCheckbox.setChecked(len(value) > 0) self.replaceNameField.setText(value) def replaceValueFieldChanged(self, value): if value != nbtReplaceSettings.replaceValueField.value(): nbtReplaceSettings.replaceValueField.setValue(value) self.resultsWidget.replaceValueCheckbox.setChecked(len(value) > 0) self.resultsWidget.replaceValueField.setText(value) self.replaceValueCheckbox.setChecked(len(value) > 0) self.replaceValueField.setText(value) def replaceNameToggled(self, enabled): if enabled != nbtReplaceSettings.replaceNameEnabled.Name(): nbtReplaceSettings.replaceNameEnabled.setName(enabled) self.resultsWidget.replaceNameCheckbox.setChecked(enabled) self.replaceNameCheckbox.setChecked(enabled) def replaceValueToggled(self, enabled): if enabled != nbtReplaceSettings.replaceValueEnabled.value(): nbtReplaceSettings.replaceValueEnabled.setValue(enabled) self.resultsWidget.replaceValueCheckbox.setChecked(enabled) self.replaceValueCheckbox.setChecked(enabled) def valueTagTypeChanged(self, index): if index != nbtReplaceSettings.replaceValueTagType.value(): nbtReplaceSettings.replaceValueTagType.setValue(index) self.replaceValueTagTypeComboBox.setCurrentIndex(index) self.replaceValueTagTypeComboBox.setCurrentIndex(index) def resultsViewIndexClicked(self, modelIndex): row = modelIndex.row() result = self.resultsModel.results[row] if result.resultType == result.EntityResult: entityPtr = result.getEntityPtr() self.editorSession.zoomAndInspectEntity(entityPtr) if result.resultType == result.TileEntityResult: self.editorSession.zoomAndInspectBlock(result.position) if result.resultType == result.ChunkResult: self.editorSession.zoomAndInspectChunk(result.position) def find(self): searchNames = self.searchNameCheckbox.isChecked() targetName = self.nameField.text() searchValues = self.searchValueCheckbox.isChecked() targetValue = self.valueField.text() searchEntities = self.searchEntitiesCheckbox.isChecked() targetEntityIDs = self.entityIDField.text() if len(targetEntityIDs): targetEntityIDs = targetEntityIDs.split(';') searchTileEntities = self.searchTileEntitiesCheckbox.isChecked() targetTileEntityIDs = self.tileEntityIDField.text() if len(targetTileEntityIDs): targetTileEntityIDs = targetTileEntityIDs.split(';') searchChunks = self.searchChunksCheckbox.isChecked() if not any((searchNames, searchValues, searchEntities, searchTileEntities, searchChunks)): # Nothing to find return dim = self.editorSession.currentDimension inSelection = self.inSelectionCheckbox.isChecked() if inSelection: selection = self.editorSession.currentSelection if selection is None: return else: selection = dim.bounds def _matchTag(name_or_index, tag): ok = True if searchValues and not tag.isCompound() and not tag.isList(): if not (tag.tagID == nbt.ID_STRING and targetValue in tag.value): ok = False elif not (targetValue == tag.value): ok = False if searchNames: if not isinstance(name_or_index, basestring): ok = False elif (targetName == name_or_index): ok = True else: ok = False return ok def _findTag(name_or_index, tag, path): if _matchTag(name_or_index, tag): if tag.isCompound(): value = "Compound" # describeCompound elif tag.isList(): value = "List" # describeList else: value = unicode(tag.value) return str(name_or_index), path, value def _findEntitiesInChunk(chunk): for entity in chunk.Entities: if entity.Position not in selection: continue if len(targetEntityIDs) and entity.id not in targetEntityIDs: continue try: uuid = entity.UUID except KeyError: uuid = None # Don't want to use find/replace on entities without UUIDs if not searchNames and not searchValues: # Finding entities only self.resultsModel.addEntry(tagName="id", value=entity.id, ID=entity.id, path=[], position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult, dimension=self.editorSession.currentDimension) continue tag = entity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry(tagName=name, value=value, ID=entity.id, path=path, position=entity.Position, uuid=uuid, resultType=NBTResultsEntry.EntityResult, dimension=self.editorSession.currentDimension) def _findTileEntitiesInChunk(chunk): for tileEntity in chunk.TileEntities: if tileEntity.Position not in selection: continue if len(targetTileEntityIDs) and tileEntity.id not in targetTileEntityIDs: continue if not searchNames and not searchValues: # Finding tile entities only self.resultsModel.addEntry(tagName="id", value=tileEntity.id, ID=tileEntity.id, path=[], position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult, dimension=self.editorSession.currentDimension) continue tag = tileEntity.raw_tag() for name, subtag, path in nbt.walk(tag): result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry(tagName=name, value=value, ID=tileEntity.id, path=path, position=tileEntity.Position, uuid=None, resultType=NBTResultsEntry.TileEntityResult, dimension=self.editorSession.currentDimension) def _findInChunk(chunk): tag = chunk.rootTag for name, subtag, path in nbt.walk(tag): if len(path) >= 2 and path[0] == "Level": if path[1] in ("Entities", "TileEntities"): continue result = _findTag(name, subtag, path) if result: name, path, value = result self.resultsModel.addEntry(tagName=name, value=value, ID="chunk", path=path, position=chunk.chunkPosition, uuid=None, resultType=NBTResultsEntry.ChunkResult, dimension=self.editorSession.currentDimension) def _find(): self.resultsDockWidget.show() self.resultsModel.clear() self.dialog.accept() self.resultsWidget.findAgainButton.setEnabled(False) self.resultsWidget.progressBar.setMaximum(selection.chunkCount-1) for i, cPos in enumerate(selection.chunkPositions()): if dim.containsChunk(*cPos): chunk = dim.getChunk(*cPos) if searchEntities: _findEntitiesInChunk(chunk) if searchTileEntities: _findTileEntitiesInChunk(chunk) if searchChunks: _findInChunk(chunk) yield self.resultsWidget.progressBar.setValue(i) self.stop() finder = _find() def find(): try: finder.next() except StopIteration: pass self.findTimer = QtCore.QTimer(timeout=find, interval=1.0) self.findTimer.start() self.resultsWidget.stopButton.setEnabled(True) def stop(self): if self.findTimer: self.findTimer.stop() self.findButton.setEnabled(True) self.resultsWidget.stopButton.setEnabled(False) self.resultsWidget.findAgainButton.setEnabled(True) 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 replaceAll(self): self.replaceEntries(self.resultsModel.results) def replaceSelected(self): entries = [] for index in self.resultsWidget.resultsView.selectedIndexes(): entries.append(self.resultsModel.data(index, role=Qt.UserRole)) self.replaceEntries(entries) 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 removeAll(self): self.removeEntries(self.resultsModel.results) def removeSelected(self): entries = [] for index in self.resultsWidget.resultsView.selectedIndexes(): entries.append(self.resultsModel.data(index, role=Qt.UserRole)) self.removeEntries(entries)