Compare commits

...

27 Commits

Author SHA1 Message Date
4335a4560a waffle2 hook fix for shinyu 2025-01-04 13:55:35 +08:00
22946df452 合并Blu3train:Yuris3Engine
修改yuris6 hook为适配英语版yuris
*这破坏了该hook原先对日文版yuris的支持
2024-12-21 23:47:14 +08:00
3b22857d12 update
buildenv, deepl, dac
2024-12-17 10:34:13 -08:00
Akash Mozumdar
df5b830d17 revert the dumbest change I ever made 2023-08-26 07:36:48 -04:00
Akash Mozumdar
f3fbe04409 standardize file names 2023-04-24 14:48:16 -04:00
Glaringsoul
5adeb1fab7 Update README_GER.md 2023-04-24 14:40:55 -04:00
Glaringsoul
5c7b41dd84 Create README_GER.md
Translated the README.MD by hand into German.

Will probably tackle the text.ccp next, although I haven't looked at it, so I cannot really say how long that can take.

Some parts especially words that are commonly used in German as Anglicisms are left as is, this is not an oversight by me, but intentional.
2023-04-24 14:40:55 -04:00
秋庭里香
92e2e85191 Update Chinese (Simplified) translation
and add a link to text.cpp in the README.md
2023-04-24 14:34:40 -04:00
Blu3train
0bc23ba2c7 update ShinaRio 2.50+ 2023-04-24 14:28:49 -04:00
Akash Mozumdar
fd8a090e28 remove workaround for fixed msvc bug 2023-04-21 19:43:32 -04:00
Akash Mozumdar
aa00d9e789 ignore extra parameters #947 2023-04-21 19:42:54 -04:00
Akash Mozumdar
cfa11c5646 use drive relative path 2023-04-21 19:23:14 -04:00
Akash Mozumdar
446f6d44e6 upgrade build configuration to not rely on qt creator which is no longer required by qt installer 2023-04-21 18:31:17 -04:00
Akash Mozumdar
ff1a7a358c handle toggling of cache properly, error cases consistently, and stop saving cache unnecessarily 2023-04-21 17:23:25 -04:00
Akash Mozumdar
60a5d74eda improve config loading and prevent crashes 2023-04-21 16:49:22 -04:00
Akash Mozumdar
4cebe9462f insane hack to work around false positive in SearchForText 2023-04-21 16:41:00 -04:00
Akash Mozumdar
d97ebd4fbb edge is also usable for devtools 2023-04-21 16:35:19 -04:00
Akash Mozumdar
233e75225c add link to stylesheets 2022-09-10 20:01:48 -04:00
Akash Mozumdar
72ad51f039 tighten abel detection 2022-08-09 00:02:27 -04:00
Akash Mozumdar
39fcfaf644 restore shinario hook 2022-08-08 23:13:51 -04:00
RoARene317
5eb0440f01 Fix some typos 2022-08-08 18:39:16 -06:00
RoARene317
c4ca84d39b Change from text --> Teks in Indonesian 2022-08-08 18:39:16 -06:00
RoARene317
c7b818aa75 Removing some english and fix translations
Fix some Indonesian translations that still english to make it Indonesian but still understandable for young people.
2022-08-08 18:39:16 -06:00
Blu3train
2cb45ab9e3 DeepL Translate: Added Turkish and Indonesian 2022-07-26 23:14:57 -06:00
Blu3train
72132239a5 new browser size setting for DeepL blocking in hidden mode 2022-07-26 22:29:29 -06:00
Blu3train
5eaafbe81c Devtools extensions: chrome user data cache error if there are spaces in path 2022-07-26 22:29:29 -06:00
Akash Mozumdar
97f2bc6304 change qt version to make alpha builds compatible with releases 2022-07-26 23:59:26 -04:00
35 changed files with 657 additions and 213 deletions

View File

@ -5,21 +5,21 @@ skip_branch_with_pr: false
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
arch: x64
platform: x64
qtbin: msvc2019_64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
qtbin: msvc2017_64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
arch: x86
platform: Win32
qtbin: msvc2019
qtbin: msvc2017
before_build:
- git submodule update --init
- cd C:\
- mkdir %arch%
- cd %arch%
- cmake -G "Visual Studio 16 2019" -A "%platform%" -DQt5_DIR="C:\Qt\5.15\%qtbin%\lib\cmake\Qt5" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DVERSION="" ../Textractor
- cmake -G "Visual Studio 15 2017" -A %platform% -DQt5_DIR="C:\Qt\5.13.2\%qtbin%\lib\cmake\Qt5" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DVERSION="" ../Textractor
build:
project: C:\%arch%\Textractor.sln

View File

