This commit is contained in:
恍兮惚兮 2024-03-23 20:24:03 +08:00
parent 973417b48e
commit 59fcf7d062
21 changed files with 117 additions and 61 deletions

View File

@ -4,11 +4,13 @@ import io,sys,platform,os
from ctypes import windll,wintypes from ctypes import windll,wintypes
isbit64= platform.architecture()[0]=='64bit' isbit64= platform.architecture()[0]=='64bit'
DLL3264path=os.path.abspath('files/plugins/DLL'+('32','64')[isbit64]) DLL3264path=os.path.abspath('files/plugins/DLL'+('32','64')[isbit64])
def GetDllpath(_): def GetDllpath(_,base=None):
if base is None:
base=DLL3264path
if isinstance(_,str): if isinstance(_,str):
return os.path.join(DLL3264path,_) return os.path.join(base,_)
elif isinstance(_,(list,tuple)): elif isinstance(_,(list,tuple)):
return os.path.join(DLL3264path,_[isbit64]) return os.path.join(base,_[isbit64])
class debugoutput(io.IOBase): class debugoutput(io.IOBase):
def __init__(self,idx,file=sys.stdout) -> None: def __init__(self,idx,file=sys.stdout) -> None:
super().__init__() super().__init__()

View File

@ -17,8 +17,8 @@ def sqlite2json2(self,sqlitefile,targetjson=None):
for _aret in ret: for _aret in ret:
if len(_aret)==4: if len(_aret)==4:
_id,source,mt,realsource=_aret _id,source_parsed,mt,source=_aret
js_format2[realsource]=mt js_format2[source]=mt
elif len(_aret)==3: elif len(_aret)==3:
_id,source,mt =_aret _id,source,mt =_aret
js_format2[source]=mt js_format2[source]=mt
@ -70,7 +70,6 @@ def sqlite2json2(self,sqlitefile,targetjson=None):
transkirokuuse=collect[combo.currentIndex()] transkirokuuse=collect[combo.currentIndex()]
for k in js_format2: for k in js_format2:
js_format2[k]=js_format2[k].get(transkirokuuse,'') js_format2[k]=js_format2[k].get(transkirokuuse,'')
# with open(e.text()+'.complex.json','w',encoding='utf8') as ff: # with open(e.text()+'.complex.json','w',encoding='utf8') as ff:
# ff.write(json.dumps(js,ensure_ascii=False,sort_keys=False, indent=4)) # ff.write(json.dumps(js,ensure_ascii=False,sort_keys=False, indent=4))

View File

