Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
325 changes: 180 additions & 145 deletions ToolBox.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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次染色的旗帜'
Expand Down Expand Up @@ -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_())
sys.exit(app.exec_())