@ -35,6 +35,10 @@ target_precompile_headers(pch PUBLIC include/common.h)
file(GLOB ASSETS assets/*)
file(COPY ${ASSETS} DESTINATION ${CMAKE_FINAL_OUTPUT_DIRECTORY})
include(QtUtils)
msvc_registry_search()
find_qt5(Core Widgets WinExtras WebSockets)
add_library(text text.cpp)
target_compile_definitions(text PRIVATE ${TEXT_LANGUAGE})
link_libraries(text)

View File

@ -4,25 +4,29 @@
"name": "x86-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"cmakeCommandArgs": "-DQT_ROOT=/Qt",
"inheritEnvironments": [ "msvc_x86" ]
},
{
"name": "x86-RelWithDebInfo",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"cmakeCommandArgs": "-DQT_ROOT=/Qt",
"inheritEnvironments": [ "msvc_x86" ]
},
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"cmakeCommandArgs": "-DQT_ROOT=/Qt",
"inheritEnvironments": [ "msvc_x64" ]
},
{
"name": "x64-RelWithDebInfo",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"cmakeCommandArgs": "-DQT_ROOT=/Qt",
"inheritEnvironments": [ "msvc_x64" ]
}
]
}
}

View File

@ -1,7 +1,3 @@
include(QtUtils)
msvc_registry_search()
find_qt5(Core Widgets WinExtras)
add_executable(Textractor WIN32
main.cpp
exception.cpp

View File

@ -88,6 +88,8 @@ namespace
TextThread* current = nullptr;
MainWindow* This = nullptr;
void FindHooks();
QString TextThreadString(TextThread& thread)
{
return QString("%1:%2:%3:%4:%5: %6").arg(
@ -274,7 +276,8 @@ namespace
void AddHook(QString hook)
{
if (QString hookCode = QInputDialog::getText(This, ADD_HOOK, CODE_INFODUMP, QLineEdit::Normal, hook, &ok, Qt::WindowCloseButtonHint); ok)
if (auto hp = HookCode::Parse(S(hookCode))) try { Host::InsertHook(selectedProcessId, hp.value()); } catch (std::out_of_range) {}
if (hookCode.startsWith("S") || hookCode.startsWith("/S")) FindHooks(); // backwards compatibility for old hook search UX
else if (auto hp = HookCode::Parse(S(hookCode))) try { Host::InsertHook(selectedProcessId, hp.value()); } catch (std::out_of_range) {}
else Host::AddConsoleOutput(INVALID_CODE);
}

View File

@ -2,7 +2,7 @@
![How it looks](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (a.k.a. NextHooker) is an open-source x86/x64 video game text hooker for Windows 7+ (and Wine) based off of [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
Watch the [tutorial video](docs/TUTORIAL.md) for a quick rundown on using it.
@ -34,7 +34,7 @@ See the extensions folder for examples of what extensions can do.
All contributions are appreciated! Please email me at akashmozumdar@gmail.com if you have any questions about the codebase.<br>
You should use the standard process of making a pull request (fork, branch, commit changes, make PR from your branch to my master).<br>
Contributing a translation is easy: text.cpp contains all of the text strings that you need to translate. Translations of this README or the tutorial video transcript are also welcome.
Contributing a translation is easy: [text.cpp](text.cpp) contains all of the text strings that you need to translate. Translations of this README or the tutorial video transcript are also welcome.
## Compiling
Before compiling Textractor, you need Qt version 5.13 and Visual Studio with CMake support.

52
README_DE.md Normal file
View File

@ -0,0 +1,52 @@
# Textractor
![Wie es aussieht](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (a.b.a. NextHooker) ist ein open-source x86/x64 Video spiel Text hooker für Windows 7+ (und Wine) basierend auf [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
Schau das [Tutorial Video](docs/TUTORIAL.md) (auf Englisch) an für einen schnellen Überblick wie du Textractor verwendest.
## Download
Der offizielle Release ist [hier](https://github.com/Artikash/Textractor/releases) zu finden.<br>
Der letzte Release von ITHVNR ist [hier](https://drive.google.com/open?id=13aHF4uIXWn-3YML_k2YCDWhtGgn5-tnO).<br>
Der experimentelle Release von Textractor (mit debug Informationen) ist [hier](https://ci.appveyor.com/project/Artikash/textractor/history) in der 'Artifacts'
Kategorie des jeweiligen Jobs.
## Features
- Modular und Anpassbar
- Automatischen 'hooken' von mehreren Engines (einige davon welche keine VNR Support haben!)
- Text 'hooken' mithilfe von /H "hook" Codes (die meisten AGTH codes funktionieren)
- Automatische suche nach funktionierenden Hook's
## Support
Wenn ihr irgendwelche Fehler, Spiele bei denen Textractor nicht funktioniert, oder Fragen/Anmerkungen habt lasst es mich bitte wissen.<br>
Falls ihr Probleme mit einem Spiel habt, schickt mir einen kostenlosen download Link von dem Spiel oder schenkt es mir auf [Steam](https://steamcommunity.com/profiles/76561198097566313/).
## Erweiterungen
Siehe [Example Extension project](https://github.com/Artikash/ExampleExtension) für Anleitungen, wie man eine Erweiterung erstellt.<br>
Im 'Extensions' Ordner sind Beispiele für Erweiterungen.
## Unterstützen
Ich bin dankbar für alle Unterstützungen! Schickt mir eine E-Mail an akashmozumdar@gmail.com falls ihr Fragen zur Codebasis habt.<br>
Verwendet bitte als Standard eine pull Request (fork, branch, commit) zum Master Release.<br>
Zu Übersetzungen beizutragen ist einfach: [text.cpp](text.cpp) enthält alle text Strings welche übersetzt werden sollen. Übersetzungen der README oder des Tutorial Video Transkripts sind ebenfalls willkommen.
## Compiling
Zum Compilen braucht ihr Qt Version 5.13 und Visual Studio mit CMake Unterstützung.
Erstellt einen Clone vom Quellcode und initialisiert die submodule mit 'git clone https://github.com/Artikash/Textractor.git' und 'git submodule update --init'.
Ihr solltet danach in der Lage sein, den Quellordner in Visual Studio zu öffnen und anzufangen.
## Projekt Architektur
Der Host injiziert texthooks in den ziel Prozess und verbindet ihn mit 2 Pipe Dateien.
Texthook wartet auf die Pipe und injiziert Instruktionen für den Text Output (z.b. TextOut, GetGlyphOutline) welche durch die Pipe gesendet werden.<br>
Weitere Informationen werden durch geteilten Speicher ausgetauscht.<br>
Der Text, welchen der Host durch die Pipe erhält, wird dann verarbeitet, bevor er wieder an die GUI gesendet wird.<br>
Zu guter Letzt, sendet die GUI den Text an die Erweiterung, welche einen lesbaren Output anzeigt.
## [Entwickler](docs/CREDITS.md)

View File

@ -1,6 +1,6 @@
# Textractor
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
## [Video tutorial](docs/TUTORIAL.md)

View File

@ -2,7 +2,7 @@
![À quoi ça ressemble](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (a.k.a. NextHooker) est un traducteur de jeux-videos basé surtout sur du texte en open source x86/x64 pour Windows/Wine [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
Regarde le [tutorial video](docs/TUTORIAL.md) pour un aperçu rapide de son utilisation.
@ -32,7 +32,7 @@ Voir le dossier des extensions pour des exemples de ce que les extensions peuven
Toutes les contributions sont appréciées! Veuillez m'envoyer un e-mail À akashmozumdar@gmail.com si vous avez des questions sur la base de code. <br>
Vous devez utiliser le processus standard de création d'une demande d'extraction (fork, branch, commit changes, make PR from your branch to my master). <br>
Contribuer à une traduction est simple: il suffit de traduire les chaînes dans text.cpp ainsi que ce fichier README.
Contribuer à une traduction est simple: il suffit de traduire les chaînes dans [text.cpp](text.cpp) ainsi que ce fichier README.
## Compilation

View File

@ -2,9 +2,9 @@
![How it looks](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (a.k.a NextHooker) adalah text hooker video game untuk Windows/Wine x86/x64 berbasis open-source yang didasari oleh [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
**Textractor** (a.k.a NextHooker) adalah teks hooker video game untuk Windows/Wine x86/x64 berbasis open-source yang didasari oleh [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
Lihat [video tutorial](docs/TUTORIAL.md) untuk mengetahui bagaimana cara menggunakannya.
## Pengunduhan
@ -21,36 +21,33 @@ Rilisan Terakhir ITHVNR dapat diunduh [disini](https://drive.google.com/open?id=
## Dukungan
Please let me know of any bugs, games that Textractor has trouble hooking, feature requests, or other suggestions.<br>
If you have trouble hooking a game please email me a place where I can freely download it, or gift it to me on [Steam](https://steamcommunity.com/profiles/76561198097566313/).
Tolong beritahu saya jika kamu menemukan bug, game yang tidak dapat di tempel oleh Textractor, permintaan fitur, atau usulan lain.<br>
Jika kamu memiliki masalah dalam menempelkan kedalam game tolong email saya link agar saya dapat mendownload game tersebut, atau gift game tersebut di [Steam](https://steamcommunity.com/profiles/76561198097566313/).
Tolong beritahu saya jika kamu menemukan kutu, game yang tidak dapat di tempel oleh Textractor, permintaan fitur, atau usulan lain.<br>
Jika kamu memiliki masalah dalam menempelkan kedalam game tolong email saya link agar saya dapat mengunduh game tersebut, atau hadiahkan game tersebut di [Steam](https://steamcommunity.com/profiles/76561198097566313/).
## Ekstensi
Lihat [project sampel ekstensi saya](https://github.com/Artikash/ExampleExtension) untuk melihat bagaimana cara membuat ekstensi.<br>
Lihat folder extensions untuk melihat sampel ekstensi.
Lihat ekstensi folder untuk melihat sampel ekstensi.
## Kontribusi
Seluruh kontribusi diapresiasi! Tolong email saya di akashmozumdar@gmail.com jika kamu memiliki pertanyaan mengenai codebase nya.<br>
Kamu harus menggunakan proses standar dalam membuat permintaan pull(fork, branch, commit changes, membuat PR dari branch kamu ke master saya).<br>
Berkontribusi dalam penerjemahan dapat dilakukan dengan mudah : cukup terjemahkan string dari text.cpp lalu terjemahkan README ini.
Seluruh kontribusi diapresiasi! Tolong email saya di akashmozumdar@gmail.com jika kamu memiliki pertanyaan mengenai kode dasar nya.<br>
Kamu harus menggunakan proses standar dalam membuat permintaan pull(fork, cabang, perubahan commit, membuat PR dari cabang kamu ke master saya).<br>
Berkontribusi dalam penerjemahan dapat dilakukan dengan mudah : cukup terjemahkan string dari [text.cpp](text.cpp) lalu terjemahkan README ini.
## Compiling
## Mengcompile
Sebelum melakukan proses compile *Textractor*, kamu harus memiliki Visual Studio dengan dukungan Cmake, juga dengan Qt version 5.13<br>
Lalu kamu dapat membuka folder di Visual Studio, dan build. Run Textractor.exe.
Lalu kamu dapat membuka folder di Visual Studio, dan build. Jalankan Textractor.exe.
## Arsitektur Project
Host (lihat folder host) menginject texthook.dll (dibuat dari folder texthook) kedalam target process dan disambungkan lewat 2 file pipe.<br>
Host (lihat folder host) menyuntikan texthook.dll (dibuat dari folder texthook) kedalam target proses dan disambungkan lewat 2 file pipe.<br>
Host menulis ke hostPipe, texthook menulis ke hookPipe.<br>
texthook menunggu pipe tersambung, lalu menginject beberapa instruksi ke teks yang menghasilkan fungsi (contoh: TextOut, GetGlyphOutline) yang membuat input dikirim melewati pipa.<br>
texthook menunggu pipe tersambung, lalu menyuntikan beberapa instruksi ke teks yang menghasilkan fungsi (contoh: TextOut, GetGlyphOutline) yang membuat input dikirim melewati pipa.<br>
Informasi tambahan tentang hook dipindahkan melewati shared memory.<br>
Text yang diterima host melewati pipe lalu diproses lagi sebelum dikembalikan ke GUI.<br>
Dan pada akhirnya, GUI melepas text ke ekstensi sebelum menampilkan teks.
Teks yang diterima host melewati pipe lalu diproses lagi sebelum dikembalikan ke GUI.<br>
Dan pada akhirnya, GUI melepas teks ke ekstensi sebelum menampilkan teks.
## [Pengembang](docs/CREDITS.md)

View File

@ -2,7 +2,7 @@
![Come si vede](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (a.k.a. NextHooker) è un agganciatore di testi di videogiochi open-source per Windows/Wine basato su[ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
Guarda il [video tutorial](docs/TUTORIAL.md) per una sintesi veloce sul suo utilizzo.
@ -33,7 +33,7 @@ Guardate la cartella delle estenzioni per esempi di cosa possono fare le estenzi
Tutti i contributi sono apprezzati! Inviatemi un email a akashmozumdar@gmail.com se avete delle domande sul codebase.<br>
Dovreste usare il processo standard di creare una pull request (fork, branch, commit changes, crea PR dal vostro ramo al mio master).<br>
Contribuire alla traduzione è semplice: traduci le stringhe in text.cpp cosi come questo README.
Contribuire alla traduzione è semplice: traduci le stringhe in [text.cpp](text.cpp) cosi come questo README.
## Compiling

View File

@ -1,6 +1,6 @@
# Textractor
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** はビジュアルノベル文字抽出プログラム。

View File

@ -2,7 +2,7 @@
![How it looks](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (a.k.a. NextHooker)는 Windows/Wine에서 작동하는 [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine)을 기반으로 한 오픈소스 x86/x64 비디오게임 텍스트 후커 입니다.<br>
빠른 사용법의 이해를 위해 [tutorial video](docs/TUTORIAL.md) 를 참고하세요.

View File

@ -2,7 +2,7 @@
![Como se Parece](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (também conhecido como NextHooker) é um extrator de textos de video-games x86/x64 para Windows/Wine baseado no [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
Assista ao [vídeo tutorial](docs/TUTORIAL.md) para uma rápida apresentação de como utilizá-lo.
@ -33,7 +33,7 @@ Veja a pasta de extensões para mais exemplos do que as extensões são capazes
Todas contribuições são bem-vindas! Por favor, me mande um e-mail no endereço akashmozumdar@gmail.com caso tenha alguma dúvida quanto ao codebase.<br>
Você deve seguir o processo padrão de fazer um pull request (fork, branch, realizar mudanças, realizar o PR do seu branch para o meu master).<br>
Contribuir com uma tradução é fácil: basta traduzir as linhas do text.cpp assim como esse README.
Contribuir com uma tradução é fácil: basta traduzir as linhas do [text.cpp](text.cpp) assim como esse README.
## Compilando

View File

@ -2,7 +2,7 @@
![Как это выглядит](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor** (a.k.a. NextHooker) это проект x86/x64 Windows/Wine программы для захвата текста из видеоигр, основанный на [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>
Смотреть [обучающее видео](docs/TUTORIAL.md) для быстрого ознакомления.
@ -33,7 +33,7 @@
Любой вклад приветствуется! Пишите мне(автору) на akashmozumdar@gmail.com, если у вас есть любые вопросы о кодовой базе.<br>
Используйте стандартные действия для создания pull request (fork, branch, commit changes, создайте PR из своей ветки branch на мой master).<br>
Вклад в перевод совсем не сложен: просто переведите строки в text.cpp, также, как и этот README.
Вклад в перевод совсем не сложен: просто переведите строки в [text.cpp](text.cpp), также, как и этот README.
## Компиляция

View File

@ -1,6 +1,6 @@
# Textractor
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
## 概述
@ -30,7 +30,7 @@ Textractor 的发行版可以在[这里](https://github.com/Artikash/Textractor/
欢迎一切贡献!如有任何关于代码的疑问,请向 akashmozumdar@gmail.com 发邮件.<br>
你应当使用创建 PR 的标准过程 (分岔 (fork), 分支 (branch), 提交变化, 创建从你的分支到我的 master 分支的 PR).<br>
提供翻译贡献很简单: 只需翻译 text.cpp 中的字符串和这份 README 即可.
提供翻译贡献很简单: 只需翻译 [text.cpp](text.cpp) 中的字符串和这份 README 即可.
## 编译

View File

@ -2,7 +2,7 @@
![How it looks](screenshot.png)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md)
[English](README.md) ● [Español](README_ES.md) ● [简体中文](README_SC.md) ● [Русский](README_RU.md) ● [한국어](README_KR.md) ● [ภาษาไทย](README_TH.md) ● [Français](README_FR.md) ● [Italiano](README_IT.md) ● [日本語](README_JP.md) ● [Bahasa Indonesia](README_ID.md) ● [Português](README_PT.md) ● [Deutsch](README_DE.md)
**Textractor**
(หรือ NextHooker) คือโปรแกรมโอเพนซอร์ซสำหรับปฏิบัติการที่มีหน้าที่เพื่อเชื่อมกับตัวอักษรกับเกมจากที่มาจากระบบปฏิบัติการ Window/Wine โดยมีแบบดังเดิมมาจาก [ITHVNR](https://web.archive.org/web/20160202084144/http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine).<br>

View File

@ -1,49 +1,24 @@
macro(msvc_registry_search)
if(NOT DEFINED Qt5_DIR)
# look for user-registry pointing to qtcreator
get_filename_component(QT_BIN [HKEY_CURRENT_USER\\Software\\Classes\\Applications\\QtProject.QtCreator.pro\\shell\\Open\\Command] PATH)
if (NOT EXISTS ${QT_ROOT})
# look for user-registry pointing to qtcreator
get_filename_component(QT_ROOT [HKEY_CURRENT_USER\\Software\\Classes\\Applications\\QtProject.QtCreator.pro\\shell\\Open\\Command] PATH)
# get root path so we can search for 5.3, 5.4, 5.5, etc
string(REPLACE "/Tools" ";" QT_BIN "${QT_BIN}")
list(GET QT_BIN 0 QT_BIN)
file(GLOB QT_VERSIONS "${QT_BIN}/5.1*")
list(SORT QT_VERSIONS)
# assume the latest version will be last alphabetically
list(REVERSE QT_VERSIONS)
list(GET QT_VERSIONS 0 QT_VERSION)
# fix any double slashes which seem to be common
string(REPLACE "//" "/" QT_VERSION "${QT_VERSION}")
if(MSVC_VERSION GREATER_EQUAL 1920)
set(QT_MSVC 2019)
elseif(MSVC_VERSION GREATER_EQUAL 1910)
set(QT_MSVC 2017)
elseif(MSVC_VERSION GREATER_EQUAL 1900)
set(QT_MSVC 2015)
else()
message(WARNING "Unsupported MSVC toolchain version")
# get root path
string(REPLACE "/Tools" ";" QT_ROOT "${QT_ROOT}")
list(GET QT_ROOT 0 QT_ROOT)
endif()
set(QT_VERSION 5.13.2)
set(QT_MSVC 2019)
if(QT_MSVC)
if(CMAKE_CL_64)
SET(QT_SUFFIX "_64")
else()
set(QT_SUFFIX "")
endif()
# MSVC 2015+ is only backwards compatible
if(EXISTS "${QT_VERSION}/msvc${QT_MSVC}${QT_SUFFIX}")
set(Qt5_DIR "${QT_VERSION}/msvc${QT_MSVC}${QT_SUFFIX}/lib/cmake/Qt5")
elseif(QT_MSVC GREATER_EQUAL 2019 AND EXISTS "${QT_VERSION}/msvc2017${QT_SUFFIX}")
set(Qt5_DIR "${QT_VERSION}/msvc2017${QT_SUFFIX}/lib/cmake/Qt5")
elseif(QT_MSVC GREATER_EQUAL 2017 AND EXISTS "${QT_VERSION}/msvc2015${QT_SUFFIX}")
set(Qt5_DIR "${QT_VERSION}/msvc2015${QT_SUFFIX}/lib/cmake/Qt5")
else()
message(WARNING "Required QT5 toolchain is not installed")
endif()
set(Qt5_DIR "${QT_VERSION}/msvc2017${QT_SUFFIX}/lib/cmake/Qt5")
endif()
endif()
endmacro()
@ -53,6 +28,11 @@ macro(find_qt5)
#set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
#add_definitions(-DQT_DEPRECATED_WARNINGS -DQT_DISABLE_DEPRECATED_BEFORE=0x060000)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(Qt5_DIR "C:/Qt/Qt5.13.2/5.13.2/msvc2017_64/lib/cmake/Qt5")
else()
set(Qt5_DIR "C:/Qt/Qt5.13.2/5.13.2/msvc2017/lib/cmake/Qt5")
endif()
find_package(Qt5 COMPONENTS ${ARGN})
if(Qt5_FOUND)

View File

@ -14,7 +14,7 @@
- French translation by [Racky](mailto:maitrenoah@gmail.com) and [Gratusfr](https://github.com/Gratusfr)
- Spanish translation by [scese250](https://github.com/scese250)
- Turkish translation by [niisokusu](https://reddit.com/u/niisokusu)
- Simplified Chinese translation by [tinyAdapter](https://github.com/tinyAdapter) and [lgztx96](https://github.com/lgztx96)
- Simplified Chinese translation by [tinyAdapter](https://github.com/tinyAdapter), [lgztx96](https://github.com/lgztx96) and [chinanoahli](https://github.com/chinanoahli)
- Russian translation by [TokcDK](https://github.com/TokcDK)
- Indonesian translation by [Hawxone](https://github.com/Hawxone)
- Portuguese translation by [TsumiHokiro](https://github.com/TsumiHokiro)

View File

@ -1,6 +1,3 @@
include(QtUtils)
msvc_registry_search()
find_qt5(Core Widgets WebSockets)
cmake_policy(SET CMP0037 OLD)
add_library(Bing\ Translate MODULE bingtranslate.cpp translatewrapper.cpp network.cpp extensionimpl.cpp)

View File

@ -49,7 +49,7 @@ private:
}
static constexpr C endImpl[5] = { '|', 'E', 'N', 'D', '|' };
static constexpr std::basic_string_view end{ endImpl, 5 };
static constexpr std::basic_string_view<C> end{ endImpl, 5 };
std::basic_streambuf<char>& streambuf;
std::basic_string<C> buffer;

View File

@ -9,92 +9,119 @@ const char* TRANSLATION_PROVIDER = "DeepL Translate";
const char* GET_API_KEY_FROM = "https://www.deepl.com/pro.html#developer";
extern const QStringList languagesTo
{
"Arabic",
"Bulgarian",
"Chinese (Simplified)",
"Czech",
"Danish",
"Dutch",
"English (American)",
"German",
"Greek",
"English (backward compatibility)",
"English (British)",
"English (American)",
"Spanish",
"Estonian",
"Finnish",
"French",
"German",
"Greek",
"Hungarian",
"Indonesian",
"Italian",
"Japanese",
"Latvian",
"Korean",
"Lithuanian",
"Latvian",
"Norwegian Bokmål",
"Dutch",
"Polish",
"Portuguese (Brazil)",
"Portuguese (Portugal)",
"Portuguese (backward compatibility)",
"Portuguese (Brazilian)",
"Portuguese (all Portuguese variants excluding Brazilian Portuguese)",
"Romanian",
"Russian",
"Slovak",
"Slovenian",
"Spanish",
"Swedish"
"Swedish",
"Turkish",
"Ukrainian",
"Chinese (backward compatibility)",
"Chinese (simplified)",
"Chinese (traditional)"
},
languagesFrom
{
"Arabic",
"Bulgarian",
"Chinese",
"Chinese (all Chinese variants)",
"Czech",
"Danish",
"Dutch",
"English",
"English (all English variants)",
"Estonian",
"Finnish",
"French",
"German",
"Greek",
"Hungarian",
"Indonesian",
"Italian",
"Japanese",
"Korean",
"Latvian",
"Lithuanian",
"Norwegian Bokmål",
"Polish",
"Portuguese",
"Portuguese (all Portuguese variants)",
"Romanian",
"Russian",
"Slovak",
"Slovenian",
"Spanish",
"Swedish"
"Swedish",
"Turkish",
"Ukrainian"
};
extern const std::unordered_map<std::wstring, std::wstring> codes
{
{ { L"Arabic" }, { L"AR" } },
{ { L"Bulgarian" }, { L"BG" } },
{ { L"Chinese" }, { L"ZH" } },
{ { L"Chinese (Simplified)" }, { L"ZH" } },
{ { L"Czech" }, { L"CS" } },
{ { L"Danish" }, { L"DA" } },
{ { L"Dutch" }, { L"NL" } },
{ { L"English" }, { L"EN" } },
{ { L"English (American)" }, { L"EN-US" } },
{ { L"German" }, { L"DE" } },
{ { L"Greek" }, { L"EL" } },
{ { L"English (all English variants)" }, { L"EN" } },
{ { L"English (backward compatibility)" }, { L"EN" } },
{ { L"English (British)" }, { L"EN-GB" } },
{ { L"English (American)" }, { L"EN-US" } },
{ { L"Spanish" }, { L"ES" } },
{ { L"Estonian" }, { L"ET" } },
{ { L"Finnish" }, { L"FI" } },
{ { L"French" }, { L"FR" } },
{ { L"German" }, { L"DE" } },
{ { L"Greek" }, { L"EL" } },
{ { L"Hungarian" }, { L"HU" } },
{ { L"Indonesian" }, { L"ID" } },
{ { L"Italian" }, { L"IT" } },
{ { L"Japanese" }, { L"JA" } },
{ { L"Latvian" }, { L"LV" } },
{ { L"Korean" }, { L"KO" } },
{ { L"Lithuanian" }, { L"LT" } },
{ { L"Latvian" }, { L"LV" } },
{ { L"Norwegian Bokmål" }, { L"NB" } },
{ { L"Dutch" }, { L"NL" } },
{ { L"Polish" }, { L"PL" } },
{ { L"Portuguese" }, { L"PT" } },
{ { L"Portuguese (Brazil)" }, { L"PT-BR" } },
{ { L"Portuguese (Portugal)" }, { L"PT-PT" } },
{ { L"Portuguese (all Portuguese variants)" }, { L"PT" } },
{ { L"Portuguese (backward compatibility)" }, { L"PT" } },
{ { L"Portuguese (Brazilian)" }, { L"PT-BR" } },
{ { L"Portuguese (all Portuguese variants excluding Brazilian Portuguese)" }, { L"PT-PT" } },
{ { L"Romanian" }, { L"RO" } },
{ { L"Russian" }, { L"RU" } },
{ { L"Slovak" }, { L"SK" } },
{ { L"Slovenian" }, { L"SL" } },
{ { L"Spanish" }, { L"ES" } },
{ { L"Swedish" }, { L"SV" } },
{ { L"Turkish" }, { L"TR" } },
{ { L"Ukrainian" }, { L"UK" } },
{ { L"Chinese (all Chinese variants)" }, { L"ZH" } },
{ { L"Chinese (backward compatibility)" }, { L"ZH" } },
{ { L"Chinese (simplified)" }, { L"ZH-HANS" } },
{ { L"Chinese (traditional)" }, { L"ZH-HANT" } },
{ { L"?" }, { L"auto" } }
};
bool translateSelectedOnly = true, useRateLimiter = true, rateLimitSelected = true, useCache = true, useFilter = true;

View File

@ -36,11 +36,11 @@ namespace
if (process) DevTools::Close();
auto args = FormatString(
L"%s --proxy-server=direct:// --disable-extensions --disable-gpu --user-data-dir=%s\\devtoolscache --remote-debugging-port=9222",
L"%s --proxy-server=direct:// --disable-extensions --disable-gpu --no-first-run --user-data-dir=\"%s\\devtoolscache\" --remote-debugging-port=9222",
chromePath,
std::filesystem::current_path().wstring()
);
if (headless) args += L" --headless";
args += headless ? L" --window-size=1920,1080 --headless" : L" --window-size=850,900";
DWORD exitCode = 0;
STARTUPINFOW DUMMY = { sizeof(DUMMY) };
PROCESS_INFORMATION processInfo = {};
@ -93,7 +93,7 @@ namespace DevTools
if (chromePath.isEmpty())
{
for (auto [_, process] : GetAllProcesses())
if (process && process->find(L"\\chrome.exe") != std::string::npos) chromePath = S(process.value());
if (process && (process->find(L"\\chrome.exe") != std::string::npos || process->find(L"\\msedge.exe") != std::string::npos)) chromePath = S(process.value());
wchar_t programFiles[MAX_PATH + 100] = {};
for (auto folder : { CSIDL_PROGRAM_FILESX86, CSIDL_PROGRAM_FILES, CSIDL_LOCAL_APPDATA })
{

View File

@ -2,6 +2,7 @@
#include "module.h"
#include "blockmarkup.h"
#include <fstream>
#include <process.h>
extern const wchar_t* REGEX_REPLACER_INSTRUCTIONS;

View File

@ -4,7 +4,7 @@
extern const char* LOAD_SCRIPT;
constexpr auto STYLE_SAVE_FILE = u8"Textractor.css";
constexpr auto STYLE_SAVE_FILE = u8"Textractor.qss";
class Window : public QDialog, Localizer
{
@ -13,7 +13,8 @@ public:
{
connect(&loadButton, &QPushButton::clicked, this, &Window::LoadScript);
if (scriptEditor.toPlainText().isEmpty()) scriptEditor.setPlainText("/*https://doc.qt.io/qt-5/stylesheet-syntax.html*/");
if (scriptEditor.toPlainText().isEmpty())
scriptEditor.setPlainText("/*\nhttps://www.google.com/search?q=Qt+stylesheet+gallery\nhttps://doc.qt.io/qt-5/stylesheet-syntax.html\n*/");
layout.addWidget(&scriptEditor);
layout.addWidget(&loadButton);

View File

@ -18,6 +18,8 @@ extern const char* MAX_TRANSLATIONS_IN_TIMESPAN;
extern const char* TIMESPAN;
extern const char* MAX_SENTENCE_SIZE;
extern const char* API_KEY;
extern const wchar_t* SENTENCE_TOO_LARGE_TO_TRANS;
extern const wchar_t* TRANSLATION_ERROR;
extern const wchar_t* TOO_MANY_TRANS_REQUESTS;
extern const char* TRANSLATION_PROVIDER;
@ -34,7 +36,6 @@ namespace
{
Synchronized<TranslationParam> tlp;
Synchronized<std::unordered_map<std::wstring, std::wstring>> translationCache;
int savedSize = 0;
std::string CacheFile()
{
@ -46,7 +47,6 @@ namespace
for (const auto& [sentence, translation] : translationCache.Acquire().contents)
allTranslations.append(L"|SENTENCE|").append(sentence).append(L"|TRANSLATION|").append(translation).append(L"|END|\r\n");
std::ofstream(CacheFile(), std::ios::binary | std::ios::trunc).write((const char*)allTranslations.c_str(), allTranslations.size() * sizeof(wchar_t));
savedSize = translationCache->size();
}
void LoadCache()
{
@ -59,7 +59,6 @@ namespace
auto& [sentence, translation] = read.value();
translationCache->try_emplace(std::move(sentence), std::move(translation));
}
savedSize = translationCache->size();
}
}
@ -141,7 +140,7 @@ public:
private:
void SaveTranslateTo(QString language)
{
if (translationCache->size() > savedSize) SaveCache();
SaveCache();
settings.setValue(TRANSLATE_TO, S(tlp->translateTo = S(language)));
LoadCache();
}
@ -153,7 +152,7 @@ private:
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
{
if (sentenceInfo["text number"] == 0 || sentence.size() > maxSentenceSize) return false;
if (sentenceInfo["text number"] == 0) return false;
static class
{
@ -175,12 +174,6 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
concurrency::concurrent_priority_queue<DWORD64, std::greater<DWORD64>> tokens;
} rateLimiter;
auto Trim = [](std::wstring& text)
{
text.erase(text.begin(), std::find_if_not(text.begin(), text.end(), iswspace));
text.erase(std::find_if_not(text.rbegin(), text.rend(), iswspace).base(), text.end());
};
bool cache = false;
std::wstring translation;
if (useFilter)
@ -189,6 +182,7 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
sentence.erase(std::remove_if(sentence.begin(), sentence.end(), [](wchar_t ch) { return ch < ' ' && ch != '\n'; }), sentence.end());
}
if (sentence.empty()) return true;
if (sentence.size() > maxSentenceSize) translation = SENTENCE_TOO_LARGE_TO_TRANS;
if (useCache)
{
auto translationCache = ::translationCache.Acquire();
@ -197,12 +191,12 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
if (translation.empty() && (!translateSelectedOnly || sentenceInfo["current select"]))
if (rateLimiter.Request() || !useRateLimiter || (!rateLimitSelected && sentenceInfo["current select"])) std::tie(cache, translation) = Translate(sentence, tlp.Copy());
else translation = TOO_MANY_TRANS_REQUESTS;
if (useFilter) Trim(translation);
if (cache) translationCache->try_emplace(sentence, translation);
if (cache && translationCache->size() > savedSize + 50) SaveCache();
if (cache) translationCache->operator[](sentence) = translation;
if (useFilter) Trim(translation);
for (int i = 0; i < translation.size(); ++i) if (translation[i] == '\r' && translation[i + 1] == '\n') translation[i] = 0x200b; // for some reason \r appears as newline - no need to double
if (!translation.empty()) (sentence += L"\x200b \n") += translation;
if (translation.empty()) translation = TRANSLATION_ERROR;
(sentence += L"\x200b \n") += translation;
return true;
}