@ -3,7 +3,7 @@ import functools,os,shutil,windows,json
from PyQt5.QtGui import QFont,QStandardItem,QStandardItemModel from PyQt5.QtGui import QFont,QStandardItem,QStandardItemModel
from PyQt5.QtCore import Qt,QSize from PyQt5.QtCore import Qt,QSize
from traceback import print_exc from traceback import print_exc
from PyQt5.QtWidgets import QFontComboBox,QDialog,QLabel,QComboBox,QPushButton,QFileDialog,QVBoxLayout,QTableView,QHeaderView,QHBoxLayout,QLineEdit from PyQt5.QtWidgets import QFontComboBox,QDialog,QLabel,QComboBox,QPushButton,QFileDialog,QFormLayout,QDialogButtonBox,QHeaderView,QHBoxLayout,QLineEdit
from gui.pretransfile import sqlite2json2 from gui.pretransfile import sqlite2json2
from gui.settingpage_ocr import getocrgrid from gui.settingpage_ocr import getocrgrid
from myutils.config import globalconfig ,_TR,_TRL,savehook_new_data,savehook_new_list from myutils.config import globalconfig ,_TR,_TRL,savehook_new_data,savehook_new_list
@ -130,14 +130,14 @@ def getfridahookgrid(self) :
return grids return grids
def doexportchspatch(exe): def doexportchspatch(exe,realgame):
b=windows.GetBinaryType(exe) b=windows.GetBinaryType(exe)
is64=(b==6) is64=(b==6)
arch=['32','64'][is64] arch=['32','64'][is64]
dllhook=os.path.abspath('./files/plugins/LunaHook/LunaHook{}.dll'.format(arch)) dllhook=os.path.abspath('./files/plugins/LunaHook/LunaHook{}.dll'.format(arch))
dllhost=os.path.abspath('./files/plugins/DLL{}/LunaHost{}.dll'.format(arch,arch)) dllhost=os.path.abspath('./files/plugins/LunaHook/LunaHost{}.dll'.format(arch,arch))
runner=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format(arch)) runner=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format(arch))
windows.CopyFile(dllhook,os.path.join(os.path.dirname(exe),os.path.basename(dllhook)),False) windows.CopyFile(dllhook,os.path.join(os.path.dirname(exe),os.path.basename(dllhook)),False)
@ -147,10 +147,10 @@ def doexportchspatch(exe):
embedconfig={ embedconfig={
'translation_file':'translation.json', 'translation_file':'translation.json',
'target_exe':os.path.basename(exe), 'target_exe':os.path.basename(exe),
'target_exe2':os.path.basename(realgame),
'startup_argument':None, 'startup_argument':None,
'isbit64':is64,
'inject_timeout':1000, 'inject_timeout':1000,
'embedhook':savehook_new_data[exe]['embedablehook'], 'embedhook':savehook_new_data[realgame]['embedablehook'],
'embedsettings':{ 'embedsettings':{
'font':globalconfig['embedded']['changefont_font'] if globalconfig['embedded']['changefont'] else '', 'font':globalconfig['embedded']['changefont_font'] if globalconfig['embedded']['changefont'] else '',
'insertspace_policy':globalconfig['embedded']['insertspace_policy'], 'insertspace_policy':globalconfig['embedded']['insertspace_policy'],
@ -159,18 +159,49 @@ def doexportchspatch(exe):
} }
with open(os.path.join(os.path.dirname(exe),'LunaPatch.json'),'w',encoding='utf8') as ff: with open(os.path.join(os.path.dirname(exe),'LunaPatch.json'),'w',encoding='utf8') as ff:
ff.write(json.dumps(embedconfig,ensure_ascii=False,indent=4)) ff.write(json.dumps(embedconfig,ensure_ascii=False,indent=4))
def getunknowgameexe(self):
dialog = QDialog(self,Qt.WindowCloseButtonHint) # 自定义一个dialog
dialog.setWindowTitle(_TR("选择游戏"))
dialog.resize(QSize(800,10))
formLayout = QFormLayout(dialog)
dialog.setLayout(formLayout)
combo=QComboBox()
combo.addItems([savehook_new_data[_]['title'] for _ in savehook_new_list])
formLayout.addRow(_TR("选择游戏"),combo)
button = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
formLayout.addRow(button)
button.rejected.connect(dialog.close)
button.accepted.connect(dialog.accept)
button.button(QDialogButtonBox.Ok).setText(_TR('确定'))
button.button(QDialogButtonBox.Cancel).setText(_TR('取消'))
if(dialog.exec()):
return savehook_new_list[combo.currentIndex()]
def exportchspatch(self): def exportchspatch(self):
f=QFileDialog.getOpenFileName(filter='*.exe') realgame=getunknowgameexe(self)
exe=f[0] if realgame is None:return
if exe=='':return exe=realgame
exe=exe.replace('/','\\') if exe.lower().endswith('.exe')==False:
if exe not in savehook_new_list:return f=QFileDialog.getOpenFileName(self,caption= _TR("选择EXE文件"),filter='*.exe')
doexportchspatch(exe) exe=f[0]
if exe=='':return
exe=exe.replace('/','\\')
doexportchspatch(exe,realgame)
md5=getfilemd5(exe) md5=getfilemd5(exe)
name= os.path.basename(exe).replace('.'+os.path.basename(exe).split('.')[-1],'') name= os.path.basename(exe).replace('.'+os.path.basename(exe).split('.')[-1],'')
sqlfname_all='./translation_record/'+name+'_'+md5+'.sqlite' sqlfname_all='./translation_record/'+name+'_'+md5+'.sqlite'
sqlite2json2(self,sqlfname_all,os.path.join(os.path.dirname(exe),'translation.json')) if os.path.exists(sqlfname_all)==False:
f=QFileDialog.getOpenFileName(self,caption=_TR("选择预翻译文件"), directory='./translation_record/',filter='*.sqlite')
sqlfname_all=f[0]
if os.path.exists(sqlfname_all):
sqlite2json2(self,sqlfname_all,os.path.join(os.path.dirname(exe),'translation.json'))
else:
with open(os.path.join(os.path.dirname(exe),'translation.json'),'w') as ff:
ff.write("{}")
def gethookembedgrid(self) : def gethookembedgrid(self) :
self.gamefont_comboBox = QFontComboBox( ) self.gamefont_comboBox = QFontComboBox( )
def callback(x): def callback(x):

View File

@ -106,7 +106,7 @@ class texthook(basetext ):
self.declare() self.declare()
self.start() self.start()
def declare(self): def declare(self):
LunaHost=CDLL(gobject.GetDllpath(('LunaHost32.dll','LunaHost64.dll'))) LunaHost=CDLL(gobject.GetDllpath(('LunaHost32.dll','LunaHost64.dll'),os.path.abspath('files/plugins/LunaHook')))
self.Luna_Settings=LunaHost.Luna_Settings self.Luna_Settings=LunaHost.Luna_Settings
self.Luna_Settings.argtypes=c_int,c_bool,c_int,c_int self.Luna_Settings.argtypes=c_int,c_bool,c_int,c_int
self.Luna_Start=LunaHost.Luna_Start self.Luna_Start=LunaHost.Luna_Start

View File

@ -308,6 +308,8 @@
"./files/plugins/shareddllproxy64.exe", "./files/plugins/shareddllproxy64.exe",
"./files/plugins/LunaHook/LunaHook32.dll", "./files/plugins/LunaHook/LunaHook32.dll",
"./files/plugins/LunaHook/LunaHook64.dll", "./files/plugins/LunaHook/LunaHook64.dll",
"./files/plugins/LunaHook/LunaHost64.dll",
"./files/plugins/LunaHook/LunaHost32.dll",
"./files/plugins/LoaderDll.dll", "./files/plugins/LoaderDll.dll",
"./files/plugins/LocaleEmulator.dll", "./files/plugins/LocaleEmulator.dll",
"./files/plugins/hookmagpie.dll" "./files/plugins/hookmagpie.dll"
@ -317,16 +319,14 @@
"./files/plugins/DLL64/winrtutils64.dll", "./files/plugins/DLL64/winrtutils64.dll",
"./files/plugins/DLL64/LunaOCR64.dll", "./files/plugins/DLL64/LunaOCR64.dll",
"./files/plugins/DLL64/libmecab.dll", "./files/plugins/DLL64/libmecab.dll",
"./files/plugins/DLL64/libcurl-x64.dll", "./files/plugins/DLL64/libcurl-x64.dll"
"./files/plugins/DLL64/LunaHost64.dll"
], ],
"32":[ "32":[
"./files/plugins/DLL32/winsharedutils32.dll", "./files/plugins/DLL32/winsharedutils32.dll",
"./files/plugins/DLL32/winrtutils32.dll", "./files/plugins/DLL32/winrtutils32.dll",
"./files/plugins/DLL32/LunaOCR32.dll", "./files/plugins/DLL32/LunaOCR32.dll",
"./files/plugins/DLL32/libmecab.dll", "./files/plugins/DLL32/libmecab.dll",
"./files/plugins/DLL32/libcurl.dll", "./files/plugins/DLL32/libcurl.dll"
"./files/plugins/DLL32/LunaHost32.dll"
] ]
} }

