From 2de3cf17e3b610ba37eb499a9a85eb49549051e4 Mon Sep 17 00:00:00 2001 From: KlparetlR <105189905+KlparetlR@users.noreply.github.com> Date: Sat, 15 Jul 2023 12:50:45 +0800 Subject: [PATCH] VPtool-2.12 --- .../VPtool-2.11/000.ico" | Bin 43175 -> 0 bytes .../VPtool-2.11/LANG/__init__.py" | 2 - .../__pycache__/__init__.cpython-311.pyc" | Bin 348 -> 0 bytes .../__pycache__/custom_lang.cpython-311.pyc" | Bin 2170 -> 0 bytes .../LANG/__pycache__/en_us.cpython-311.pyc" | Bin 1469 -> 0 bytes .../LANG/__pycache__/zh_cn.cpython-311.pyc" | Bin 1975 -> 0 bytes .../VPtool-2.11/LANG/custom_lang.py" | 29 -- .../VPtool-2.11/LANG/zh_cn.py" | 25 -- .../VPtool-2.11/main.py" | 358 ------------------ .../VPtool-2.12/LANG/__init__.py" | 2 + .../VPtool-2.12/LANG/custom_lang.py" | 60 +++ .../VPtool-2.12/LANG/zh_cn.py" | 56 +++ .../VPtool-2.12/dialogs.py" | 0 .../VPtool-2.12/func/__init__.py" | 3 + .../VPtool-2.12/func/ldcStringExtractor.py" | 173 +++++++++ .../VPtool-2.12/func/text_conversion.py" | 235 ++++++++++++ .../VPtool-2.12/func/text_conversion_asm.py" | 157 ++++++++ .../VPtool-2.12/main.py" | 159 ++++++++ 18 files changed, 845 insertions(+), 414 deletions(-) delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/000.ico" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__init__.py" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/__init__.cpython-311.pyc" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/custom_lang.cpython-311.pyc" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/en_us.cpython-311.pyc" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/zh_cn.cpython-311.pyc" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/custom_lang.py" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/zh_cn.py" delete mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/main.py" create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/__init__.py" create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/custom_lang.py" create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/zh_cn.py" rename "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/dialogs.py" => "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/dialogs.py" (100%) create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/__init__.py" create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/ldcStringExtractor.py" create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion.py" create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion_asm.py" create mode 100644 "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/main.py" diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/000.ico" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/000.ico" deleted file mode 100644 index 962a0fc523220d68b4fb7b67d00e4270f8b5b0e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43175 zcmV)nK%Kt;00962000000096P0FkHw02TlM0EtjeM-2)Z3IG5A4M|8uQUCw}00001 z00;sA007evKQRCR010qNS#tmY4#WTe4#WYKD-Ig~03ZNKL_t(|ob0{Hu53wmCAQYy zcKp63-iyeLOeP6-QnA1yD}~~K15E_hCrJ7!4K&dgXdq}>&__ssRGJ8aKtd7rwmukW%S4gAC3|K0C@|9hGF;>C-<`SITzkNw%R=bwJ}`%j)cdHMQP zHw3gEC2a|KL6Rz{`%kk>(?*7 zBTX;vfCqAN
    fU%dxMoWA(%G^y82J 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 diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/en_us.cpython-311.pyc" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/en_us.cpython-311.pyc" deleted file mode 100644 index a3afac85e7ff6345b1dce1fbfa839cfcf39c99b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1469 zcmaJ>O-vg{6yCM@G5+DlK%!PahFY|-BCJ9J{fnp^prjI|$OP0zR;yuV46Cen+?iP? ztY%aW9NMY}PHm1sMw+-6MJ#$Xe;QZ=PXV1CoP5v(u!)8c3+SM@~*B!c3cj<1O&^xtW_=I*XE5OYFPQ6O87;=QZW=0Q>pq+Sfcp0fRDj zXR8E8>H!pjvIqwh;j@~BXzYJC7ow31^DRY%D801)Iap8Lw+<~f92E(Auj@y;IpvfT#udxdV-(+}qLVhxb7C730^S+M*(8?`| z@`8}Hw4QhNY4p~jZGIemX74}^gPykRNN%hu&V3|9V((ui^!=SPwMwE1SvbEtKw#$q zBrsCjC(Oa>+*n1>^X*mCI+FrQHm{jf+|K!|s|krH+*SfFcM6Z3{BR?Nr@*Gcu7lkG zn*o~z`vB}iu#XyXJoUbXDGSpUu3NZaVaCF2BVMmTwqAp5y$0EO4YKvxjI^IQx@i4# z7c%7I^16hBFBfUm3p}ad>TpqBVDg^gwQ^xADu3Yxj0jv&<(G%Qz4~kK<&z&@{QOI~ zHLtVBI{2gG|IqrFT_ttUGRSU!C zFl)WMh4(C6ZbLG=JAa(KW?{ra&cc|5p>r6u-uJunCow1WRm=txt)OUwROW}x{p|j& zeev*}hoytq!Sn$+%pH=)xyR&b?kRbedq$q;o|B`}`cZ2AsAK&UWI8K(w<%n7K_JE~ ki~#(bxY;`4IdKKTW?MOMPU5cXp2RM>8}5m7F*b|*2ihFing9R* diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/zh_cn.cpython-311.pyc" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/LANG/__pycache__/zh_cn.cpython-311.pyc" deleted file mode 100644 index f8f323aa46af14ad2a38ad94515578cc3909edab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1975 zcmb_dT~HHO6y79&5I_`AoLbwoj-6r+3Q=2IhZ!yYO%)xe*s&R%C3k^LW0Kj;rb>5b z77Pd!B(2Dwarh}}R7iq#B#}gX^pQu0S95naPcY;3rB6LK8)$7EpL%D`xA)%foO92) z_uRYp3JZ-CH2?Mx%FdyvS7fl-beYcU0_Y4;i1JbADWt2X%JsHY9r7&$F@U`G1Av}R zq>x_JA%mz#S)u`Di&-c~%tq_P9F!}rLwRB@GKzU9Uo@fuF&`C*1!%okh>FDZXoFaU zHi{civA7YHh{dQ>EJ2&ZQnXpzgv!Lt0ww4KyBxH6LSLHio@ouJ^cD#$-%J zZ={BT$>`IDGjec3nfIwuuQD*EjQYrOiI5T>#GNB}?hfvl%XqfzIbb=;IGaz|oz0r_ zjBjHy5m2QL+}}guynR(3j6po|$YW)C1WyL#u^Y?rF7^6D9O_<OJaL;}4@m&r5qmx0#qjV!{x22>}WgwV|=A_F;JM66tI`#GL z<1~wGF2sDxT=uNytC<*aJf=JtN+uTmwq#Kw<3!BvdfsVnpdAk8iun@5adb1&=(@~s zd=Zocp7JUFPS_23@LF>I3I7qyrKE28=lkm2w&cQXJTtsT;;EQ+2z)MReTo-4@WjJ% zZ2&gufd!akVmuX)z+Q8dj7rJq1J7lTwgmpQSDVQUr(&<9_Vl{%wtJ`68@}=&hGS<> zsNoqkDDlN4qW>hq!-dKu%9lV_S(sPDzi8)cRuYe}zc0N%^30S*!Gv-z^5&e}->)uc zbD9#_s&tX9y2qi>bQda4?((Otm5FJnIc2;}t3UoUtga@e<-SRI=n1~|RJk5W4UDMa z@N&FO4bREHN%GhoWp*C-#)!qJZ~Kwj8adD{KbjyI?*~2Ok-ECmb*3g4YdW}ttL9tY z;&UjJnj8jQC|ddVn~+X2+J^(de|lDXui{&eac9TBTz;~H`>J|5-YXA>vHz|ze@~g8 zfsk?U;BtJ7|A6e|YQ)+>sB>Zb%$JN#;;C8i#WSGNaK__uIZUt(xMvJUI!!yc3MdLw z#v;7~a7|5cPrC+>XD+J=^40c99*^UAKNNux$DZK!AQUD<4^B+vZAjcqMrTNcINy;u z9`8&Igygwd{PZrC;{Q|r_o?!-r7XL%$+e`XD?zG2EFgP9_JQmN`5fd6kONBwx^fSJ zN&-~`ECluv*hgUhlELc+*6Rk=>ju{A2G;8a*6ZHSkr&*`8%e-9#O4guyZ7xle zlHoQ0W3lx0OXG(Gw!R5zA`NN6N?4x2P68}}p8)cU{Ca*-* -项目地址:https://github.com/KlparetlR/Vault-Patcher-Grocery-Store/blob/main/VPtool%E7%BC%96%E5%86%99%E5%B7%A5%E5%85%B7/ -专门为VP模组而生的配置编写工具(https://github.com/3093FengMing/VaultPatcher ) -作者及版权方:晴笙墨染(莫安)、KlparetlR、捂脸Wulian, 技术辅助:XDawned -Fabric通用(https://github.com/LocalizedMC/HardcodeTextPatcher-Fabric ) -弹窗使用https://github.com/rdbende/Sun-Valley-messageboxes -""" - -from tkinter import filedialog, StringVar, Tk, ttk -from tkinter.ttk import Button, Label, Entry,Combobox -import os,codecs,copy,json,dialogs,sys,subprocess,re,sv_ttk,ctypes,LANG -from LANG import zhlangtext,zdyconfig,zdylangtext - -if __name__ == "__main__": - vaulelang = hex(ctypes.windll.kernel32.GetSystemDefaultUILanguage()) - def updateGui(): - file_lb.config(text=a1) - savelangButton.config(text=a15) - saveButton.config(text=a16) - mods_lb.config(text=a14) - desc_lb.config(text=a13) - name_lb.config(text=a12) - authors_lb.config(text=a11) - packButton.config(text=a10) - icon_lb.config(text=a9) - IconButton.config(text=a10) - cGuilang_lb.config(text=a8) - mods_vaule.set(a4) - desc_vaule.set(a4) - name_vaule.set(a4) - authors_vaule.set(a4) - icon_var.set(a3) - FileGUI.set(a3) - def runlangGui(): - global zdy,a0,info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,vp1,vp2,vp3,vp4,vp5,vp6,langcurrent - zdy,a0 = zdyconfig() - if vaulelang == "0x804": - info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,vp1,vp2,vp3,vp4,vp5,vp6 = zhlangtext() - def langcurrent(): - cGuilang_entry.current(0) - if vaulelang == f"{a0}": - info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,vp1,vp2,vp3,vp4,vp5,vp6 = zdylangtext() - def langcurrent(): - cGuilang_entry.current(2) - runlangGui() - def runclangGui(): - global zdy,a0,info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,vp1,vp2,vp3,vp4,vp5,vp6 - zdy,a0 = zdyconfig() - if cGuilang_entry.get() == "中文简体": - info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,vp1,vp2,vp3,vp4,vp5,vp6 = zhlangtext() - if cGuilang_entry.get() == f"{zdy}": - info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,vp1,vp2,vp3,vp4,vp5,vp6 = zdylangtext() - updateGui() - root.update() - def browseStruct(): - FileGUI.set(filedialog.askopenfilename(filetypes=(("%s" % (a1), "*.txt *.TXT"),),initialdir=os.path.abspath(os.path.dirname(__file__)))) - def browseIcon(): - icon_var.set(filedialog.askdirectory(title="%s" % (a2),initialdir=os.path.abspath(os.path.dirname(__file__)))) - def box_checked(): - saveButton.grid_forget() - r = 0 - cGuilang_lb.grid(row=r, column=0,pady=5) - langcurrent() - cGuilang_entry.grid(row=r, column=1,pady=5) - savelangButton.grid(row=r, column=2,pady=5,padx=20) - r += 1 - empty_lb.grid(row=r, column=1,pady=5) - r += 1 - file_lb.grid(row=r, column=0,pady=5) - file_entry.grid(row=r, column=1,pady=5) - packButton.grid(row=r, column=2,pady=5) - r += 1 - icon_lb.grid(row=r, column=0,pady=5,padx=20) - icon_entry.grid(row=r, column=1,pady=5) - IconButton.grid(row=r, column=2,pady=5,padx=20) - r += 1 - authors_lb.grid(row=r, column=0,pady=5,padx=20) - authors_entry.grid(row=r, column=1,pady=5,padx=20) - r += 1 - name_lb.grid(row=r, column=0,pady=5,padx=20) - name_entry.grid(row=r, column=1,pady=5,padx=20) - r += 1 - desc_lb.grid(row=r, column=0,pady=5,padx=20) - desc_entry.grid(row=r, column=1,pady=5,padx=20) - r += 1 - mods_lb.grid(row=r, column=0,pady=5,padx=20) - mods_entry.grid(row=r, column=1,pady=5,padx=20) - r += 1 - saveButton.grid(row=r, column=2,pady=5,padx=20) - r += 1 - def runFromGui(): - if FileGUI.get() and icon_var.get() == "%s" % (a3) or len(FileGUI.get() and icon_var.get()) == 0: - dialogs.show_message("ERROR", "%s" % (a5)) - else: - if FileGUI.get() == "%s" % (a3) or len(FileGUI.get()) == 0: - dialogs.show_message("ERROR", "%s" % (a6)) - if icon_var.get() == "%s" % (a3) or len(icon_var.get()) == 0: - dialogs.show_message("ERROR", "%s" % (a7)) - vp() - root = Tk() - root.title("VPtool 2.11") - cGuilang_lb = Label(root, text="%s" % (a8)) - combo_list = ["中文简体",f"{zdy}"] - empty_lb = Label(root, text="") - cGuilang_entry = Combobox(root,state="readonly", values=combo_list) - FileGUI = StringVar(value="%s" % (a3)) - icon_var = StringVar(value="%s" % (a3)) - authors_vaule = StringVar(value="%s" % (a4)) - name_vaule = StringVar(value="%s" % (a4)) - desc_vaule = StringVar(value="%s" % (a4)) - mods_vaule = StringVar(value="%s" % (a4)) - file_entry = Entry(root, textvariable=FileGUI) - icon_lb = Label(root, text="%s" % (a9)) - icon_entry = Entry(root, textvariable=icon_var) - IconButton = Button(root, text="%s" % (a10), command=browseIcon) - file_lb = Label(root, text="%s" % (a1)) - packButton = Button(root, text="%s" % (a10), command=browseStruct) - authors_lb = Label(root, text="%s" % (a11)) - authors_entry = Entry(root, textvariable=authors_vaule) - name_lb = Label(root, text="%s" % (a12)) - name_entry = Entry(root, textvariable=name_vaule) - desc_lb = Label(root, text="%s" % (a13)) - desc_entry = Entry(root, textvariable=desc_vaule) - mods_lb = Label(root, text="%s" % (a14)) - mods_entry = Entry(root, textvariable=mods_vaule) - saveButton = Button(root, text="%s" % (a16), command=runFromGui) - savelangButton = Button(root, text="%s" % (a15), command=runclangGui) - box_checked() - sv_ttk.use_light_theme() - root.update_idletasks() - width = root.winfo_width() - height = root.winfo_height() - x = (root.winfo_screenwidth() // 2) - (width // 2) - y = (root.winfo_screenheight() // 2) - (height // 2) - 200 - root.geometry('{}x{}+{}+{}'.format(width,height,x,y)) - root.resizable(False, False) - dialogs.show_message('VPtool-welcome',info) - def vp(): - # 文件地址 - filePath = FileGUI.get() - folderpath = icon_var.get()+'/%s/' % (vp1) - fileName = os.path.basename(os.path.splitext(filePath)[0]) - # 文件初始内容 - fileTxtList = [] - # 1号下标 - index = 3 - # 类匹配开关 - isClass = False - # 类名 - className = '' - tempclassName = ' ' - # 堆键 - Reactordepth = '' - # 包名备份 - packname = '' - # 汉化占位基础文本 - valueTxt = '' - # 基础字典模板 - placeholder = {"authors": f"{authors_vaule}", "name": f"{name_vaule}", "desc": f"{desc_vaule}", "mods": f"{mods_vaule}"} - targetClass = {'name': 'nametype', 'method': 'method', 'stack_depth': -1} - # 最终结果输出 - resultList = [] - resultList2 = {} - # 重启tool - def restart(): - subprocess.Popen([sys.executable] + sys.argv) - sys.exit() - # 获取文件行内容 - with open(filePath, 'r', encoding='utf8') as f: - # 逐行读取加入列表 - fileTxtList = f.read().splitlines() - # nametype - packname = fileTxtList[0] - # value基础值 - valueTxt = fileTxtList[1] - # 起始值 - valueIndex = int(fileTxtList[2]) - # 遍历文本内容 - for _ in range(len(fileTxtList) - 3): - resultDictionaries = {} - # 获取当前临时文本 - tempFileTxt = fileTxtList[index] - # 基础字典模板 - txtResult = {'key': "测试被汉化文本", 'value': '测试汉化文本'} - # 判断开始 - print(tempFileTxt) - methoddata = "" - Reactordata = "" - # 先判断 是否启动类匹配开关 - if tempFileTxt[0] == '#' and tempFileTxt[1:4] != 'END': - if tempclassName == ' ': - isClass = True - className = tempFileTxt - tempclassName = str(tempFileTxt) - index += 1 - continue - elif tempclassName != ' ': - if tempclassName[0] == '#' and tempFileTxt[1:4] != 'END': - print ("ERROR for <"+tempclassName+">") - dialogs.show_message('VPtool',f'{vp2}' % (tempclassName)) - restart() - else: - isClass = True - className = tempFileTxt - tempclassName = str(tempFileTxt) - index += 1 - continue - elif tempFileTxt[0:4] == '#END': - isClass = False - className = '' - tempclassName = ' ' - index += 1 - continue - # 后判断 method有没有 - methoddata = "".join(re.findall(r"&(.+?);",tempFileTxt)) - if methoddata != "" and isClass != False: - tempFileTxt = tempFileTxt.replace("&"+methoddata+";","") - if methoddata != "" and isClass == False: - print ("ERROR for <&"+methoddata+";>") - yan1 = dialogs.ask_yes_no('VPtool',f'{vp3}' % (methoddata)) - if yan1 == True: - tempFileTxt = tempFileTxt.replace("&"+methoddata+";","") - methoddata = "" - else: - restart() - # 判断 堆键深度有没有 - Reactordata = "".join(re.findall(r":(.+?);",tempFileTxt)) - if Reactordata != "" and isClass != False: - tempFileTxt = tempFileTxt.replace(":"+Reactordata+";","") - if Reactordata != "" and isClass == False: - print ("ERROR for <:"+Reactordata+";>") - yan1 = dialogs.ask_yes_no('VPtool',f'{vp6}' % (Reactordata)) - if yan1 == True: - tempFileTxt = tempFileTxt.replace(":"+Reactordata+";","") - Reactordata = "" - else: - restart() - # 开启包名 和 半匹配 和 有类匹配(优先) - if "@bm;" in tempFileTxt and "@;" in tempFileTxt and isClass: - txtResult['key'] = tempTxt = tempFileTxt.split(';')[2] - txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) - targetClass['name'] = className - tempTxt3 = valueTxt + str(valueIndex) - tempTargetClass = copy.deepcopy(targetClass) - resultDictionaries = {'target_class': tempTargetClass} - resultDictionaries.update(txtResult) - resultList.append(resultDictionaries) - resultList2[tempTxt3] = tempTxt - # 开启包名 和 半匹配 和 无类匹配 - elif "@bm;" in tempFileTxt and "@;" in tempFileTxt and isClass != True: - targetClass['name'] = packname - txtResult['key'] = tempTxt = tempFileTxt.split(';')[2] - txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) - tempTxt3 = valueTxt + str(valueIndex) - tempTargetClass = copy.deepcopy(targetClass) - resultDictionaries = {'target_class': tempTargetClass} - resultDictionaries.update(txtResult) - resultList.append(resultDictionaries) - resultList2[tempTxt3] = tempTxt - # 开启包名 和 有类匹配 类匹配优先 - elif "@bm;" in tempFileTxt and "@;" not in tempFileTxt and isClass: - txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] - txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) - targetClass['name'] = className - tempTargetClass = copy.deepcopy(targetClass) - resultDictionaries = {'target_class': tempTargetClass} - resultDictionaries.update(txtResult) - resultList.append(resultDictionaries) - resultList2[tempTxt2] = tempTxt - # 开启包名 和 无类匹配 - elif "@bm;" in tempFileTxt and "@;" not in tempFileTxt and isClass != True: - targetClass['name'] = packname - txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] - txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) - tempTargetClass = copy.deepcopy(targetClass) - resultDictionaries = {'target_class': tempTargetClass} - resultDictionaries.update(txtResult) - resultList.append(resultDictionaries) - resultList2[tempTxt2] = tempTxt - # 开启半匹配 和 有类匹配 - elif "@;" in tempFileTxt and "@bm;" not in tempFileTxt and isClass: - txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] - txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) - targetClass['name'] = className - tempTxt3 = valueTxt + str(valueIndex) - tempTargetClass = copy.deepcopy(targetClass) - resultDictionaries = {'target_class': tempTargetClass} - resultDictionaries.update(txtResult) - resultList.append(resultDictionaries) - resultList2[tempTxt3] = tempTxt - # 开启半匹配 和 无类匹配 - elif "@;" in tempFileTxt and "@bm;" not in tempFileTxt and isClass != True: - txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] - txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) - tempTxt3 = valueTxt + str(valueIndex) - resultDictionaries.update(txtResult) - resultList.append(resultDictionaries) - resultList2[tempTxt3] = tempTxt - # 纯类匹配 - elif '@;' and '@bm' not in tempFileTxt and isClass: - txtResult['key'] = tempTxt = tempFileTxt - txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) - targetClass['name'] = className - tempTargetClass = copy.deepcopy(targetClass) - resultDictionaries = {'target_class': tempTargetClass} - resultDictionaries.update(txtResult) - resultList.append(resultDictionaries) - resultList2[tempTxt2] = tempTxt - # 什么都不开 正常填入 - else: - txtResult['key'] = tempTxt = tempFileTxt - txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) - resultDictionaries.update(txtResult) - resultList.append(txtResult) - resultList2[tempTxt2] = tempTxt - targetClass['method'] = methoddata - targetClass['stack_depth'] = Reactordata - methoddata = "" - Reactordata = "" - index += 1 - valueIndex += 1 - # 确保目标文件夹存在 - if not os.path.exists(folderpath): - os.makedirs(folderpath) - # 输出 json化的字典数据到 该文件 没有该文件就创建新文件 - putFile = folderpath + fileName + '.json' - putFile2 = folderpath + fileName + '-zh_cn.json' - fp = codecs.open(os.path.join(putFile), 'w+', encoding='utf8') - fp2 = codecs.open(os.path.join(putFile2), 'w+', encoding='utf8') - # 嵌套字典 - resultList.insert(0, placeholder) - resultDic = {'list': resultList} - # 循环输出到文件 - resultDicJson = json.dumps(resultDic, ensure_ascii=False) - resultList2 = json.dumps(resultList2, ensure_ascii=False) - resultDicJson = str(resultDicJson[8:len(resultDicJson) - 1]) - resultList2 = str(resultList2) - resultDicJson = resultDicJson.replace(r"\\n", r"\n").replace(r"\\u", r"\u") - resultList2 = resultList2.replace(r"\\n", r"\n").replace(r"\\u", r"\u") - fp.write(resultDicJson) - fp2.write(resultList2) - # 关闭文件流 - fp.close() - fp2.close() - # 打开文件资源管理器并选中文件夹 - def open_folder(folderpath): - if os.path.exists(folderpath): - os.startfile(folderpath) - else: - print ("ERROR: File path lost!") - dialogs.show_message('VPtool',f'{vp4}') - subprocess.Popen([sys.executable] + sys.argv) - sys.exit() - open_folder(folderpath) - # 成功提示 - dialogs.show_message('VPtool',f'{vp5}' % (fileName,folderpath)) - root.mainloop() \ No newline at end of file diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/__init__.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/__init__.py" new file mode 100644 index 0000000..6ce2e51 --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/__init__.py" @@ -0,0 +1,2 @@ +from .zh_cn import zhguitext,zh_func_tc_text,zh_gui_tca_text,zh_func_lse_text +from .custom_lang import zdyguitext,zdyconfig,zdy_gui_tc_text,zdy_gui_tca_text,zdy_gui_lse_text \ No newline at end of file diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/custom_lang.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/custom_lang.py" new file mode 100644 index 0000000..32645a1 --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/custom_lang.py" @@ -0,0 +1,60 @@ +def zdyconfig(): + zdy = "繁体中文" + a0 = "0x404" + return zdy,a0 +def zdyguitext(): + info = "*-*<適配版本:1.2.10+>*-*\n項目地址:github-/KlparetlR/Vault-Patcher-Grocery-Store \n專門為VP模組而生的配寘編寫工具github-3093FengMing/VaultPatcher \n作者及版權方:晴笙墨染(莫安)、KlparetlR、捂脸Wulian、3093FengMing,科技輔助:XDawned\nFabric通用:github-LocalizedMC/HardcodeTextPatcher-Fabric \n彈窗使用github-rdbende/Sun-Valley-messageboxes" + a1 ="處理的檔案" + a2 ="選擇要保存的資料夾地址" + a3 ="(必填)" + a4 ="(選填)" + a5 ="你需要選擇一個txt檔案和一個資料夾。" + a6 ="你需要選擇一個txt檔案。" + a7 ="你需要選擇一個資料夾。" + a8 ="GUI語言" + a9 ="保存的資料夾" + a10 ="選擇" + a11 ="翻譯作者-署名" + a12 ="此翻譯名稱" + a13 ="此翻譯描述" + a14 ="翻譯的模組" + a15 ="選定" + a16 ="生成" + a17 ="2.10版-文字轉json" + a18 ="asm版-文字轉json" + a19 ="模組全字串選取" + a20 ="開始運行功能:" + a21 ="功能選擇" + return info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21 +def zdy_gui_tc_text(): + vp1 ="硬編碼配寘" + vp2 ="轉換時出現錯誤!請檢查類匹配的#END有沒有漏!\nERROR for <%s>" + vp3 ="轉換時出現問題!方法名不在類匹配的範圍內!\nERROR for <&%s;>,是否繼續轉化?" + vp4 ="錯誤!檔案路徑遺失!" + vp5 ="VPtool成功將 %s.txt 檔案轉換為 VP或HP模組 的配寘格式。\n並儲存在%s目錄中。" + vp6 = "轉換時出現問題!堆鍵深度值不在類匹配的範圍內!\nERROR for <&%s;>,是否繼續轉化?" + vp7 = "檔案無法訪問,可能是資料夾設為只讀或其它問題!" + return vp1,vp2,vp3,vp4,vp5,vp6,vp7 +def zdy_gui_tca_text(): + vp8 = "key:%s,不在類匹配範圍內,囙此替換不生效,是否跳過該key" + return vp8 +def zdy_gui_lse_text(): + lse1 ="開始工作!(0/3)" + lse2 ="開始選取檔案!(1/3)" + lse3 ="跳過選取步驟" + lse4 ="開始反編譯檔案!(2/3)" + lse5 ="無法訪問,可能是java環境沒設定全或其它問題!" + lse6 ="按回車鍵退出…" + lse7 ="反編譯失敗,因為結果為無!" + lse8 ="跳過該類!" + lse9 ="開始輸出檔案!(3/3)" + lse10 ="輸出檔案至" + lse11 ="模組原始檔案:%s.jar" + lse12 ="輸出Json地址:%s" + lse13 ="臨時Jar緩存資料夾:extracted" + lse14 ="你可以跳過解壓步驟," + lse15 ="通過創建選取的目錄。" + lse16 ="JAVA_HOME:可能不存在,請設定" + lse17 ="按回車鍵繼續…" + lse18 ="完成!" + return lse1,lse2,lse3,lse4,lse5,lse6,lse7,lse8,lse9,lse10,lse11,lse12,lse13,lse14,lse15,lse16,lse17,lse18 \ No newline at end of file diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/zh_cn.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/zh_cn.py" new file mode 100644 index 0000000..990cc1c --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/LANG/zh_cn.py" @@ -0,0 +1,56 @@ +def zhguitext(): + info = "*-*<适配版本:1.2.10+>*-*\n项目地址:github-KlparetlR/Vault-Patcher-Grocery-Store \n专门为VP模组而生的配置编写工具github-3093FengMing/VaultPatcher\n作者及版权方:晴笙墨染(莫安)、KlparetlR、捂脸Wulian、3093FengMing, 技术辅助:XDawned\nFabric通用github-LocalizedMC/HardcodeTextPatcher-Fabric\n弹窗使用github-rdbende/Sun-Valley-messageboxes" + a1 = "处理的文件" + a2 = "选择要保存的文件夹地址" + a3 = "(必填)" + a4 = "(选填)" + a5 = "你需要选择一个txt文件和一个文件夹。" + a6 = "你需要选择一个txt文件。" + a7 = "你需要选择一个文件夹。" + a8 = "GUI语言" + a9 = "保存的文件夹" + a10 = "选择" + a11 = "翻译作者-署名" + a12 = "此翻译名称" + a13 = "此翻译描述" + a14 = "翻译的模组" + a15 = "选定" + a16 = "生成" + a17 = "2.10版-文本转json" + a18 = "asm版-文本转json" + a19 = "模组全字符串提取" + a20 = "开始运行功能:" + a21 = "功能选择" + return info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21 +def zh_func_tc_text(): + vp1 = "硬编码配置" + vp2 = "转换时出现错误!请检查类匹配的#END有没有漏!\nERROR for <%s>" + vp3 = "转换时出现问题!方法名不在类匹配的范围内!\nERROR for <&%s;>,是否继续转化?" + vp4 = "错误!文件路径丢失!" + vp5 = "VPtool 成功将 %s.txt 文件转换为 VP或HP模组 的配置格式。\n并储存在 %s 目录中。" + vp6 = "转换时出现问题!堆键深度值不在类匹配的范围内!\nERROR for <&%s;>,是否继续转化?" + vp7 = "文件无法访问,可能是文件夹设为只读或其它问题!" + return vp1,vp2,vp3,vp4,vp5,vp6,vp7 +def zh_gui_tca_text(): + vp8 = "key:%s,不在类匹配范围内,因此替换不生效,是否跳过该key" + return vp8 +def zh_func_lse_text(): + lse1 = "开始工作!(0/3)" + lse2 = "开始提取文件!(1/3)" + lse3 = "跳过提取步骤" + lse4 = "开始反编译文件!(2/3)" + lse5 = "无法访问,可能是java环境没设置全或其它问题!" + lse6 = "按回车键退出..." + lse7 = "反编译失败,因为结果为无!" + lse8 = "跳过该类!" + lse9 = "开始输出文件!(3/3)" + lse10 = "输出文件至" + lse11 = "模组源文件: %s.jar" + lse12 = "输出Json地址:%s" + lse13 = "临时Jar缓存文件夹: extracted" + lse14 = "你可以跳过解压步骤," + lse15 = "通过创建提取的目录。" + lse16 = "JAVA_HOME:可能不存在,请设置" + lse17 = "按回车键继续..." + lse18 = "完成!" + return lse1,lse2,lse3,lse4,lse5,lse6,lse7,lse8,lse9,lse10,lse11,lse12,lse13,lse14,lse15,lse16,lse17,lse18 \ No newline at end of file diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/dialogs.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/dialogs.py" similarity index 100% rename from "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.11/dialogs.py" rename to "VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/dialogs.py" diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/__init__.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/__init__.py" new file mode 100644 index 0000000..6f470e4 --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/__init__.py" @@ -0,0 +1,3 @@ +from .text_conversion import tc +from .text_conversion_asm import tca +from .ldcStringExtractor import lse \ No newline at end of file diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/ldcStringExtractor.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/ldcStringExtractor.py" new file mode 100644 index 0000000..bea2070 --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/ldcStringExtractor.py" @@ -0,0 +1,173 @@ +import os,time,zipfile,re,json +from datetime import datetime +from LANG import zh_func_lse_text,zdy_gui_lse_text,zdyconfig + +class Method: + def __init__(self, name, code): + self.name = name + self.code = code +class Field: + def __init__(self, name): + self.name = name +class Code: + def __init__(self, instructions): + self.instructions = instructions + +def lse(FileGUI,icon_var,cGuilang_entry): + global CONST_SOURCE,CONST_JAR,filePath,fileName + CONST_SOURCE = icon_var + fileName = os.path.basename(os.path.splitext(icon_var)[0]) + CONST_JAR = FileGUI+"/extracted" + filePath = FileGUI+"/output.json" + def runtcGui(): + global zdy,a0,lse1,lse2,lse3,lse4,lse5,lse6,lse7,lse8,lse9,lse10,lse11,lse12,lse13,lse14,lse15,lse16,lse17,lse18 + zdy,a0 = zdyconfig() + if cGuilang_entry == "中文简体": + lse1,lse2,lse3,lse4,lse5,lse6,lse7,lse8,lse9,lse10,lse11,lse12,lse13,lse14,lse15,lse16,lse17,lse18 = zh_func_lse_text() + if cGuilang_entry == f"{zdy}": + lse1,lse2,lse3,lse4,lse5,lse6,lse7,lse8,lse9,lse10,lse11,lse12,lse13,lse14,lse15,lse16,lse17,lse18 = zdy_gui_lse_text() + runtcGui() + aaeeoo() + +logt = '' +def logs(s): + global logt + now = datetime.now() + logt = ''.join([logt, f'[{now.hour:02d}:{now.minute:02d}:{now.second:02d}] {s}\n']) + print(f'[{now.hour:02d}:{now.minute:02d}:{now.second:02d}] {s}') +def parse_string(s): + lines = s.split('\n')[1:] + g = re.search(r'class (.*) {', lines[0]) + if g is None: + return [None, None, None] + class_name = g.group(1) + methods = [] + fields = [] + for i in range(1, len(lines)): + line = lines[i].strip().replace('static {};', 'public staticMethod();') + k = None + if line.startswith('public'): + k = 'public' + elif line.startswith('private'): + k = 'private' + elif line.startswith('protected'): + k = 'protected' + if k is not None: + if '(' in line: + method_name = re.search(k + r' (.*)\(', line).group(1) + code_lines = [] + i += 1 + while not lines[i] == '': + code_lines.append(lines[i]) + i += 1 + code_str = '\n'.join(code_lines) + instructions = re.findall(r'\d+: (.*)', code_str) + code = Code(instructions) + method = Method(method_name, code) + methods.append(method) + elif 'Code:' not in line: + field_name = re.search(k + r' (.*) (.*);', line).group(2) + field = Field(field_name) + fields.append(field) + else: + method_name = re.search(r'(.*);', line).group(1) + code_lines = [] + i += 1 + while not lines[i].startswith('}'): + code_lines.append(lines[i]) + i += 1 + code_str = '\n'.join(code_lines) + instructions = re.findall(r'\d+: (.*)', code_str) + code = Code(instructions) + method = Method(method_name, code) + methods.append(method) + return [class_name, methods, fields] +def main(): + logs(f'{lse1}') + time.sleep(2) + if not os.path.exists("extracted"): + logs(f'{lse2}') + zf = zipfile.ZipFile(CONST_SOURCE) + zf.extractall(path=CONST_JAR) + logs(f'{lse3}') + time.sleep(1) + ar = [{ + "authors": "FengMing", + "name": "ldcStringExtractor-output", + "desc": "Automatically generated by ldcStringExtractor.\nThe output is only for one class", + "mods": f"{fileName}" + }] + logs(f'{lse4}') + for root, dirs, files in os.walk(CONST_JAR): + for f in files: + if os.path.splitext(f)[1] == ".class": + logs("Decompile... {}".format(os.path.join(root, f))) + try: + resultC = os.popen('javap -c "' + os.path.join(root, f) + '"') + except: + logs(f'{lse5}') + input(f'{lse6}') + cms = [] + if resultC is not None: + name, methods, fields = parse_string(resultC.read()) + if name is None or methods is None or fields is None: + resultC.close() + continue + for m in methods: + if ' ' in m.name: + m.name = m.name.split(' ')[-1] + if '.' in m.name: + m.name = '' + if m.name == 'staticMethod': + m.name = '' + # logs(m.name + '-----------') + for c in m.code.instructions: + if c.startswith("ldc") or c.startswith("ldc_w"): + pos = c.rfind('// String ') + if pos < 0: + continue + cms.append([name, m.name, c[pos + 10:]]) + # logs(c) + resultC.close() + else: + logs(f"{lse7}") + return + if not cms: + logs(f"{lse8}") + continue + for i in range(0, len(cms)): + ar.append({ + 'key': cms[i][2], + 'value': "vaultpatcher.modify.ldc" + str(i), + 'target_class': { + 'name': cms[i][0], + 'method': cms[i][1] + } + }) + logs(f'{lse9}') + with open(filePath, "w") as jf: + logs(f'{lse10}{filePath}') + json.dump(ar, jf) + # logs(ar) +def inita(): + logs('--------ldcStringExtractor--------') + logs('By FengMing V1.0') + logs(f'{lse11}' % (fileName)) + logs(f'{lse12}' % (filePath)) + logs(f'{lse13}') + logs(f'{lse14}') + logs(f'{lse15}') + javah = os.environ.get('JAVA_HOME') + if javah: + logs(f'JAVA_HOME: {javah}') + else: + logs(f'{lse16}') + logs('--------ldcStringExtractor--------') + input(f'{lse17}') +def aaeeoo(): + inita() + main() + logs(f'{lse18}') + with open(CONST_JAR+"/logs.txt", "w") as lf: + lf.write(logt) + input(f'{lse6}') \ No newline at end of file diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion.py" new file mode 100644 index 0000000..209527a --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion.py" @@ -0,0 +1,235 @@ +import os,codecs,copy,json,dialogs,sys,subprocess,re +from LANG import zh_func_tc_text,zdy_gui_tc_text,zdyconfig + +def tc(FileGUI,icon_var,cGuilang_entry,authors_vaule,name_vaule,desc_vaule,mods_vaule): + def runtcGui(): + global zdy,a0,vp1,vp2,vp3,vp4,vp5,vp6,vp7 + zdy,a0 = zdyconfig() + if cGuilang_entry == "中文简体": + vp1,vp2,vp3,vp4,vp5,vp6,vp7 = zh_func_tc_text() + if cGuilang_entry == f"{zdy}": + vp1,vp2,vp3,vp4,vp5,vp6,vp7 = zdy_gui_tc_text() + runtcGui() + # 文件地址 + filePath = icon_var + folderpath = FileGUI+'/%s/' % (vp1) + fileName = os.path.basename(os.path.splitext(filePath)[0]) + # 文件初始内容 + fileTxtList = [] + # 1号下标 + index = 3 + # 类匹配开关 + isClass = False + # 类名 + className = '' + tempclassName = ' ' + # 包名备份 + packname = '' + # 汉化占位基础文本 + valueTxt = '' + # 基础字典模板 + placeholder = {"authors": f"{authors_vaule}", "name": f"{name_vaule}", "desc": f"{desc_vaule}", "mods": f"{mods_vaule}"} + targetClass = {'name': 'nametype', 'method': 'method', 'stack_depth': -1} + # 最终结果输出 + resultList = [] + resultList2 = {} + # 重启tool + def restart(): + subprocess.Popen([sys.executable] + sys.argv) + sys.exit() + # 获取文件行内容 + try: + with open(filePath, 'r', encoding='utf8') as f: + # 逐行读取加入列表 + fileTxtList = f.read().splitlines() + except TypeError: + dialogs.show_message('VPtool',f'{vp7}') + print(f'{vp7}') + # nametype + packname = fileTxtList[0] + # value基础值 + valueTxt = fileTxtList[1] + # 起始值 + valueIndex = int(fileTxtList[2]) + # 遍历文本内容 + for _ in range(len(fileTxtList) - 3): + resultDictionaries = {} + # 获取当前临时文本 + tempFileTxt = fileTxtList[index] + # 基础字典模板 + txtResult = {'key': "测试被汉化文本", 'value': '测试汉化文本'} + # 判断开始 + print(tempFileTxt) + if tempFileTxt == "": + index += 1 + continue + methoddata = "" + Reactordata = "" + # 先判断 是否启动类匹配开关 + if tempFileTxt[0] == '#' and tempFileTxt[1:4] != 'END': + if tempclassName == ' ': + isClass = True + className = tempFileTxt + tempclassName = str(tempFileTxt) + index += 1 + continue + elif tempclassName != ' ': + if tempclassName[0] == '#' and tempFileTxt[1:4] != 'END': + print ("ERROR for <"+tempFileTxt+">,line:"+str(index)) + dialogs.show_message('VPtool',f'{vp2}' % (tempFileTxt)) + restart() + else: + isClass = True + className = tempFileTxt + tempclassName = str(tempFileTxt) + index += 1 + continue + elif tempFileTxt[0:4] == '#END': + isClass = False + className = '' + tempclassName = ' ' + index += 1 + continue + # 后判断 method有没有 + methoddata = "".join(re.findall(r"&(.+?);",tempFileTxt)) + if methoddata != "" and isClass != False: + tempFileTxt = tempFileTxt.replace("&"+methoddata+";","") + if methoddata != "" and isClass == False: + print ("ERROR for <&"+methoddata+";>,line:"+str(index)) + yan1 = dialogs.ask_yes_no('VPtool',f'{vp3}' % (methoddata)) + if yan1 == True: + tempFileTxt = tempFileTxt.replace("&"+methoddata+";","") + methoddata = "" + else: + restart() + # 判断 堆键深度有没有 + Reactordata = "".join(re.findall(r":(.+?);",tempFileTxt)) + if Reactordata != "" and isClass != False: + tempFileTxt = tempFileTxt.replace(":"+Reactordata+";","") + if Reactordata != "" and isClass == False: + print ("ERROR for <:"+Reactordata+";>,line:"+str(index)) + yan1 = dialogs.ask_yes_no('VPtool',f'{vp6}' % (Reactordata)) + if yan1 == True: + tempFileTxt = tempFileTxt.replace(":"+Reactordata+";","") + Reactordata = "" + else: + restart() + # 开启包名 和 半匹配 和 有类匹配(优先) + if "@bm;" in tempFileTxt and "@;" in tempFileTxt and isClass: + txtResult['key'] = tempTxt = tempFileTxt.split(';')[2] + txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) + targetClass['name'] = className + tempTxt3 = valueTxt + str(valueIndex) + tempTargetClass = copy.deepcopy(targetClass) + resultDictionaries = {'target_class': tempTargetClass} + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt3] = tempTxt + # 开启包名 和 半匹配 和 无类匹配 + elif "@bm;" in tempFileTxt and "@;" in tempFileTxt and isClass != True: + targetClass['name'] = packname + txtResult['key'] = tempTxt = tempFileTxt.split(';')[2] + txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) + tempTxt3 = valueTxt + str(valueIndex) + tempTargetClass = copy.deepcopy(targetClass) + resultDictionaries = {'target_class': tempTargetClass} + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt3] = tempTxt + # 开启包名 和 有类匹配 类匹配优先 + elif "@bm;" in tempFileTxt and "@;" not in tempFileTxt and isClass: + txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] + txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) + targetClass['name'] = className + tempTargetClass = copy.deepcopy(targetClass) + resultDictionaries = {'target_class': tempTargetClass} + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt2] = tempTxt + # 开启包名 和 无类匹配 + elif "@bm;" in tempFileTxt and "@;" not in tempFileTxt and isClass != True: + targetClass['name'] = packname + txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] + txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) + tempTargetClass = copy.deepcopy(targetClass) + resultDictionaries = {'target_class': tempTargetClass} + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt2] = tempTxt + # 开启半匹配 和 有类匹配 + elif "@;" in tempFileTxt and "@bm;" not in tempFileTxt and isClass: + txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] + txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) + targetClass['name'] = className + tempTxt3 = valueTxt + str(valueIndex) + tempTargetClass = copy.deepcopy(targetClass) + resultDictionaries = {'target_class': tempTargetClass} + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt3] = tempTxt + # 开启半匹配 和 无类匹配 + elif "@;" in tempFileTxt and "@bm;" not in tempFileTxt and isClass != True: + txtResult['key'] = tempTxt = tempFileTxt.split(';')[1] + txtResult['value'] = tempTxt2 = "@" + valueTxt + str(valueIndex) + tempTxt3 = valueTxt + str(valueIndex) + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt3] = tempTxt + # 纯类匹配 + elif '@;' and '@bm' not in tempFileTxt and isClass: + txtResult['key'] = tempTxt = tempFileTxt + txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) + targetClass['name'] = className + tempTargetClass = copy.deepcopy(targetClass) + resultDictionaries = {'target_class': tempTargetClass} + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt2] = tempTxt + # 什么都不开 正常填入 + else: + txtResult['key'] = tempTxt = tempFileTxt + txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) + resultDictionaries.update(txtResult) + resultList.append(txtResult) + resultList2[tempTxt2] = tempTxt + targetClass['method'] = methoddata + targetClass['stack_depth'] = Reactordata + methoddata = "" + Reactordata = "" + index += 1 + valueIndex += 1 + # 确保目标文件夹存在 + if not os.path.exists(folderpath): + os.makedirs(folderpath) + # 输出 json化的字典数据到 该文件 没有该文件就创建新文件 + putFile = folderpath + fileName + '.json' + putFile2 = folderpath + fileName + '-zh_cn.json' + fp = codecs.open(os.path.join(putFile), 'w+', encoding='utf8') + fp2 = codecs.open(os.path.join(putFile2), 'w+', encoding='utf8') + # 嵌套字典 + resultList.insert(0, placeholder) + resultDic = {'list': resultList} + # 循环输出到文件 + resultDicJson = json.dumps(resultDic, ensure_ascii=False) + resultList2 = json.dumps(resultList2, ensure_ascii=False) + resultDicJson = str(resultDicJson[8:len(resultDicJson) - 1]) + resultList2 = str(resultList2) + resultDicJson = resultDicJson.replace(r"\\n", r"\n").replace(r"\\u", r"\u").replace(r'\\\"', r'\"').replace(r"\\\'", r"\'") + resultList2 = resultList2.replace(r"\\n", r"\n").replace(r"\\u", r"\u").replace(r'\\\"', r'\"').replace(r"\\\'", r"\'") + fp.write(resultDicJson) + fp2.write(resultList2) + # 关闭文件流 + fp.close() + fp2.close() + # 打开文件资源管理器并选中文件夹 + def open_folder(folderpath): + if os.path.exists(folderpath): + os.startfile(folderpath) + else: + print ("ERROR: File path lost!") + dialogs.show_message('VPtool',f'{vp4}') + subprocess.Popen([sys.executable] + sys.argv) + sys.exit() + open_folder(folderpath) + # 成功提示 + dialogs.show_message('VPtool',f'{vp5}' % (fileName,folderpath)) diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion_asm.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion_asm.py" new file mode 100644 index 0000000..fb2844e --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/func/text_conversion_asm.py" @@ -0,0 +1,157 @@ +import os,codecs,copy,json,dialogs,sys,subprocess,re +from LANG import zh_func_tc_text,zdy_gui_tc_text,zdyconfig,zh_gui_tca_text,zdy_gui_tca_text + +def tca(FileGUI,icon_var,cGuilang_entry,authors_vaule,name_vaule,desc_vaule,mods_vaule): + def runtcGui(): + global zdy,a0,vp1,vp2,vp3,vp4,vp5,vp6,vp7,vp8 + zdy,a0 = zdyconfig() + if cGuilang_entry == "中文简体": + vp1,vp2,vp3,vp4,vp5,vp6,vp7 = zh_func_tc_text() + vp8 = zh_gui_tca_text() + if cGuilang_entry == f"{zdy}": + vp1,vp2,vp3,vp4,vp5,vp6,vp7 = zdy_gui_tc_text() + vp8 = zdy_gui_tca_text() + runtcGui() + # 文件地址 + filePath = icon_var + folderpath = FileGUI+'/%s/' % (vp1) + fileName = os.path.basename(os.path.splitext(filePath)[0]) + # 文件初始内容 + fileTxtList = [] + # 1号下标 + index = 2 + # 类匹配开关 + isClass = False + # 类名 + className = '' + tempclassName = ' ' + # 汉化占位基础文本 + valueTxt = '' + # 基础字典模板 + placeholder = {"authors": f"{authors_vaule}", "name": f"{name_vaule}", "desc": f"{desc_vaule}", "mods": f"{mods_vaule}"} + targetClass = {'name': '', 'method': ''} + # 最终结果输出 + resultList = [] + resultList2 = {} + # 重启tool + def restart(): + subprocess.Popen([sys.executable] + sys.argv) + sys.exit() + # 获取文件行内容 + try: + with open(filePath, 'r', encoding='utf8') as f: + # 逐行读取加入列表 + fileTxtList = f.read().splitlines() + except TypeError: + dialogs.show_message('VPtool',f'{vp7}') + print(f'{vp7}') + # value基础值 + valueTxt = fileTxtList[0] + # 起始值 + valueIndex = int(fileTxtList[1]) + # 遍历文本内容 + for _ in range(len(fileTxtList) - 2): + resultDictionaries = {} + # 获取当前临时文本 + tempFileTxt = fileTxtList[index] + # 基础字典模板 + txtResult = {'key': "测试被汉化文本", 'value': '测试汉化文本'} + # 判断开始 + print(tempFileTxt) + if tempFileTxt == "": + index += 1 + continue + methoddata = "" + # 先判断 是否启动类匹配开关 + if tempFileTxt[0] == '#' and tempFileTxt[1:4] != 'END': + if tempclassName == ' ': + isClass = True + className = tempFileTxt + tempclassName = str(tempFileTxt) + index += 1 + continue + elif tempclassName != ' ': + if tempclassName[0] == '#' and tempFileTxt[1:4] != 'END': + print ("ERROR for <"+tempFileTxt+">,line:"+str(index)) + dialogs.show_message('VPtool',f'{vp2}' % (tempFileTxt)) + restart() + else: + isClass = True + className = tempFileTxt + tempclassName = str(tempFileTxt) + index += 1 + continue + elif tempFileTxt[0:4] == '#END': + isClass = False + className = '' + tempclassName = ' ' + index += 1 + continue + # 后判断 method有没有 + methoddata = "".join(re.findall(r"&(.+?);",tempFileTxt)) + if methoddata != "" and isClass != False: + tempFileTxt = tempFileTxt.replace("&"+methoddata+";","") + if methoddata != "" and isClass == False: + print ("ERROR for <&"+methoddata+";>,line:"+str(index)) + yan1 = dialogs.ask_yes_no('VPtool',f'{vp3}' % (methoddata)) + if yan1 == True: + tempFileTxt = tempFileTxt.replace("&"+methoddata+";","") + methoddata = "" + else: + restart() + if isClass: + txtResult['key'] = tempTxt = tempFileTxt + txtResult['value'] = tempTxt2 = valueTxt + str(valueIndex) + targetClass['name'] = className + tempTargetClass = copy.deepcopy(targetClass) + resultDictionaries = {'target_class': tempTargetClass} + resultDictionaries.update(txtResult) + resultList.append(resultDictionaries) + resultList2[tempTxt2] = tempTxt + if not isClass and tempFileTxt[0] != '#': + print ("ERROR for <"+tempFileTxt+">,line:"+str(index)) + yan2 = dialogs.ask_yes_no('VPtool',f'{vp8}' % (tempFileTxt)) + if yan2 == True: + index += 1 + continue + else: + restart() + targetClass['method'] = methoddata + methoddata = "" + index += 1 + valueIndex += 1 + # 确保目标文件夹存在 + if not os.path.exists(folderpath): + os.makedirs(folderpath) + # 输出 json化的字典数据到 该文件 没有该文件就创建新文件 + putFile = folderpath + fileName + '.json' + putFile2 = folderpath + fileName + '-zh_cn.json' + fp = codecs.open(os.path.join(putFile), 'w+', encoding='utf8') + fp2 = codecs.open(os.path.join(putFile2), 'w+', encoding='utf8') + # 嵌套字典 + resultList.insert(0, placeholder) + resultDic = {'list': resultList} + # 循环输出到文件 + resultDicJson = json.dumps(resultDic, ensure_ascii=False) + resultList2 = json.dumps(resultList2, ensure_ascii=False) + resultDicJson = str(resultDicJson[8:len(resultDicJson) - 1]) + resultList2 = str(resultList2) + resultDicJson = resultDicJson.replace(r"\\n", r"\n").replace(r"\\u", r"\u").replace(r'\\\"', r'\"').replace(r"\\\'", r"\'") + resultList2 = resultList2.replace(r"\\n", r"\n").replace(r"\\u", r"\u").replace(r'\\\"', r'\"').replace(r"\\\'", r"\'") + fp.write(resultDicJson) + fp2.write(resultList2) + # 关闭文件流 + fp.close() + fp2.close() + # 打开文件资源管理器并选中文件夹 + def open_folder(folderpath): + if os.path.exists(folderpath): + os.startfile(folderpath) + else: + print ("ERROR: File path lost!") + dialogs.show_message('VPtool',f'{vp4}') + subprocess.Popen([sys.executable] + sys.argv) + sys.exit() + open_folder(folderpath) + # 成功提示 + dialogs.show_message('VPtool',f'{vp5}' % (fileName,folderpath)) diff --git "a/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/main.py" "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/main.py" new file mode 100644 index 0000000..b09ae62 --- /dev/null +++ "b/VPtool\347\274\226\345\206\231\345\267\245\345\205\267/VPtool-2.12/main.py" @@ -0,0 +1,159 @@ +""" +*-*<适配版本:1.2.10+>*-* +项目地址:https://github.com/KlparetlR/Vault-Patcher-Grocery-Store/blob/main/VPtool%E7%BC%96%E5%86%99%E5%B7%A5%E5%85%B7/ +专门为VP模组而生的配置编写工具(https://github.com/3093FengMing/VaultPatcher ) +作者及版权方:晴笙墨染(莫安)、KlparetlR、捂脸Wulian、3093FengMing, 技术辅助:XDawned +Fabric通用(https://github.com/LocalizedMC/HardcodeTextPatcher-Fabric ) +弹窗使用https://github.com/rdbende/Sun-Valley-messageboxes +""" +from tkinter import filedialog, StringVar, Tk +from tkinter.ttk import Button, Label, Entry,Combobox +import os,dialogs,sv_ttk,ctypes +from LANG import zhguitext,zdyconfig,zdyguitext +from func import tca,lse,tc + +if __name__ == "__main__": + vaulelang = hex(ctypes.windll.kernel32.GetSystemDefaultUILanguage()) + def updateGui(): + file_lb.config(text=a1) + savelangButton.config(text=a15) + saveButton.config(text=a16) + mods_lb.config(text=a14) + desc_lb.config(text=a13) + name_lb.config(text=a12) + authors_lb.config(text=a11) + packButton.config(text=a10) + icon_lb.config(text=a9) + IconButton.config(text=a10) + cGuilang_lb.config(text=a8) + func_lb.config(text=a21) + mods_vaule.set(a4) + desc_vaule.set(a4) + name_vaule.set(a4) + authors_vaule.set(a4) + icon_var.set(a3) + FileGUI.set(a3) + func_entry.configure(values=func_list_data) + func_entry.current(0) + def runlangGui(): + global zdy,a0,info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,langcurrent + zdy,a0 = zdyconfig() + if vaulelang == "0x804": + info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21 = zhguitext() + def langcurrent(): + cGuilang_entry.current(0) + if vaulelang == f"{a0}": + info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21 = zdyguitext() + def langcurrent(): + cGuilang_entry.current(2) + runlangGui() + def runclangGui(): + global func_list_data,zdy,a0,info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21 + zdy,a0 = zdyconfig() + if cGuilang_entry.get() == "中文简体": + info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21 = zhguitext() + func_list_data =[f"{a17}",f"{a18}",f"{a19}"] + if cGuilang_entry.get() == f"{zdy}": + info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21 = zdyguitext() + func_list_data =[f"{a17}",f"{a18}",f"{a19}"] + updateGui() + root.update() + def browseStruct(): + FileGUI.set(filedialog.askopenfilename(filetypes=(("%s" % (a1), "*.txt *.TXT *.jar"),),initialdir=os.path.abspath(os.path.dirname(__file__)))) + def browseIcon(): + icon_var.set(filedialog.askdirectory(title="%s" % (a2),initialdir=os.path.abspath(os.path.dirname(__file__)))) + def box_checked(): + saveButton.grid_forget() + r = 0 + cGuilang_lb.grid(row=r, column=0,pady=5) + langcurrent() + cGuilang_entry.grid(row=r, column=1,pady=5) + savelangButton.grid(row=r, column=2,pady=5,padx=20) + r += 1 + func_lb.grid(row=r, column=0,pady=5) + func_entry.current(0) + func_entry.grid(row=r, column=1,pady=5) + r += 1 + empty_lb.grid(row=r, column=1,pady=5) + r += 1 + file_lb.grid(row=r, column=0,pady=5) + file_entry.grid(row=r, column=1,pady=5) + packButton.grid(row=r, column=2,pady=5) + r += 1 + icon_lb.grid(row=r, column=0,pady=5,padx=20) + icon_entry.grid(row=r, column=1,pady=5) + IconButton.grid(row=r, column=2,pady=5,padx=20) + r += 1 + authors_lb.grid(row=r, column=0,pady=5,padx=20) + authors_entry.grid(row=r, column=1,pady=5,padx=20) + r += 1 + name_lb.grid(row=r, column=0,pady=5,padx=20) + name_entry.grid(row=r, column=1,pady=5,padx=20) + r += 1 + desc_lb.grid(row=r, column=0,pady=5,padx=20) + desc_entry.grid(row=r, column=1,pady=5,padx=20) + r += 1 + mods_lb.grid(row=r, column=0,pady=5,padx=20) + mods_entry.grid(row=r, column=1,pady=5,padx=20) + r += 1 + saveButton.grid(row=r, column=2,pady=5,padx=20) + r += 1 + def runFromGui(): + if FileGUI.get() and icon_var.get() == "%s" % (a3) or len(FileGUI.get() and icon_var.get()) == 0: + dialogs.show_message("ERROR", "%s" % (a5)) + else: + if FileGUI.get() == "%s" % (a3) or len(FileGUI.get()) == 0: + dialogs.show_message("ERROR", "%s" % (a6)) + if icon_var.get() == "%s" % (a3) or len(icon_var.get()) == 0: + dialogs.show_message("ERROR", "%s" % (a7)) + if func_entry.get() == f"{a17}": + print (f"{a20}{a17}") + tc(icon_var.get(),FileGUI.get(),cGuilang_entry.get(),authors_vaule,name_vaule,desc_vaule,mods_vaule) + if func_entry.get() == f"{a18}": + print (f"{a20}{a18}") + tca(icon_var.get(),FileGUI.get(),cGuilang_entry.get(),authors_vaule,name_vaule,desc_vaule,mods_vaule) + if func_entry.get() == f"{a19}": + print (f"{a20}{a19}") + lse(icon_var.get(),FileGUI.get(),cGuilang_entry.get()) + root = Tk() + root.title("VPtool 2.12") + cGuilang_lb = Label(root, text="%s" % (a8)) + combo_list = ["中文简体",f"{zdy}"] + empty_lb = Label(root, text="") + cGuilang_entry = Combobox(root,state="readonly", values=combo_list) + FileGUI = StringVar(value="%s" % (a3)) + icon_var = StringVar(value="%s" % (a3)) + authors_vaule = StringVar(value="%s" % (a4)) + name_vaule = StringVar(value="%s" % (a4)) + desc_vaule = StringVar(value="%s" % (a4)) + mods_vaule = StringVar(value="%s" % (a4)) + file_entry = Entry(root, textvariable=FileGUI) + icon_lb = Label(root, text="%s" % (a9)) + icon_entry = Entry(root, textvariable=icon_var) + IconButton = Button(root, text="%s" % (a10), command=browseIcon) + file_lb = Label(root, text="%s" % (a1)) + packButton = Button(root, text="%s" % (a10), command=browseStruct) + authors_lb = Label(root, text="%s" % (a11)) + authors_entry = Entry(root, textvariable=authors_vaule) + name_lb = Label(root, text="%s" % (a12)) + name_entry = Entry(root, textvariable=name_vaule) + desc_lb = Label(root, text="%s" % (a13)) + desc_entry = Entry(root, textvariable=desc_vaule) + mods_lb = Label(root, text="%s" % (a14)) + mods_entry = Entry(root, textvariable=mods_vaule) + saveButton = Button(root, text="%s" % (a16), command=runFromGui) + savelangButton = Button(root, text="%s" % (a15), command=runclangGui) + func_lb = Label(root, text="%s" % (a21)) + func_list = [f"{a17}",f"{a18}",f"{a19}"] + func_entry = Combobox(root,state="readonly", values=func_list) + box_checked() + sv_ttk.use_light_theme() + root.update_idletasks() + width = root.winfo_width() + height = root.winfo_height() + x = (root.winfo_screenwidth() // 2) - (width // 2) + y = (root.winfo_screenheight() // 2) - (height // 2) - 200 + root.geometry('{}x{}+{}+{}'.format(width,height,x,y)) + root.resizable(False, False) + dialogs.show_message('VPtool-welcome',info) + root.mainloop() \ No newline at end of file