From 32b5bc95335c877464f5ef2e82a33a469493d659 Mon Sep 17 00:00:00 2001 From: RadND <69626236+RadND@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:22:52 +0800 Subject: [PATCH] =?UTF-8?q?give=E5=91=BD=E4=BB=A4=E7=94=9F=E6=88=90?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将give命令生成过程分解为多个版本的CommandGenerator,便于理解调试与后续新版本新增 --- ToolBox.py | 325 +++++++++++++++++++++++++++++------------------------ 1 file changed, 180 insertions(+), 145 deletions(-) diff --git a/ToolBox.py b/ToolBox.py index 40ea99f..120e95f 100644 --- a/ToolBox.py +++ b/ToolBox.py @@ -12,6 +12,160 @@ zoom_level_to_factor = [25,33,50,67,75,80,90,100,110,125,150,175,200,250,300,400,500] +class CommandGeneratorBase: + def __init__(self, design_name, design_size, patterns_dict, version_pattern_index): + self.design_name = design_name + self.design_size = design_size # [width, height] + self.patterns_dict = patterns_dict # {"x:y": "base:pat1:col1:pat2:col2:..."} + self.version_pattern_index = version_pattern_index # 用于检查图案支持的版本 + self.group_size = 27 + self.generated_count = 0 + self.is_over6 = False + self.is_skip = False + + def generate(self): + command = "" + for i in range(self.design_size[0] - 1, -1, -1): + for j in range(self.design_size[1]): + key = f"{i}:{j}" + if key not in self.patterns_dict: + continue + + banner_data = self.patterns_dict[key].split(":") + if len(banner_data) > 13: + self.is_over6 = True + + base_color = int(banner_data[0]) + if base_color == 16: + continue + + slot = self.generated_count % self.group_size + if slot == 0: + command += self.get_prefix() + + item_str = self.format_banner_item(banner_data, slot, (i, j)) + command += item_str + "," + + self.generated_count += 1 + + if slot == self.group_size - 1: + command += self.get_suffix() + + if self.generated_count % self.group_size != 0: + command += self.get_suffix() + return command + + # 子类必须实现 + def get_prefix(self): + """每组开头的命令前缀""" + raise NotImplementedError + + def get_suffix(self): + """每组结尾的命令后缀""" + raise NotImplementedError + + def format_banner_item(self, banner_data, slot, position): + """生成单个旗帜物品的 NBT/组件字符串""" + raise NotImplementedError + + +class CommandGenerator1_8(CommandGeneratorBase): + def get_prefix(self): + return f'/give @p minecraft:chest 1 0 {{display: {{Name: "{self.design_name}"}},BlockEntityTag:{{Items:[' + + def get_suffix(self): + return f']}}}}\n___________________________\n' + + def format_banner_item(self, banner_data, slot, position): + base_id = int(banner_data[0]) + damage = 15 - base_id + pos_str = f"{position[0]}_{position[1]}" + + item = f'{{Slot:{slot}b,id:"minecraft:banner",Damage:{damage}s,Count:1b,tag:{{display: {{Name: "{pos_str}"}}' + + pattern_types = banner_data[1::2] + pattern_colors = banner_data[2::2] + if any(x != '0' for x in pattern_types): + item += f',BlockEntityTag:{{Patterns:[' + for k in range(len(pattern_types)): + ptype = int(pattern_types[k]) + if ptype == 0: + continue + if pattern.type_support_version[ptype] <= self.version_pattern_index: + color_id = int(pattern_colors[k]) + color_value = 15 - color_id + item += f'{{Pattern:"{pattern.type[ptype]}",Color:{color_value}}},' + else: + self.is_skip = True + item += f']}}' + item += f'}}}}' + return item + +class CommandGenerator1_13(CommandGeneratorBase): + def get_prefix(self): + return f'/give @p minecraft:chest{{display: {{Name: \'{{"text":"{self.design_name}","color":"gold"}}\'}},BlockEntityTag:{{Items:[' + + def get_suffix(self): + return f']}}}}\n___________________________\n' + + def format_banner_item(self, banner_data, slot, position): + base_id = int(banner_data[0]) + color_name = pattern.color_name[base_id] + pos_str = f"{position[0]}_{position[1]}" + + item = f'{{Slot:{slot}b,id:"minecraft:{color_name}_banner",Count:1b,tag:{{display: {{Name: \'{{"text":"{pos_str}"}}\'}}' + + pattern_types = banner_data[1::2] + pattern_colors = banner_data[2::2] + if any(x != '0' for x in pattern_types): + item += f',BlockEntityTag:{{Patterns:[' + for k in range(len(pattern_types)): + ptype = int(pattern_types[k]) + if ptype == 0: + continue + if pattern.type_support_version[ptype] <= self.version_pattern_index: + color_id = int(pattern_colors[k]) + item += f'{{Pattern:"{pattern.type[ptype]}",Color:{color_id}}},' + else: + self.is_skip = True + item += f']}}' + item += f'}}}}' + return item + +class CommandGenerator1_20_5(CommandGeneratorBase): + # 可用指令示例 give @p chest[custom_name='{text:"bbb",color:"gold"}',container=[{slot:0,item:{id:"red_banner",components:{custom_name:"1_1",banner_patterns:[{pattern:"stripe_top",color:"white"}]}}}]] 1 + def get_prefix(self): + return f'/give @p chest[custom_name=\'{{"text":"{self.design_name}","color":"gold"}}\',container=[' + + def get_suffix(self): + return f']]\n___________________________\n' + + def format_banner_item(self, banner_data, slot, position): + base_id = int(banner_data[0]) + color_name = pattern.color_name[base_id] + pos_str = f"{position[0]}_{position[1]}" + + item = f'{{slot:{slot},item:{{id:"{color_name}_banner",components:{{custom_name:"{pos_str}"' + + pattern_types = banner_data[1::2] + pattern_colors = banner_data[2::2] + if any(x != '0' for x in pattern_types): + item += f',banner_patterns:[' + for k in range(len(pattern_types)): + ptype = int(pattern_types[k]) + if ptype == 0: + continue + if pattern.type_support_version[ptype] <= self.version_pattern_index: + color_id = int(pattern_colors[k]) + color_name_pat = pattern.color_name[color_id] + item += f"{{pattern:'{pattern.advanced_type[ptype]}',color:{color_name_pat}}}," + else: + self.is_skip = True + item += f"]" + item += f'}}}}}}' + return item + + class ToolBox(QWidget): LoadDesign = pyqtSignal() UpdateZoom = pyqtSignal(float, bool) # zoom_factor, real_margin @@ -276,153 +430,34 @@ def SetDefaultBackgroundColor(self, color_id: int): self.ui.ViewBackgroundBlueSchollbar.setValue(pattern.color[pattern.color_name[color_id]][2]) def GenerateCommand(self): - '''生成指令''' - command = "" - generated_num = 0 - isover6 = False # 是否有>6次染色的旗帜 - isskip = False # 是否有跳过的图案 - - if self.ui.VersionCmdSelectComboBox.currentIndex() == 0: # 1.8~1.13 - for i in range(DataStorage.get_instance().current_design_size[0] - 1): - _i = DataStorage.get_instance().current_design_size[0] - i - 1 - for j in range(DataStorage.get_instance().current_design_size[1]): - # 旗帜属性 - if f"{_i}:{j}" not in DataStorage.get_instance().current_design_patterns: - continue - now_banner = DataStorage.get_instance().current_design_patterns[f"{_i}:{j}"].split(":") - if(len(now_banner) > 13): - isover6 = True - - if now_banner[0] != "16": - if generated_num % 27 == 0: - # 指令前缀, 缩进似乎会影响指令执行, 因此不缩进不换行 - command += f'''/give @p minecraft:chest 1 0 {{display: {{Name: "{DataStorage.get_instance().current_design_name}"}},BlockEntityTag:{{Items:[''' - - command += f'''{{Slot:{generated_num % 27}b,id:"minecraft:banner",Damage:{15 - int(now_banner[0])}s,Count:1b,tag:{{display: {{Name: "{_i}_{j}"}},''' - - # 判断是否需要添加图案 - if not all(x == '0' for x in now_banner[1::2]): - - command += f'''BlockEntityTag:{{Patterns:[''' - - for k in range((len(now_banner) - 1) // 2): - try: - if int(now_banner[2 * k + 1]) != 0: - if pattern.type_support_version[int(now_banner[2 * k + 1])] <= self.ui.VersionPatternSelectComboBox.currentIndex(): - command += f"{{Pattern:\"{pattern.type[int(now_banner[2 * k + 1])]}\",Color:{15 - int(now_banner[2 * k + 2])}}}," - else: - isskip = True - except IndexError: - pass - command += f"]}}" - - command += f'''}}}},''' - - if generated_num % 27 == 26: - # 指令后缀 - command += f''']}}}}\n___________________________\n''' - - generated_num += 1 - if generated_num % 27 != 0: - # 指令后缀 - command += f''']}}}}\n___________________________\n''' - elif self.ui.VersionCmdSelectComboBox.currentIndex() == 1: # 1.13~1.20.5 - for i in range(DataStorage.get_instance().current_design_size[0] - 1): - _i = DataStorage.get_instance().current_design_size[0] - i - 1 - for j in range(DataStorage.get_instance().current_design_size[1]): - # 旗帜属性 - if f"{_i}:{j}" not in DataStorage.get_instance().current_design_patterns: - continue - now_banner = DataStorage.get_instance().current_design_patterns[f"{_i}:{j}"].split(":") - if(len(now_banner) > 13): - isover6 = True - - if now_banner[0] != "16": - if generated_num % 27 == 0: - # 指令前缀, 缩进似乎会影响指令执行, 因此不缩进不换行 - command += f'''/give @p minecraft:chest{{display: {{Name: '{{"text":"{DataStorage.get_instance().current_design_name}","color":"gold"}}'}},BlockEntityTag:{{Items:[''' - - command += f'''{{Slot:{generated_num % 27}b,id:"minecraft:{pattern.color_name[int(now_banner[0])]}_banner",Count:1b,tag:{{display: {{Name: '{{"text":"{_i}_{j}"}}'}},''' - - # 判断是否需要添加图案 - if not all(x == '0' for x in now_banner[1::2]): + storage = DataStorage.get_instance() + design_name = storage.current_design_name + design_size = storage.current_design_size + patterns_dict = storage.current_design_patterns + + version_cmd_index = self.ui.VersionCmdSelectComboBox.currentIndex() + version_pattern_index = self.ui.VersionPatternSelectComboBox.currentIndex() + + # 根据版本选择对应的生成器 + if version_cmd_index == 0: + generator = CommandGenerator1_8(design_name, design_size, patterns_dict, version_pattern_index) + elif version_cmd_index == 1: + generator = CommandGenerator1_13(design_name, design_size, patterns_dict, version_pattern_index) + elif version_cmd_index == 2: + generator = CommandGenerator1_20_5(design_name, design_size, patterns_dict, version_pattern_index) + else: + QMessageBox.warning(self, '错误', '尚不支持的版本') + return - command += f'''BlockEntityTag:{{Patterns:[''' + command = generator.generate() + generated_num = generator.generated_count + isover6 = generator.is_over6 + isskip = generator.is_skip - for k in range((len(now_banner) - 1) // 2): - try: - if int(now_banner[2 * k + 1]) != 0 : - if pattern.type_support_version[int(now_banner[2 * k + 1])] <= self.ui.VersionPatternSelectComboBox.currentIndex(): - command += f"{{Pattern:\"{pattern.type[int(now_banner[2 * k + 1])]}\",Color:{now_banner[2 * k + 2]}}}," - else: - isskip = True - except IndexError: - pass - command += f"]}}" - - command += f'''}}}},''' - - if generated_num % 27 == 26: - # 指令后缀 - command += f''']}}}}\n___________________________\n''' - - generated_num += 1 - if generated_num % 27 != 0: - # 指令后缀 - command += f''']}}}}\n___________________________\n''' - elif self.ui.VersionCmdSelectComboBox.currentIndex() == 2: # 1.20.5+ - # 可用指令示例 give @p chest[custom_name={text:"bbb",color:"gold"},container=[{slot:0,item:{id:"red_banner",components:{custom_name:"1_1",banner_patterns:[{pattern:"stripe_top",color:"white"}]}}}]] 1 - for i in range(DataStorage.get_instance().current_design_size[0] - 1): - _i = DataStorage.get_instance().current_design_size[0] - i - 1 - for j in range(DataStorage.get_instance().current_design_size[1]): - # 旗帜属性 - if f"{_i}:{j}" not in DataStorage.get_instance().current_design_patterns: - continue - now_banner = DataStorage.get_instance().current_design_patterns[f"{_i}:{j}"].split(":") - if(len(now_banner) > 13): - isover6 = True - - if now_banner[0] != "16": - if generated_num % 27 == 0: - # 指令前缀 - command += f'''/give @p chest[custom_name={{text:"{DataStorage.get_instance().current_design_name}",color:"gold"}},container=[''' - - command += f'''{{slot:{generated_num % 27},item:{{id:"{pattern.color_name[int(now_banner[0])]}_banner",components:{{custom_name:"{_i}_{j}"''' - - # 判断是否需要添加图案 - if not all(x == '0' for x in now_banner[1::2]): - command += f''',banner_patterns:[''' - - for k in range((len(now_banner) - 1) // 2): - try: - if int(now_banner[2 * k + 1]) != 0: - if pattern.type_support_version[int(now_banner[2 * k + 1])] <= self.ui.VersionPatternSelectComboBox.currentIndex(): - command += f"{{pattern:'{pattern.advanced_type[int(now_banner[2 * k + 1])]}',color:{pattern.color_name[int(now_banner[2 * k + 2])]}}}," - else: - isskip = True - except IndexError: - pass - command += f"]" - - command += f'''}}}}}},''' # 关闭components、item和slot - - if generated_num % 27 == 26: - # 指令后缀 - command += f''']]\n___________________________\n''' - - generated_num += 1 - - if generated_num % 27 != 0: - # 指令后缀 - command += f''']]\n___________________________\n''' - # 复制剪贴板 - app = QApplication.instance() - if not app: - app = QApplication(sys.argv) - - clipboard = app.clipboard() - clipboard.setText(command) + app = QApplication.instance() or QApplication(sys.argv) + app.clipboard().setText(command) + text = f'已复制指令到剪贴板,共{(generated_num - 1) // 27 + 1}条' if isover6: text += ',存在大于6次染色的旗帜' @@ -556,4 +591,4 @@ def RowColumnOperation(self, isAdd: bool = True, isRow: bool = True, inverted: b app = QApplication(sys.argv) window = ToolBox() window.show() - sys.exit(app.exec_()) \ No newline at end of file + sys.exit(app.exec_())