View File

@ -720,5 +720,7 @@
"离线": "غير متصل", "离线": "غير متصل",
"导出翻译补丁": "تصدير ترجمة التصحيح", "导出翻译补丁": "تصدير ترجمة التصحيح",
"语音修正": "صوت تصحيح", "语音修正": "صوت تصحيح",
"藏语": "التيبتية" "藏语": "التيبتية",
"选择EXE文件": "حدد ملف إكس",
"选择预翻译文件": "حدد ملف ما قبل الترجمة"
} }

View File

@ -720,5 +720,7 @@
"离线": "離線", "离线": "離線",
"导出翻译补丁": "匯出翻譯補丁", "导出翻译补丁": "匯出翻譯補丁",
"语音修正": "語音修正", "语音修正": "語音修正",
"藏语": "藏語" "藏语": "藏語",
"选择EXE文件": "選擇EXE檔案",
"选择预翻译文件": "選擇預翻譯檔案"
} }

View File

@ -720,5 +720,7 @@
"离线": "off-line", "离线": "off-line",
"导出翻译补丁": "Export translation patches", "导出翻译补丁": "Export translation patches",
"语音修正": "Voice correction", "语音修正": "Voice correction",
"藏语": "Tibetan" "藏语": "Tibetan",
"选择EXE文件": "Select EXE file",
"选择预翻译文件": "Select pre translated file"
} }