View File

@ -276,7 +276,9 @@ namespace HookCode
{
std::optional<HookParam> Parse(std::wstring code)
{
if (code[0] == L'/') code.erase(0, 1); // legacy/AGTH compatibility
if (code[0] == L'/') code.erase(0, 1);
code.erase(std::find(code.begin(), code.end(), L'/'), code.end()); // legacy/AGTH compatibility
Trim(code);
if (code[0] == L'R') return ParseRCode(code.erase(0, 1));
else if (code[0] == L'H') return ParseHCode(code.erase(0, 1));
return {};
@ -292,6 +294,7 @@ namespace HookCode
assert(HexString(-12) == L"-C"),
assert(HexString(12) == L"C"),
assert(Parse(L"/HQN936#-c*C:C*1C@4AA:gdi.dll:GetTextOutA")),
assert(Parse(L"/HQN936#-c*C:C*1C@4AA:gdi.dll:GetTextOutA /KF")),
assert(Parse(L"HB4@0")),
assert(Parse(L"/RS65001#@44")),
assert(Parse(L"HQ@4")),

View File

@ -88,7 +88,7 @@ void SpawnThread(const F& f) // works in DllMain unlike std thread
}, copy, 0, nullptr));
}
static struct // should be inline but MSVC (linker) is bugged
inline struct
{
inline static BYTE DUMMY[100];
template <typename T> operator T*() { static_assert(sizeof(T) < sizeof(DUMMY)); return (T*)DUMMY; }
@ -120,6 +120,12 @@ inline std::wstring FormatString(const wchar_t* format, const Args&... args)
}
#pragma warning(pop)
inline void Trim(std::wstring& text)
{
text.erase(text.begin(), std::find_if_not(text.begin(), text.end(), iswspace));
text.erase(std::find_if_not(text.rbegin(), text.rend(), iswspace).base(), text.end());
}
inline std::optional<std::wstring> StringToWideString(const std::string& text, UINT encoding)
{
std::vector<wchar_t> buffer(text.size() + 1);

118
text.cpp
View File

@ -143,6 +143,7 @@ const char* RATE_LIMIT_SELECTED_THREAD = u8"Rate limit selected text thread";
const char* USE_TRANS_CACHE = u8"Use translation cache";
const char* MAX_TRANSLATIONS_IN_TIMESPAN = u8"Max translation requests in timespan";
const char* TIMESPAN = u8"Timespan (ms)";
const wchar_t* SENTENCE_TOO_LARGE_TO_TRANS = L"Sentence too large to translate";
const wchar_t* TOO_MANY_TRANS_REQUESTS = L"Rate limit exceeded: refuse to make more translation requests";
const wchar_t* TRANSLATION_ERROR = L"Error while translating";
const char* USE_PREV_SENTENCE_CONTEXT = u8"Use previous sentence as context";
@ -353,28 +354,30 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
SETTINGS = u8"设置";
EXTENSIONS = u8"扩展";
SELECT_PROCESS = u8"选择进程";
ATTACH_INFO = u8R"(如果没看见想要附加的进程,尝试使用管理员权限运行
ATTACH_INFO = u8R"(如果没看见想要附加的进程,尝试使用管理员权限运行Textractor
ID)";
SELECT_PROCESS_INFO = u8"如果手动输入游戏名,请使用绝对路径";
FROM_COMPUTER = u8"计算机中选择";
PROCESSES = u8"进程 (*.exe)";
FROM_COMPUTER = u8"资源管理器中选择";
PROCESSES = u8"可执行文件 (*.exe)";
SAVE_SETTINGS = u8"保存设置";
EXTEN_WINDOW_INSTRUCTIONS = u8R"(从计算机拖拽扩展 (.dll) 文件到这里来添加
(使)
使 delete )";
EXTEN_WINDOW_INSTRUCTIONS = u8R"(在列表中单击右键以添加或移除扩展
,
)";
ADD_EXTENSION = u8"添加扩展";
REMOVE_EXTENSION = u8"移除扩展";
INVALID_EXTENSION = u8"%1 是一个无效扩展";
CONFIRM_EXTENSION_OVERWRITE = u8"此扩展的另一个版本已启用,是否删除并覆盖它?";
EXTENSION_WRITE_ERROR = u8"保存扩展失败";
USE_JP_LOCALE = u8"模拟日本区域设置?";
FAILED_TO_CREATE_CONFIG_FILE = u8"无法创建配置文件 \"%1\"";
HOOK_SEARCH_UNSTABLE_WARNING = u8"搜索钩子的功能是不稳定的! 可能会导致你的游戏崩溃! ";
HOOK_SEARCH_STARTING_VIEW_CONSOLE = u8"正在初始化钩子搜索 - 请查看控制台以获取更多提示";
SEARCH_CJK = u8"搜索中文/日文/韩文";
SEARCH_PATTERN = u8"搜索匹配特征 (hex byte array)";
SEARCH_DURATION = u8"搜索持续时间 (ms)";
SEARCH_MODULE = u8"搜索指定模块";
PATTERN_OFFSET = u8"相对于特征地址的偏移值";
MAX_HOOK_SEARCH_RECORDS = u8"搜索结果上限";
MAX_HOOK_SEARCH_RECORDS = u8"搜索结果达到上限";
MIN_ADDRESS = u8"起始地址 (hex)";
MAX_ADDRESS = u8"结束地址 (hex)";
STRING_OFFSET = u8"字符串偏移值 (hex)";
@ -388,7 +391,7 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
DOUBLE_CLICK_TO_REMOVE_HOOK = u8"双击移除不需要的钩子";
FILTER_REPETITION = u8"过滤重复文本";
AUTO_ATTACH = u8"自动附加";
ATTACH_SAVED_ONLY = u8"自动附加 (saved only)";
ATTACH_SAVED_ONLY = u8"自动附加 (仅限保存过配置的游戏)";
SHOW_SYSTEM_PROCESSES = u8"显示系统进程";
DEFAULT_CODEPAGE = u8"默认代码页";
FLUSH_DELAY = u8"刷新延迟";
@ -401,7 +404,7 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
: https://github.com/Artikash/Textractor
: https://github.com/Artikash/Textractor/blob/master/docs/TUTORIAL.md
Textractor
()
(Issues )
GPLv3 )";
UPDATE_AVAILABLE = L"有可用的更新: 请从 https://github.com/Artikash/Textractor/releases 下载";
ALREADY_INJECTED = L"Textractor: 已经注入";
@ -417,7 +420,8 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
HOOK_FAILED = u8"Textractor: 钩子注入失败";
TOO_MANY_HOOKS = u8"Textractor: 钩子数量已达上限: 无法注入";
HOOK_SEARCH_STARTING = u8"Textractor: 开始搜索钩子";
NOT_ENOUGH_TEXT = u8"Textractor: 没有足够的文本用来精确搜索";
HOOK_SEARCH_INITIALIZING = u8"Textractor: 初始化钩子搜索 (%f%%)";
NOT_ENOUGH_TEXT = u8"Textractor: 文本长度不足, 无法精确搜索";
HOOK_SEARCH_INITIALIZED = u8"Textractor: 搜索初始化完成, 创建了 %zd 个钩子";
MAKE_GAME_PROCESS_TEXT = u8"Textractor: 请点击游戏区域, 在接下来的 %d 秒内使游戏强制处理文本";
HOOK_SEARCH_FINISHED = u8"Textractor: 钩子搜索完毕, 找到了 %d 条结果";
@ -430,46 +434,65 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
HIJACK_ERROR = u8"Textractor: Hijack 错误";
COULD_NOT_FIND = u8"Textractor: 无法找到文本";
TRANSLATE_TO = u8"翻译为";
TRANSLATE_FROM = u8"原文语言";
FILTER_GARBAGE = u8"过滤无意义字符";
TRANSLATE_SELECTED_THREAD_ONLY = u8"仅翻译当前选择的文本线程";
RATE_LIMIT_ALL_THREADS = u8"限制所有文本线程的请求频率";
RATE_LIMIT_SELECTED_THREAD = u8"限制当前选择线程的请求频率";
RATE_LIMIT_ALL_THREADS = u8"限制请求频率";
RATE_LIMIT_SELECTED_THREAD = u8"限制选中线程的请求频率";
USE_TRANS_CACHE = u8"使用缓存的翻译结果";
MAX_TRANSLATIONS_IN_TIMESPAN = u8"限流器令牌";
TIMESPAN = u8"限流器令牌重置时间 (ms)";
TOO_MANY_TRANS_REQUESTS = L"太多翻译请求: 拒绝生成更多";
MAX_TRANSLATIONS_IN_TIMESPAN = u8"单位时间内最大请求次";
TIMESPAN = u8"单位时间长度 (ms)";
TOO_MANY_TRANS_REQUESTS = L"超出频率限制: 拒绝发出翻译请求";
TRANSLATION_ERROR = L"翻译时出错";
USE_PREV_SENTENCE_CONTEXT = u8"使用之前的句子作为上下文";
API_KEY = u8"API key";
EXTRA_WINDOW_INFO = u8R"(右键修改设置
)";
CHROME_LOCATION = u8"Google Chrome 安装位置";
START_DEVTOOLS = u8"启动 DevTools";
STOP_DEVTOOLS = u8"停止 DevTools";
HIDE_CHROME = u8"隐藏 Chrome 窗口";
DEVTOOLS_STATUS = u8"DevTools 状态";
AUTO_START = u8"自动启动";
ERROR_START_CHROME = L"无法启动或连接到 Chrome";
EXTRA_WINDOW_INFO = u8R"(在此点击右键以修改设置
, )";
MAX_SENTENCE_SIZE = u8"最大文本长度";
TOPMOST = u8"窗口总是置顶";
DICTIONARY = u8"字典";
SHOW_ORIGINAL = u8"显示原文";
SHOW_ORIGINAL_INFO = u8R"(将不显示原文
使)";
OPACITY = u8"透明度";
SHOW_ORIGINAL_INFO = u8R"(原文将被隐藏
使)";
ORIGINAL_AFTER_TRANSLATION = u8"把原文显示在翻译文本的后面";
SIZE_LOCK = u8"锁定窗口大小";
POSITION_LOCK = u8"锁定窗口位置";
CENTERED_TEXT = u8"居中显示文本";
AUTO_RESIZE_WINDOW_HEIGHT = u8"自动改变窗口高度";
CLICK_THROUGH = u8"点击穿透\tAlt+X";
HIDE_MOUSEOVER = u8"鼠标经过时隐藏窗口";
OPACITY = u8"透明度";
BG_COLOR = u8"背景颜色";
TEXT_COLOR = u8"文本颜色";
TEXT_OUTLINE = u8"文字边框";
OUTLINE_COLOR = u8"边框颜色";
OUTLINE_SIZE = u8"边框大小";
OUTLINE_SIZE_INFO = u8"以像素为单位的大小(建议保持在字体大小的20%以下)";
TEXT_OUTLINE = u8"文字";
OUTLINE_COLOR = u8"文字描边颜色";
OUTLINE_SIZE = u8"文字描边大小";
OUTLINE_SIZE_INFO = u8"描边的单位为px (建议保持在字体大小的20%以下)";
FONT = u8"字体";
LUA_INTRO = u8R"(--[[
ProcessSentence Textractor每接收到一句文本时都会调用的函数
sentence: Textractor接收到的文本 (UTF-8)
sentenceInfo: table
nil
使Lua解释器的副本用于保证线程安全
ProcessSentence函数中对全局变量的修改可能不会生效
sentenceInfo有以下成员:
"current select": 线0
"process id": id. 0 线
"text number": 线id. 线 0 , 1
ProcessSentence Textractor每接收到一句文本时都会调用的函数.
sentence: Textractor接收到的文本 (UTF-8), string.
sentenceInfo: , tabel.
.
nil, .
使Lua解释器的副本用于保证线程安全.
ProcessSentence .
sentenceInfo :
current select: 线, 0. number.
process id: ID. 0 线. number.
text number: 线ID. 线. 0 , 1 . number.
--]]
function ProcessSentence(sentence, sentenceInfo)
--...
end)";
@ -481,13 +504,28 @@ end)";
REPLACER_INSTRUCTIONS = LR"(使用"Replace"扩展时会使用此文件
:
|ORIG||BECOMES||END|
.
.
^ .
.
使Unicode字符集(UTF-16 little endian).)";
使 Unicode (UTF-16 little endian).)";
REGEX_REPLACER_INSTRUCTIONS = LR"(使用"Regex Replace"扩展时会使用此文件
:
|REGEX||BECOMES||MODIFIER||END|
$[] (: $1 1).
:
g .
i .
, 1, .
.
使 Unicode (UTF-16 little endian).
线:
https://www.runoob.com/regexp/regexp-intro.html
https://regexr.com/)";
THREAD_LINKER = u8"线程链接器";
LINK = u8"链接";
THREAD_LINK_FROM = u8"需要链接的线程id";
THREAD_LINK_TO = u8"链接到的线程id";
UNLINK = u8"断开";
THREAD_LINK_FROM = u8"需要链接的线程ID";
THREAD_LINK_TO = u8"链接到的线程ID";
HEXADECIMAL = u8"十六进制";
#endif // SIMPLIFIED_CHINESE