View File

@ -720,5 +720,7 @@
"离线": "Fuera de línea", "离线": "Fuera de línea",
"导出翻译补丁": "Exportar parches de traducción", "导出翻译补丁": "Exportar parches de traducción",
"语音修正": "Corrección de voz", "语音修正": "Corrección de voz",
"藏语": "Tibetano" "藏语": "Tibetano",
"选择EXE文件": "Seleccionar archivo EXE",
"选择预翻译文件": "Seleccionar archivo pretranslatado"
} }

View File

@ -720,5 +720,7 @@
"离线": "Hors ligne", "离线": "Hors ligne",
"导出翻译补丁": "Exporter le patch de traduction", "导出翻译补丁": "Exporter le patch de traduction",
"语音修正": "Correction vocale", "语音修正": "Correction vocale",
"藏语": "Tibétain" "藏语": "Tibétain",
"选择EXE文件": "Sélectionner un fichier exe",
"选择预翻译文件": "Choisir un fichier pré - traduit"
} }

View File

@ -720,5 +720,7 @@
"离线": "off-line", "离线": "off-line",
"导出翻译补丁": "Esporta patch di traduzione", "导出翻译补丁": "Esporta patch di traduzione",
"语音修正": "Correzione vocale", "语音修正": "Correzione vocale",
"藏语": "Tibetano" "藏语": "Tibetano",
"选择EXE文件": "Seleziona file EXE",
"选择预翻译文件": "Seleziona file pre-tradotto"
} }

View File

@ -720,5 +720,7 @@
"离线": "オフライン", "离线": "オフライン",
"导出翻译补丁": "翻訳パッチのエクスポート", "导出翻译补丁": "翻訳パッチのエクスポート",
"语音修正": "音声修正", "语音修正": "音声修正",
"藏语": "チベット語" "藏语": "チベット語",
"选择EXE文件": "EXEファイルを選択",
"选择预翻译文件": "事前翻訳ファイルの選択"
} }

View File

@ -720,5 +720,7 @@
"离线": null, "离线": null,
"导出翻译补丁": "번역 패치 내보내기", "导出翻译补丁": "번역 패치 내보내기",
"语音修正": "음성 수정", "语音修正": "음성 수정",
"藏语": "티베트어" "藏语": "티베트어",
"选择EXE文件": "EXE 파일 선택",
"选择预翻译文件": "사전 번역 파일 선택"
} }

View File

@ -720,5 +720,7 @@
"离线": "off-line", "离线": "off-line",
"导出翻译补丁": "Eksportuj łatki tłumaczeniowe", "导出翻译补丁": "Eksportuj łatki tłumaczeniowe",
"语音修正": "Korekta głosu", "语音修正": "Korekta głosu",
"藏语": "Tybetański" "藏语": "Tybetański",
"选择EXE文件": "Wybierz plik EXE",
"选择预翻译文件": "Wybierz wstępnie przetłumaczony plik"
} }

View File

@ -720,5 +720,7 @@
"离线": "В автономном режиме", "离线": "В автономном режиме",
"导出翻译补丁": "Экспорт исправлений перевода", "导出翻译补丁": "Экспорт исправлений перевода",
"语音修正": "Голосовая коррекция", "语音修正": "Голосовая коррекция",
"藏语": "Тибетский язык" "藏语": "Тибетский язык",
"选择EXE文件": "Выберите файл EXE",
"选择预翻译文件": "Выберите файл для предварительного перевода"
} }

View File

@ -720,5 +720,7 @@
"离线": "ออฟไลน์", "离线": "ออฟไลน์",
"导出翻译补丁": "ส่งออกแพทช์การแปล", "导出翻译补丁": "ส่งออกแพทช์การแปล",
"语音修正": "แก้ไขเสียง", "语音修正": "แก้ไขเสียง",
"藏语": "ทิเบต" "藏语": "ทิเบต",
"选择EXE文件": "เลือกไฟล์ EXE",
"选择预翻译文件": "เลือกไฟล์ที่แปลไว้ล่วงหน้า"
} }

View File

@ -720,5 +720,7 @@
"离线": "off line", "离线": "off line",
"导出翻译补丁": "Çeviri örneklerini dışarı aktar", "导出翻译补丁": "Çeviri örneklerini dışarı aktar",
"语音修正": "Ses düzeltmesi", "语音修正": "Ses düzeltmesi",
"藏语": "TibetanKCharselect unicode block name" "藏语": "TibetanKCharselect unicode block name",
"选择EXE文件": "Select EXE file",
"选择预翻译文件": "Önceden çevirilen dosya seçin"
} }

View File

@ -720,5 +720,7 @@
"离线": "вимкнено", "离线": "вимкнено",
"导出翻译补丁": "Експортувати латки перекладу", "导出翻译补丁": "Експортувати латки перекладу",
"语音修正": "Виправлення голосу", "语音修正": "Виправлення голосу",
"藏语": "Тибетський" "藏语": "Тибетський",
"选择EXE文件": "Виберіть файл EXE",
"选择预翻译文件": "Виберіть попередньо перекладаний файл"
} }

View File

@ -720,5 +720,7 @@
"离线": "Ngoại tuyến", "离线": "Ngoại tuyến",
"导出翻译补丁": "Xuất bản bản vá dịch", "导出翻译补丁": "Xuất bản bản vá dịch",
"语音修正": "Sửa giọng nói", "语音修正": "Sửa giọng nói",
"藏语": "Tây Tạng" "藏语": "Tây Tạng",
"选择EXE文件": "Chọn tập tin EXE",
"选择预翻译文件": "Chọn tập tin pre-translate"
} }

View File

@ -720,5 +720,7 @@
"离线": "", "离线": "",
"导出翻译补丁": "", "导出翻译补丁": "",
"语音修正": "", "语音修正": "",
"藏语": "" "藏语": "",
"选择EXE文件": "",
"选择预翻译文件": ""
} }

View File