View File

@ -27,6 +27,7 @@
//#include <boost/foreach.hpp>
#include <cstdio>
#include <string>
#include <sstream>
// jichi 375/2014: Add offset of pusha/pushad
// http://faydoc.tripod.com/cpu/pushad.htm
@ -5730,21 +5731,21 @@ void SpecialHookShina2(DWORD esp_base, HookParam *, BYTE, DWORD *data, DWORD *sp
// Used to merge correct text thread.
// 1. Only keep threads with 0 and -1 split
// 2. Skip the thread withb 0 split and with minimum return address
void SpecialHookShina1(DWORD esp_base, HookParam *hp, BYTE, DWORD *data, DWORD *split, DWORD *len)
{
static DWORD min_retaddr = -1;
DWORD s = *(DWORD *)(esp_base + hp->split);
if (s == 0 || (s & 0xffff) == 0xffff) { // only keep threads with 0 and -1 split
if (s == 0 && retof(esp_base) <= min_retaddr) {
min_retaddr = retof(esp_base);
return;
}
*split = FIXED_SPLIT_VALUE;
// Follow the same logic as the hook.
*data = *(DWORD *)*data; // DATA_INDIRECT
*len = LeadByteTable[*data & 0xff];
}
}
//void SpecialHookShina1(DWORD esp_base, HookParam *hp, BYTE, DWORD *data, DWORD *split, DWORD *len)
//{
// static DWORD min_retaddr = -1;
// DWORD s = *(DWORD *)(esp_base + hp->split);
// if (s == 0 || (s & 0xffff) == 0xffff) { // only keep threads with 0 and -1 split
// if (s == 0 && retof(esp_base) <= min_retaddr) {
// min_retaddr = retof(esp_base);
// return;
// }
// *split = FIXED_SPLIT_VALUE;
// // Follow the same logic as the hook.
// *data = *(DWORD *)*data; // DATA_INDIRECT
// *len = LeadByteTable[*data & 0xff];
// }
//}
// jichi 8/27/2013
// Return ShinaRio version number
@ -5803,7 +5804,7 @@ bool InsertShinaHook()
trigger_fun = [](LPVOID funcAddr, DWORD, DWORD stack)
{
bool ret = false;
if (funcAddr != GetGlyphOutlineA) return false;
if (funcAddr != GetGlyphOutlineA && funcAddr != GetTextExtentPoint32A) return false;
for (int i = 0; i < 100; ++i)
{
// Address of text is somewhere on stack in call to func. Search for it.
@ -5817,7 +5818,7 @@ bool InsertShinaHook()
hp.type = DIRECT_READ;
hp.address = addr;
ConsoleOutput("Textractor: triggered: adding dynamic reader");
NewHook(hp, "READ");
NewHook(hp, "ShinaRio READ");
ret = true;
}
};
@ -5825,9 +5826,8 @@ bool InsertShinaHook()
return ret;
};
ConsoleOutput("Textractor: ShinaRio 2.50+: adding trigger");
return true;
}
else if (ver >= 48) { // v2.48, v2.49
if (ver >= 48) { // v2.48, v2.49
HookParam hp = {};
hp.address = (DWORD)::GetTextExtentPoint32A;
hp.text_fun = SpecialHookShina2;
@ -6007,9 +6007,9 @@ bool InsertWaffleHook()
0x50, //50 push eax
0x8b, 0xce, //8BCE mov ecx,esi
0xc6, 0x45, 0xfc, XX, //C645 FC 01 move byte ptr ss:[ebp-4],?
0x89, 0x75, 0xd4, //8975 D4 move dword ptr ss:[ebp-0x2c],esi
0x89, 0x75, XX, //8975 D4 move dword ptr ss:[ebp-0x2c],esi
0xe8, XX4, //E8 ?? call ??
0x8d, 0x45, 0xdc //8D45 DC lea eax,dword ptr ss:[ebp-0x24]
0x8d, 0x45, XX //8D45 DC lea eax,dword ptr ss:[ebp-0x24]
};
if (DWORD addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress))
{
@ -6352,9 +6352,267 @@ static bool InsertYuris2Hook()
NewHook(hp, "YU-RIS2");
return true;
}
static bool Yuris3Filter(LPVOID data, DWORD* size, HookParam*, BYTE)
{
static wchar_t prev_text;
wchar_t* pText = reinterpret_cast<wchar_t*>(data);
if (prev_text == *pText)
{
prev_text = '\0';
return false;
}
prev_text = *pText;
return true;
}
static bool InsertYuris3Hook()
{
//by Blu3train
HookParam hp = {};
wcsncpy_s(hp.module, L"kernel32.dll", MAX_MODULE_SIZE - 1);
strncpy_s(hp.function, "MultiByteToWideChar", MAX_MODULE_SIZE - 1);
hp.address = 6;
hp.offset = 0xC; //arg3
hp.index = 0;
hp.split = 0x1C;
hp.split_index = 0;
hp.filter_fun = Yuris3Filter;
hp.type = USING_STRING | USING_SPLIT | MODULE_OFFSET | FUNCTION_OFFSET;
hp.length_offset = 0x10 / (short)sizeof(void*); // arg4/arg_sz
ConsoleOutput("vnreng: INSERT YU-RIS 3");
NewHook(hp, "YU-RIS3");
return true;
}
bool InsertYuris4Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v6540
*/
bool found = false;
const BYTE pattern[] = {
0x52, // 52 push edx
0x68, 0x00, 0x42, 0x5C, 0x00, // 68 00425C00 push euphoria.exe+1C4200
0xFF, 0x15, 0x90, 0x44, 0x7E, 0x00, // FF 15 90447E00 call dword ptr [euphoria.exe+3E4490]
0x83, 0xC4, 0x0C, // 83 C4 0C add esp,0C
0xEB, 0x5F, // EB 5F jmp euphoria.exe+4F4C5
0xFF, 0x35, 0xA4, 0x19, 0x66, 0x00, // FF 35 A4196600 push [euphoria.exe+2619A4]
0x52 // 52 push edx
};
enum { addr_offset = 12 }; // distance to the beginning of the function, which is 0x83, 0xC4, 0x0C (add esp,0C)
for (auto addr : Util::SearchMemory(pattern, sizeof(pattern), PAGE_EXECUTE, processStartAddress, processStopAddress))
{
HookParam hp = {};
hp.address = addr + addr_offset;
hp.offset = pusha_edx_off - 4;
hp.type = USING_STRING;
ConsoleOutput("Textractor: INSERT YU-RIS 4");
NewHook(hp, "YU-RIS4");
found = true;
}
if (!found) ConsoleOutput("Textractor:YU-RIS 4: pattern not found");
return found;
}
bool InsertYuris5Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v4037
*/
const BYTE bytes[] = {
0x33, 0xD2, // xor edx,edx
0x88, 0x14, 0x0F, // mov [edi+ecx],dl
0xA1, XX4, // mov eax,[exe+2DE630]
0x8B, 0x78, 0x3C, // mov edi,[eax+3C]
0x8B, 0x58, 0x5C, // mov ebx,[eax+5C]
0x88, 0x14, 0x3B // mov [ebx+edi],dl
};
enum { addr_offset = 0 }; // distance to the beginning of the function, which is 0x55 (push ebp)
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr + addr_offset;
hp.offset = pusha_ecx_off - 4;
hp.type = USING_STRING | NO_CONTEXT;
ConsoleOutput("Textractor: INSERT YU-RIS 5");
NewHook(hp, "YU-RIS5");
return true;
}
static bool Yuris6Filter(LPVOID data, DWORD* size, HookParam*, BYTE)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
static std::string prevText;
if (prevText.length() == *len && prevText.find(text, 0, *len) != std::string::npos) // Check if the string is present in the previous one
return false;
prevText.assign(text, *len);
// ruby <手水舎/ちょうずや>
if (cpp_strnstr(text, "\x81\x83", *len)) { // \x81\x83 -> ''
StringFilterBetween(text, len, "\x81\x5E", 2, "\x81\x84", 2); // \x81\x5E -> '' , \x81\x84 -> ''
StringFilter(text, len, "\x81\x83", 2); // \x81\x83 -> ''
}
// ruby ≪美桜/姉さん≫
else if (cpp_strnstr(text, "\x81\xE1", *len)) { // \x81\xE1 -> '≪'
StringFilterBetween(text, len, "\x81\x5E", 2, "\x81\xE2", 2); // \x81\x5E -> '' , \x81\xE2 -> '≫'
StringFilter(text, len, "\x81\xE1", 2); // \x81\xE1 -> '≪'
}
CharReplacer(text, len, '=', '-');
StringCharReplacer(text, len, "\xEF\xF0", 2, ' ');
StringFilter(text, len, "\xEF\xF2", 2);
StringFilter(text, len, "\xEF\xF5", 2);
StringFilter(text, len, "\x81\x98", 2);
return true;
}
bool InsertYuris6Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v40058
* https://vndb.org/v42883
* https://vndb.org/v44092
* https://vndb.org/v21171
* https://vndb.org/r46910
*/
const BYTE bytes[] = {
0xE9, XX4, // jmp oshitona01.exe+1B629
0xBF, XX4, // mov edi,oshitona01.exe+24EEA0
0x8A, 0x17, // mov dl,[edi]
0x47, // inc edi
0x88, 0x16, // mov [esi],dl
0x46, // inc esi
0x84, 0xD2 // test dl,dl
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr;
hp.offset = pusha_eax_off - 4;
hp.index = 0x38;
hp.codepage = 65001;
hp.filter_fun = Yuris6Filter;
hp.type = USING_STRING | NO_CONTEXT | DATA_INDIRECT;
ConsoleOutput("Textractor: INSERT YU-RIS 6");
NewHook(hp, "YU-RIS6");
return true;
}
bool InsertYuris7Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v45381
* https://vndb.org/v47458
* https://vndb.org/v21144
* https://vndb.org/v18681
*/
const BYTE bytes[] = {
0x03, 0xC1, // add eax,ecx
0x99, // cdq
0xE9, XX4 // jmp nekonin_spin.exe+55753 << hook here
};
enum { addr_offset = sizeof(bytes) - 5 };
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr + addr_offset;
hp.offset = pusha_eax_off - 4;
hp.index = 0;
hp.length_offset = 1; // only 1 character
hp.text_fun = [](DWORD esp_base, HookParam*, BYTE, DWORD*, DWORD*, DWORD* len)
{
*len = (retof(esp_base) == 0) ? 2 : 0;
};
hp.type = BIG_ENDIAN;
ConsoleOutput("vnreng: INSERT YU-RIS7");
NewHook(hp, "YU-RIS7");
return true;
}
bool InsertYuris8Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v47458
* https://vndb.org/v45381
*/
const BYTE bytes[] = {
0x57, // push edi << hook here
0x56, // push esi
0x55, // push ebp
0x53, // push ebx
0x83, 0xEC, 0x10, // sub esp,10
0x8B, 0x5C, 0x24, 0x24, // mov ebx,[esp+24]
0x8B, 0x15, XX4, // mov edx,[hajiron.exe+47243C]
0x8B, 0x0C, 0x9A, // mov ecx,[edx+ebx*4]
0xC6, 0x41, 0x01, 0x03, // mov byte ptr [ecx+01],03
0x8B, 0xC3, // mov eax,ebx
0xE8,XX4 // call hajiron.exe+54EA4
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr;
hp.offset = pusha_edx_off - 4;
hp.index = 0;
hp.text_fun = [](DWORD esp_base, HookParam*, BYTE, DWORD*, DWORD*, DWORD* len)
{
DWORD textLen = regof(eax, esp_base);
if (textLen > 2)
return;
*len = (regof(edi, esp_base) >= 0xFA && regof(edi, esp_base) <= 0xFE || regof(edi, esp_base) >= 0x1A0 && regof(edi, esp_base) <= 0x1C2) ? textLen : 0;
};
hp.type = USING_STRING;
ConsoleOutput("vnreng: INSERT YU-RIS8");
NewHook(hp, "YU-RIS8");
return true;
}
bool InsertYurisHook()
{ return InsertYuris1Hook() || InsertYuris2Hook(); }
{
bool ok = InsertYuris1Hook();
ok = InsertYuris2Hook() || ok;
ok = InsertYuris3Hook() || ok;
ok = InsertYuris4Hook() || ok;
ok = InsertYuris5Hook() || ok;
ok = InsertYuris6Hook() || ok;
ok = InsertYuris7Hook() || ok;
ok = InsertYuris8Hook() || ok;
return ok;
}
bool InsertCotophaHook1()
{
@ -17002,7 +17260,7 @@ void InsertMonoHook(HMODULE h)
if (!getDomain || !getName || !getJitInfo) goto failed;
static auto domain = getDomain();
if (!domain) goto failed;
ConsoleOutput("Textractor: Mono Dynamic ENTER (hooks = %s)", loadedConfig ? loadedConfig : "brute force");
ConsoleOutput("Textractor: Mono Dynamic ENTER (hooks = %s)", *loadedConfig ? loadedConfig : "brute force");
const BYTE prolog[] = { 0x55, 0x8b, 0xec };
for (auto addr : Util::SearchMemory(prolog, sizeof(prolog), PAGE_EXECUTE_READWRITE))
{
@ -17017,7 +17275,7 @@ void InsertMonoHook(HMODULE h)
HookParam hp = {};
hp.address = addr;
hp.type = USING_UNICODE | FULL_STRING;
if (!loadedConfig) hp.type |= KNOWN_UNSTABLE;
if (!*loadedConfig) hp.type |= KNOWN_UNSTABLE;
hp.offset = 4;
char nameForUser[HOOK_NAME_SIZE] = {};
strncpy_s(nameForUser, name + 1, HOOK_NAME_SIZE - 1);
@ -17035,7 +17293,7 @@ void InsertMonoHook(HMODULE h)
__except (EXCEPTION_EXECUTE_HANDLER) {}
}(addr);
}
if (!loadedConfig) ConsoleOutput("Textractor: Mono Dynamic used brute force: if performance issues arise, please specify the correct hook in the game configuration");
if (!*loadedConfig) ConsoleOutput("Textractor: Mono Dynamic used brute force: if performance issues arise, please specify the correct hook in the game configuration");
return true;
failed:
ConsoleOutput("Textractor: Mono Dynamic failed");
@ -17092,7 +17350,7 @@ bool InsertMonoHooks()
if (FARPROC addr = ::GetProcAddress(h, func.functionName)) {
hp.address = (DWORD)addr;
hp.type = func.hookType;
if (loadedConfig) hp.type |= HOOK_EMPTY;
if (*loadedConfig) hp.type |= HOOK_EMPTY;
hp.filter_fun = NoAsciiFilter;
hp.offset = func.textIndex * 4;
hp.length_offset = func.lengthIndex * 4;
@ -21027,6 +21285,84 @@ bool InsertTecmoPSPHook()
}
#endif // 0
//for debug
void StringBlockProcessor(char* str, size_t* size, size_t fixlength)
{
size_t original_len = *size;
size_t new_len = 0;
char* new_str = new char[original_len + 1];
size_t i = 0;
while (i < original_len) {
size_t block_end = i + fixlength;
if (block_end > original_len) {
block_end = original_len;
}
size_t block_len = block_end - i;
char* block = str + i;
for (size_t j = 0; j < block_len; ++j) {
if (block[j] != 0) {
new_str[new_len++] = block[j];
}
else {
break;
}
}
i = block_end;
}
new_str[new_len] = '\0';
std::memcpy(str, new_str, new_len + 1);
*size = new_len;
delete[] new_str;
}
bool DACFilter(LPVOID data, DWORD* size, HookParam*, BYTE)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
StringBlockProcessor(text, len, 0x3f);
return true;
}
bool InsertDACHook()
{
const BYTE bytecodes[] = {
0x0F, 0xBF, 0x56, 0x34, // movsx edx, word ptr ds:[esi+34]
0x83, 0xC2, 0x05, // add edx, 5
0x8B, 0x8E, 0x00, 0x01, 0x00, 0x00, // mov ecx, dword ptr ds:[esi+100]
0x0F, 0xAF, 0xD3 // imul edx, ebx <--
};
ULONG addr = MemDbg::findBytes(bytecodes, sizeof(bytecodes), processStartAddress, processStopAddress);
if (addr == 0) {
ConsoleOutput("vnreng:DAC: pattern not found");
return false;
}
enum { addr_offset = 13 };
HookParam hp = {};
hp.type = USING_STRING; //S
hp.address = addr + addr_offset;
hp.offset = pusha_ecx_off - 4; //-C
hp.index = 0x00;
hp.filter_fun = DACFilter;
hp.length_fun = [](uintptr_t, uintptr_t data)
{
int len = 0x3f;
return len * 4;
};
NewHook(hp, "DAC");
ConsoleOutput("vnreng: INSERT DAC");
return true;
}
/** jichi 7/19/2014 PCSX2
* Tested wit pcsx2-v1.2.1-328-gef0e3fe-windows-x86, built at http://buildbot.orphis.net/pcsx2
*/
@ -21262,7 +21598,6 @@ bool InsertTypeMoonPS2Hook()
ConsoleOutput("vnreng: TypeMoon PS2: leave");
return addr;
}
/** 8/3/2014 jichi
* Tested game: School Rumble <EFBFBD>
*

View File

@ -14,7 +14,7 @@ namespace Engine {
// Global variables
extern wchar_t *processName, // cached
processPath[MAX_PATH]; // cached
inline const char *requestedEngine = nullptr, *loadedConfig = nullptr;
inline const char *requestedEngine = "", * loadedConfig = "";
bool InsertMonoHooks(); // Mono
@ -96,6 +96,7 @@ bool InsertCandyHook(); // SystemC@CandySoft: *.fpk
bool InsertCatSystemHook(); // CatSystem2: *.int
bool InsertCMVSHook(); // CMVS: data/pack/*.cpz; do not support the latest cmvs32.exe and cmvs64.exe
bool InsertCotophaHook(); // Cotopha: *.noa
bool InsertDACHook(); // DAC
bool InsertDebonosuHook(); // Debonosu: bmp.bak and dsetup.dll
bool InsertEaglsHook(); // E.A.G.L.S: EAGLES.dll
bool InsertEMEHook(); // EmonEngine: emecfg.ecf

View File

@ -45,13 +45,13 @@ namespace Engine
if (AutoHandle<> configFile = CreateFileW(configFilename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))
{
ReadFile(configFile, configFileData, sizeof(configFileData) - 1, DUMMY, nullptr);
if (strncmp(configFileData, "Engine:", 7) == 0)
if (strnicmp(configFileData, "engine:", 7) == 0)
{
if (loadedConfig = strchr(configFileData, '\n')) *(char*)loadedConfig++ = 0;
ConsoleOutput("Textractor: Engine = %s", requestedEngine = configFileData + 7);
if (const char* config = strchr(configFileData, '\n')) *(char*)(loadedConfig = config)++ = 0;
ConsoleOutput("Textractor: Engine = %s", requestedEngine = strlwr(configFileData + 7));
}
else loadedConfig = configFileData;
if ((loadedConfig && !*loadedConfig) || strstr(configFileData, "https://")) loadedConfig = nullptr;
if (!*loadedConfig || strstr(configFileData, "https://")) loadedConfig = "";
else ConsoleOutput("Textractor: game configuration loaded");
}
@ -67,14 +67,14 @@ namespace Engine
spDefault.maxAddress = processStopAddress;
ConsoleOutput("Textractor: hijacking process located from 0x%p to 0x%p", processStartAddress, processStopAddress);
DetermineEngineType();
if (!strstr(requestedEngine, "none")) DetermineEngineType();
if (processStartAddress + 0x40000 > processStopAddress) ConsoleOutput("Textractor: WARNING injected process is very small, possibly a dummy!");
}(), 0);
}
bool ShouldMonoHook(const char* name)
{
if (!loadedConfig) return strstr(name, "string:") && !strstr(name, "string:mem");
if (!*loadedConfig) return strstr(name, "string:") && !strstr(name, "string:mem");
for (const char* hook = loadedConfig; hook; hook = strchr(hook + 1, '\t'))
for (auto start = name; *start; ++start)
for (int i = 0; ; ++i)

View File

@ -54,6 +54,11 @@ bool DeterminePCEngine()
return true;
}
if (Util::CheckFile(L"script.dpk")) {
InsertDACHook();
return true;
}
// jichi 5/14/2015: Skip hijacking BALDRSKY ZEROs
//if (Util::CheckFile(L"bsz_Data\\Mono\\mono.dll") || Util::CheckFile(L"bsz2_Data\\Mono\\mono.dll")) {
// ConsoleOutput("vnreng: IGNORE BALDRSKY ZEROs");
@ -629,10 +634,9 @@ bool DetermineEngineAtLast()
}
if (Util::CheckFile(L"MovieTexture.dll") && (InsertPensilHook() || Insert2RMHook())) // MovieTexture.dll also exists in 2RM games such as 母子愛2体験版, which is checked first
return true;
if ((Util::CheckFile(L"system") && Util::CheckFile(L"system.dat")) || Util::CheckFile(L"*01")) { // jichi 7/31/2015 & Artikash 6/15/2018
InsertAbelHook();
return true;
}
if ((Util::CheckFile(L"system") && Util::CheckFile(L"system.dat")) || Util::CheckFile(L"*01")) // jichi 7/31/2015 & Artikash 6/15/2018
if (InsertAbelHook())
return true;
if (Util::CheckFile(L"data\\*.cpk")) { // jichi 12/2/2014
Insert5pbHook();
return true;

View File

@ -80,7 +80,7 @@ namespace Engine
if (!getDomain || !getName || !getJitInfo) goto failed;
static auto domain = getDomain();
if (!domain) goto failed;
ConsoleOutput("Textractor: Mono Dynamic ENTER (hooks = %s)", loadedConfig ? loadedConfig : "brute force");
ConsoleOutput("Textractor: Mono Dynamic ENTER (hooks = %s)", *loadedConfig ? loadedConfig : "brute force");
const BYTE prolog1[] = { 0x55, 0x48, 0x8b, 0xec };
const BYTE prolog2[] = { 0x48, 0x83, 0xec };
for (auto [prolog, size] : Array<const BYTE*, size_t>{ { prolog1, sizeof(prolog1) }, { prolog2, sizeof(prolog2) } })
@ -97,7 +97,7 @@ namespace Engine
HookParam hp = {};
hp.address = addr;
hp.type = USING_STRING | USING_UNICODE | FULL_STRING;
if (!loadedConfig) hp.type |= KNOWN_UNSTABLE;
if (!*loadedConfig) hp.type |= KNOWN_UNSTABLE;
hp.offset = -0x20; // rcx
hp.padding = 20;
char nameForUser[HOOK_NAME_SIZE] = {};
@ -119,7 +119,7 @@ namespace Engine
}(addr);
}
if (!loadedConfig) ConsoleOutput("Textractor: Mono Dynamic used brute force: if performance issues arise, please specify the correct hook in the game configuration");
if (!*loadedConfig) ConsoleOutput("Textractor: Mono Dynamic used brute force: if performance issues arise, please specify the correct hook in the game configuration");
return true;
failed:
ConsoleOutput("Textractor: Mono Dynamic failed");

View File

@ -193,6 +193,7 @@ void TextHook::Send(uintptr_t dwDataBase)
TextOutput(tp, buffer, count);
#endif // _WIN64
++*pbData;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{