@ -105,7 +105,6 @@ class lunapatch{
public: public:
HANDLE hMessage; HANDLE hMessage;
HANDLE hwait; HANDLE hwait;
std::wstring target_exe;
nlohmann::json config; nlohmann::json config;
std::map<std::string,std::string>translation; std::map<std::string,std::string>translation;
std::unordered_set<DWORD>connectedpids; std::unordered_set<DWORD>connectedpids;
@ -116,6 +115,7 @@ public:
bool (*Luna_checkisusingembed)(DWORD pid,uint64_t address,uint64_t ctx1,uint64_t ctx2); bool (*Luna_checkisusingembed)(DWORD pid,uint64_t address,uint64_t ctx1,uint64_t ctx2);
void (*Luna_embedcallback)(DWORD pid,LPCWSTR text,LPCWSTR trans); void (*Luna_embedcallback)(DWORD pid,LPCWSTR text,LPCWSTR trans);
std::set<std::string>notranslation; std::set<std::string>notranslation;
HANDLE hsema;
lunapatch(std::wstring dll,nlohmann::json&&_translation,nlohmann::json&&_config):translation(_translation),config(_config){ lunapatch(std::wstring dll,nlohmann::json&&_translation,nlohmann::json&&_config):translation(_translation),config(_config){
auto LunaHost=LoadLibraryW(dll.c_str()); auto LunaHost=LoadLibraryW(dll.c_str());
@ -125,13 +125,12 @@ public:
Luna_useembed=(decltype(Luna_useembed))GetProcAddress(LunaHost,"Luna_useembed"); Luna_useembed=(decltype(Luna_useembed))GetProcAddress(LunaHost,"Luna_useembed");
Luna_checkisusingembed=(decltype(Luna_checkisusingembed))GetProcAddress(LunaHost,"Luna_checkisusingembed"); Luna_checkisusingembed=(decltype(Luna_checkisusingembed))GetProcAddress(LunaHost,"Luna_checkisusingembed");
Luna_embedcallback=(decltype(Luna_embedcallback))GetProcAddress(LunaHost,"Luna_embedcallback"); Luna_embedcallback=(decltype(Luna_embedcallback))GetProcAddress(LunaHost,"Luna_embedcallback");
hsema=CreateSemaphore(NULL,0,100,NULL);
Luna_Start(&hMessage); Luna_Start(&hMessage);
std::thread([&](){Parsehostmessage();}).detach(); std::thread([&](){Parsehostmessage();}).detach();
} }
void run(){ void run(){
target_exe=StringToWideString(config["target_exe"]); auto target_exe=StringToWideString(config["target_exe"]);
auto _startup_argument=config["startup_argument"]; auto _startup_argument=config["startup_argument"];
@ -147,29 +146,29 @@ public:
for(auto &text:notranslation){ for(auto &text:notranslation){
translation[text]=""; translation[text]="";
} }
auto notrs=nlohmann::json(notranslation).dump(4); auto notrs=nlohmann::json(translation).dump(4);
std::ofstream of; std::ofstream of;
of.open("no_translation.json"); of.open(std::string(config["translation_file"]));
of<<notrs;
of.close();
notrs=nlohmann::json(translation).dump(4);
of.open("no_translation_and_translation.json");
of<<notrs; of<<notrs;
of.close(); of.close();
} }
} }
void wait(){ void wait(){
WaitForSingleObject(hwait,INFINITE); WaitForSingleObject(hwait,INFINITE);
while(connectedpids.size())
WaitForSingleObject(hsema,INFINITE);
} }
void inject(){ void inject(){
//chrome has multi process //chrome has multi process
Sleep(config["inject_timeout"]); Sleep(config["inject_timeout"]);
auto pids=EnumerateProcesses(target_exe); for(auto exe :std::set<std::string>{config["target_exe"],config["target_exe2"]})
for(auto pid:pids){ {
Luna_Inject(pid,L""); auto pids=EnumerateProcesses(StringToWideString(exe));
for(auto pid:pids){
wprintf(L"%d\n",pid);
Luna_Inject(pid,L"");
}
} }
} }
std::wstring findtranslation(const std::wstring& text){ std::wstring findtranslation(const std::wstring& text){
auto utf8text=WideStringToString(text); auto utf8text=WideStringToString(text);
@ -200,6 +199,7 @@ public:
case 1: case 1:
{ {
connectedpids.erase(message.pid); connectedpids.erase(message.pid);
ReleaseSemaphore(hsema,1,NULL);
} }
break; break;
case 7: case 7:
@ -272,18 +272,12 @@ bool checkisapatch(){
std::string translation_file=configjson["translation_file"]; std::string translation_file=configjson["translation_file"];
jsonfile.open(translation_file); jsonfile.open(translation_file);
std::map<std::string,std::string> translation=nlohmann::json::parse(jsonfile); std::map<std::string,std::string> translation=nlohmann::json::parse(jsonfile);
jsonfile.close(); jsonfile.close();
auto LunaHost=(curr/(std::wstring(L"LunaHost")+std::to_wstring(8*sizeof(void*)))).wstring();
bool isbit64=configjson["isbit64"];
auto bitappendix=isbit64?L"64":L"32";
auto LunaHost=(curr/(std::wstring(L"LunaHost")+bitappendix)).wstring();
auto LunaHook=(curr/(std::wstring(L"LunaHook")+bitappendix)).wstring();
lunapatch _lunapatch(LunaHost,std::move(translation),std::move(configjson)); lunapatch _lunapatch(LunaHost,std::move(translation),std::move(configjson));
_lunapatch.run(); _lunapatch.run();
_lunapatch.inject(); _lunapatch.inject();
_lunapatch.wait(); _lunapatch.wait();