mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-13 15:44:35 +01:00
Compare commits
96 Commits
v1.1.1-alp
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9879817c9 | ||
|
|
2ed97f9787 | ||
|
|
1a82ab0012 | ||
|
|
017c116d81 | ||
|
|
422ce59f96 | ||
|
|
02a304d830 | ||
|
|
ae8c03debe | ||
|
|
dcc2b1707b | ||
|
|
8ba916d1ea | ||
|
|
4b6d1a11fb | ||
|
|
2b95034ddb | ||
|
|
989487b381 | ||
|
|
f6f5eae31c | ||
|
|
31c60755af | ||
|
|
22a2fff644 | ||
|
|
d11e432e76 | ||
|
|
572006ff95 | ||
|
|
27148eac8e | ||
|
|
7dce15f553 | ||
|
|
1204f967d7 | ||
|
|
51b938a5da | ||
|
|
0def90223f | ||
|
|
f6de90ca50 | ||
|
|
e1ba27203a | ||
|
|
6a161f4539 | ||
|
|
5b6f4e94db | ||
|
|
a32d7186df | ||
|
|
680c6b04a4 | ||
|
|
5db28756d2 | ||
|
|
6d53f344ac | ||
|
|
d144b2dc94 | ||
|
|
7264331436 | ||
|
|
016d377f30 | ||
|
|
0e2b4a4a54 | ||
|
|
a1571ad800 | ||
|
|
d849ea32c9 | ||
|
|
1c7293578c | ||
|
|
73a9e18712 | ||
|
|
96bf4ef3fe | ||
|
|
4c5b79513a | ||
|
|
b222601cf1 | ||
|
|
f8d2e62a06 | ||
|
|
33547cd34e | ||
|
|
a29fdf3d9c | ||
|
|
a86055cce9 | ||
|
|
014641307e | ||
|
|
51da474b2a | ||
|
|
97bbfea694 | ||
|
|
1d4cf94643 | ||
|
|
843913a664 | ||
|
|
3875599c5f | ||
|
|
bc1df1f5e1 | ||
|
|
4ea9df5db7 | ||
|
|
b81beb0971 | ||
|
|
62b54f33df | ||
|
|
2c07cf90bd | ||
|
|
b179ccc1f0 | ||
|
|
699eb2838e | ||
|
|
3ecc4f4231 | ||
|
|
ef576e36b8 | ||
|
|
75f3e829d5 | ||
|
|
dbbbb6603d | ||
|
|
74c6dd6792 | ||
|
|
ee9fe9e0a7 | ||
|
|
09f5e74b51 | ||
|
|
a31bc46c39 | ||
|
|
a9b1fa0130 | ||
|
|
7d92586210 | ||
|
|
9f73883d59 | ||
|
|
3fee55a30b | ||
|
|
98661d1b2c | ||
|
|
ab22379694 | ||
|
|
e4647a5811 | ||
|
|
d94dbcf384 | ||
|
|
b56ad4e465 | ||
|
|
b9b0929668 | ||
|
|
3ba467d03b | ||
|
|
882bad370f | ||
|
|
3eec0e4a11 | ||
|
|
9798f6d0d3 | ||
|
|
a76f90c1d8 | ||
|
|
f1ecb1aab0 | ||
|
|
7c9b2f7335 | ||
|
|
38436472e3 | ||
|
|
db6f23dbad | ||
|
|
d9dfb6ac4e | ||
|
|
981cb3180e | ||
|
|
d5187cb5d6 | ||
|
|
5a1e7d105c | ||
|
|
26d7ac2b11 | ||
|
|
6b07ccf1b5 | ||
|
|
f6856431bd | ||
|
|
f7e33d5035 | ||
|
|
190adb1d52 | ||
|
|
742a24df11 | ||
|
|
06e48e06b6 |
2
.github/workflows/backend-checks.yml
vendored
2
.github/workflows/backend-checks.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows-latest, ubuntu-latest, macos-latest]
|
||||
platform: [windows-latest, ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"rust-analyzer.linkedProjects": [".\\src-tauri\\Cargo.toml"]
|
||||
"rust-analyzer.linkedProjects": ["src-tauri/Cargo.toml"]
|
||||
}
|
||||
|
||||
10
README.md
10
README.md
@@ -1,4 +1,4 @@
|
||||
EN | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) |
|
||||
EN | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | [日本語](README_ja-JP.md)
|
||||
|
||||
# Cultivation
|
||||
|
||||
@@ -19,7 +19,7 @@ A game launcher designed to easily proxy traffic from anime game to private serv
|
||||
- [Screenshots](#screenshots)
|
||||
- [Credits](#credits)
|
||||
|
||||
# Client Patching Notice - RSA
|
||||
# Client Patching Notice
|
||||
|
||||
For game versions 3.1 and above, Cultivation automatically makes a small patch to your game client when launching using Grasscutter, and restores it upon closing the game. In theory, you should still be totally safe, however it would be dishonest to not explicitly state that **modifying the game client could, theoretically, lead to a ban if you connect to official servers with it**. It is extremely unlikely AND there are no instances known of it happening, but the possibility exists.
|
||||
|
||||
@@ -46,15 +46,15 @@ Download and open the MSI, and once installed, run Cultivation as administrator.
|
||||
- If you use multiple Java versions, you can set the Java path to your Java 17 installation (only required if you are running your own server)
|
||||
- Decide if you want to download your own server, or just join a public one
|
||||
- If joining a public one, you're done. Just click "Connect with Grasscutter" and input the address and port. You do not have to continue these instructions.
|
||||
- If you are getting System Error, or 4214, ask the [Discord support channels](https://discord.gg/grasscutter)
|
||||
- If you are getting System Error, or 4214, ask the [Discord support channels](https://discord.gg/T5vZU6UyeG)
|
||||
- Open the "Downloads" menu (top right)
|
||||
- Download "Grasscutter All-in-One" (top of the list)
|
||||
- Download "Grasscutter All-in-One" (select **one** of the AIOs that matches the version you want)
|
||||
- Once that is done, click the icon next to "Launch"
|
||||
- To play on your new server:
|
||||
- Click "Connect with Grasscutter"
|
||||
- Input `localhost` as the address, and `443` as the port
|
||||
- Ensure HTTPS is disabled
|
||||
- Any generic "I am getting XYZ error!" should go in the [Discord support channels](https://discord.gg/grasscutter)
|
||||
- Any generic "I am getting XYZ error!" should go in the [Discord support channels](https://discord.gg/T5vZU6UyeG)
|
||||
- Any specific Cultivation issues should go in [the issues section](/issues)
|
||||
- Any Grasscutter server related issues should go in [the Grasscutter issues section](https://github.com/Grasscutters/Grasscutter)
|
||||
|
||||
|
||||
124
README_ja-JP.md
Normal file
124
README_ja-JP.md
Normal file
@@ -0,0 +1,124 @@
|
||||
[EN](README.md) | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) | 日本語
|
||||
|
||||
# Cultivation
|
||||
|
||||
某アニメゲームからプライベートサーバーへのトラフィックを簡単にプロキシできるように設計されたゲームランチャー。
|
||||
|
||||
# 目次
|
||||
|
||||
- [クライアントのパッチに関するお知らせ](#クライアントのパッチに関するお知らせ)
|
||||
- [ダウンロード](#ダウンロード)
|
||||
- [セットアップ](#セットアップ)
|
||||
- [トラブルシューティング](#トラブルシューティング)
|
||||
- [開発者向けクイックスタート](#開発者向けクイックスタート)
|
||||
- [セットアップ](#セットアップ)
|
||||
- [ビルド](#ビルド)
|
||||
- [コードフォーマット・lint](#コードフォーマットlint)
|
||||
- [artifact を生成](#artifactを生成)
|
||||
- [テーマについて](#テーマについて)
|
||||
- [スクリーンショット](#スクリーンショット)
|
||||
- [クレジット](#クレジット)
|
||||
|
||||
# クライアントのパッチに関するお知らせ
|
||||
|
||||
ゲームバージョン 3.1 以降の場合、Cultivation は Grasscutter を使用して起動するときにゲームクライアントに自動的に小さなパッチ(RSA パッチ)を適用し、ゲームを閉じると自動的に解除します。理論上は安全ですが、<strong>ゲームクライアント自体に変更を加えるため、公式サーバーに接続すると BAN につながる可能性があります。</strong>これによる BAN についての既知の事例はありませんが、可能性は存在します。
|
||||
|
||||
# ダウンロード
|
||||
|
||||
[**リリースビルドはこちら**](https://github.com/Grasscutters/Cultivation/releases)
|
||||
|
||||
MSI インストーラーをダウンロードして開き、インストールしたら、管理者として Cultivation を実行します。[より詳細なセットアップ手順](#セットアップ)については、以下を参照してください。
|
||||
|
||||
**Windows 7 をお使いの場合:** [WebView2](https://developer.microsoft.com/ja-jp/microsoft-edge/webview2/#download-section)を手動でダウンロードしてインストールする必要があります。また、Cultivation のインストールには`.msi`の代わりに`.zip`を使用してください。
|
||||
|
||||
# セットアップ
|
||||
|
||||
5 分間の解説動画(英語): https://youtu.be/e0irOYbQe7I
|
||||
|
||||
- Cultivation をダウンロードします。
|
||||
- Windows 10/11 をお使いの場合は、MSI インストーラーを使用してください。
|
||||
- Windows 7 をお使いの場合または MSI インストーラーが動作しない場合、ZIP を使用してください。また、[WebView2](https://developer.microsoft.com/ja-jp/microsoft-edge/webview2/)をインストールしてください。
|
||||
- GNU/Linux または macOS をお使いの場合は、[Linux・macOS での動作をサポートするのを手伝っていただけると嬉しいです!](https://github.com/Grasscutters/Cultivation/issues/7)
|
||||
- Cultivation をインストールまたは展開します。
|
||||
- Cultivation を<strong><u>管理者権限で</u></strong>開きます。
|
||||
- Options(右上の歯車アイコン)内で、ゲームのインストールパスを設定します。
|
||||
- 他の場所に既存の Grasscutter サーバーがインストールされている場合は、`.jar`ファイルのパスを設定できます。Cultivation を介して行われるすべてのダウンロードは、そのパスを自動的に使用します。追加の構成は必要ありません。
|
||||
- 複数の Java バージョンを使用している場合、Java 17 のパスを Cultivation に設定できます(自分で Grasscutter サーバーを実行している場合にのみ必要です)。
|
||||
- 自分でサーバーをダウンロードするか、公開サーバーに参加するかどうかを決定します。
|
||||
- 公開サーバーに参加する場合は、[Grasscutter に接続]をクリックして、アドレスとポートを入力してください。
|
||||
- システムエラー、または 4214 エラーが表示されている場合は、[Discord サポートチャンネル](https://discord.gg/grasscutter)で問い合わせてください。
|
||||
- 自分でサーバーをダウンロードする場合は、"Downloads"メニューを開きます。(右上の下矢印アイコン)
|
||||
- "Grasscutter All-in-One をダウンロード"します。(一番上)
|
||||
- それが完了したら、「起動」の横にあるサーバーアイコンをクリックします。
|
||||
- 自分のサーバーでプレイするには:
|
||||
- [Grasscutter に接続]をクリックします。
|
||||
- アドレスに`localhost`、ポート番号に`443`を指定します。
|
||||
- HTTPS 接続を無効にします。
|
||||
- 何らかのエラーが発生した場合は、[Discord サポートチャンネル](https://discord.gg/grasscutter)で問い合わせてください。
|
||||
- 何らかの Cultivation に関する問題は[Issues ページ](/issues)へお願いします。
|
||||
- 何らかの Grasscutter サーバーに関する問題は[Grasscutter の Issues ページ](https://github.com/Grasscutters/Grasscutter/issues)へお願いします。
|
||||
|
||||
# トラブルシューティング
|
||||
|
||||
### ホワイトスクリーン、インスタントクラッシュなどの問題
|
||||
|
||||
- まず、[Windows 8 互換モード](https://www.lifewire.com/run-older-programs-with-windows-10-compatibility-mode-4587064)で実行してみてください。
|
||||
- 解決しない場合は、[WebView2](https://developer.microsoft.com/ja-jp/microsoft-edge/webview2/#download-section)を完全にアンインストールしてから再インストールしてみてください。
|
||||
- アンインストール時に問題が発生する場合は、`HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}`レジストリを削除して再度試してください。
|
||||
- [コマンドプロンプトからアンインストール](https://superuser.com/a/1743626)する方法を試すこともできます。
|
||||
|
||||
### Cultivation を使用した後にインターネットに接続できない問題
|
||||
|
||||
ゲームを終了すると、Cultivation ウィンドウに戻り再びポップアップすることを確認してください。これは、ゲームが終了されたこと、そしてプロキシ設定が正常に戻されたことを示しています。ウィンドウに戻る前に Cultivation を閉じた場合、またはインターネットの他の問題が発生した場合は、[Windows のプロキシ設定](https://is.gd/tZHkvl)を開き、"手動プロキシセットアップ"をオフにしてください。これでインターネット接続は元に戻ります。
|
||||
|
||||
# 開発者向けクイックスタート
|
||||
|
||||
### セットアップ
|
||||
|
||||
- [NodeJS >12](https://nodejs.org/en/) をインストール
|
||||
- [yarn](https://classic.yarnpkg.com/lang/en/docs/install) をインストール (`npm`愛用者の方々、ごめんなさい...)
|
||||
- [Rust](https://www.rust-lang.org/tools/install) をインストール
|
||||
- `yarn install`
|
||||
- `yarn tauri dev`
|
||||
|
||||
### ビルド
|
||||
|
||||
リリースビルド:
|
||||
|
||||
- `yarn build`
|
||||
|
||||
デバッグビルド:
|
||||
|
||||
- `yarn build --debug`
|
||||
|
||||
### コードフォーマット・lint
|
||||
|
||||
- `yarn format`
|
||||
- `yarn lint`, `yarn lint:fix`
|
||||
|
||||
### artifact を生成
|
||||
|
||||
- 秘密鍵へのパスを持つ環境変数として`TAURI_PRIVATE_KEY`を追加
|
||||
- 秘密鍵のパスワードを持つ環境変数として`TAURI_KEY_PASSWORD`を追加
|
||||
- `yarn build`
|
||||
|
||||
アップデートは`src-tauri/target/(release|debug)/msi/Cultivation_X.X.X_x64_xx-XX.msi.zip`へ追加されます
|
||||
|
||||
# テーマについて
|
||||
|
||||
テーマについての完全なリファレンスは[こちら](/THEMES.md)
|
||||
|
||||
# スクリーンショット
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## クレジット
|
||||
|
||||
- [SpikeHD](https://github.com/SpikeHD): オリジナルである **GrassClipper** を製作し、Cultivation の素晴らしい UI を作成
|
||||
- [KingRainbow44](https://github.com/KingRainbow44): ゼロからプロキシデーモンを作成し、Cultivation へ統合
|
||||
- [Benj](https://github.com/4Benj): クライアントのパッチに関するアシスタント
|
||||
- [lilmayofuksu](https://github.com/lilmayofuksu): クライアントのパッチに関するアシスタント
|
||||
- [Tauri](https://tauri.app): 素晴らしく軽量でシンプルなデスクトップアプリケーションフレームワーク・ライブラリを提供
|
||||
@@ -1,4 +1,4 @@
|
||||
[EN](README.md) | 简中 | [繁中](README_zh-TW.md)
|
||||
[EN](README.md) | 简中 | [繁中](README_zh-TW.md) | [日本語](README_ja-JP.md)
|
||||
|
||||
# Cultivation
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[EN](README.md) | [简中](README_zh-CN.md) | 繁中
|
||||
[EN](README.md) | [简中](README_zh-CN.md) | 繁中 | [日本語](README_ja-JP.md)
|
||||
|
||||
# 客戶端修補通知
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Themes support entirely custom JS and CSS, enabling you to potentially change every single thing about Cultivation with relative ease.
|
||||
|
||||
You can refer to the example theme [found here.](https://cdn.discordapp.com/attachments/992943872479084614/992993575652565002/Example.zip)
|
||||
You can refer to the example theme [found here.](https://github.com/Grasscutters/Cultivation/blob/main/docs/ExampleTheme.zip)
|
||||
|
||||
You will need CSS and JS experience if you want to do anything cool.
|
||||
|
||||
|
||||
BIN
docs/ExampleTheme.zip
Normal file
BIN
docs/ExampleTheme.zip
Normal file
Binary file not shown.
@@ -89,6 +89,9 @@ This does not include commonly used components (buttons, divider lines, commit a
|
||||
| `#menuOptionsContainerBG` | Container for Background option |
|
||||
| `#menuOptionsLabelBG` | Label for background option |
|
||||
| `#menuOptionsDirBG` | Container for background url/local path option |
|
||||
| `#menuOptionsContainerUseThemeBG` | Container for forcing theme background option |
|
||||
| `#menuOptionsLabelUseThemeBG` | Label for forcing theme background option |
|
||||
| `#menuOptionsUseThemeBG` | Toggle forcing theme background button container |
|
||||
| `#menuOptionsContainerLang` | Container for language change option |
|
||||
| `#menuOptionsLabelLang` | Label for language change option |
|
||||
| `#menuOptionsSelectLang` | Container for language change select menu |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cultivation",
|
||||
"version": "1.0.26",
|
||||
"version": "1.5.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.0.0-rc.5",
|
||||
|
||||
3244
src-tauri/Cargo.lock
generated
3244
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "cultivation"
|
||||
version = "1.1.1"
|
||||
version = "1.5.1"
|
||||
description = "A custom launcher for anime game."
|
||||
authors = ["KingRainbow44", "SpikeHD"]
|
||||
license = ""
|
||||
repository = "https://github.com/Grasscutters/Cultivation.git"
|
||||
default-run = "cultivation"
|
||||
edition = "2021"
|
||||
rust-version = "1.57"
|
||||
rust-version = "1.58"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -22,6 +22,12 @@ registry = "1.2.1"
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
sudo = "0.6.0"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
anyhow = "1.0.58"
|
||||
os_type = "2.6"
|
||||
term-detect = "0.1.7"
|
||||
which = "4.4"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.0.9", features = ["api-all"] }
|
||||
@@ -53,7 +59,7 @@ serde_json = "1"
|
||||
|
||||
# Dependencies for the HTTP(S) proxy.
|
||||
http = "0.2"
|
||||
hudsucker = "0.19.1"
|
||||
hudsucker = "0.19.2"
|
||||
tracing = "0.1.21"
|
||||
tokio-rustls = "0.23.0"
|
||||
tokio-tungstenite = "0.17.0"
|
||||
@@ -71,6 +77,12 @@ file_diff = "1.0.0"
|
||||
rust-ini = "0.18.0"
|
||||
ctrlc = "3.2.3"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies.anime-launcher-sdk]
|
||||
git = "https://github.com/an-anime-team/anime-launcher-sdk.git"
|
||||
tag = "1.11.1"
|
||||
default-features = false
|
||||
features = ["all", "genshin"]
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "IP 地址...",
|
||||
"port_placeholder": "端口...",
|
||||
"files_downloading": "文件下载中:",
|
||||
"files_extracting": "文件解压中:"
|
||||
"files_extracting": "文件解压中:",
|
||||
"game_path_notify": "未找到游戏路径,请记得在设置中进行设置"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "已启用",
|
||||
@@ -24,17 +25,23 @@
|
||||
"grasscutter_with_game": "随游戏自动启动 Grasscutter",
|
||||
"language": "选择语言",
|
||||
"background": "设置自定义背景(链接或文件)",
|
||||
"use_theme_background": "使用所选主题提供的背景",
|
||||
"theme": "设置主题",
|
||||
"patch_rsa": "自动修改RSA",
|
||||
"use_proxy": "使用内置代理",
|
||||
"wipe_login": "清除登录缓存",
|
||||
"horny_mode": "Horny 模式",
|
||||
"auto_mongodb": "自动启动 MongoDB",
|
||||
"un_elevated": "非提升运行游戏(无管理员)"
|
||||
"un_elevated": "非提升运行游戏(无管理员)",
|
||||
"redirect_more": "还可以重定向其他MHY游戏",
|
||||
"web_cache": "删除 webCaches 文件夹",
|
||||
"launch_args": "启动参数",
|
||||
"offline_mode": "离线模式",
|
||||
"fix_res": "修复登录超时"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "下载 Grasscutter 一体化",
|
||||
"grasscutter_fullquest": "下载 Quest 一体化",
|
||||
"grasscutter_fullquest": "下载 5.0 一体化",
|
||||
"grasscutter_stable_data": "下载 Grasscutter 稳定版数据",
|
||||
"grasscutter_latest_data": "下载 Grasscutter 开发版数据",
|
||||
"grasscutter_stable_data_update": "更新 Grasscutter 稳定版数据",
|
||||
@@ -62,7 +69,8 @@
|
||||
"select_folder": "选择文件夹...",
|
||||
"download": "下载",
|
||||
"delete": "删除",
|
||||
"install": "安装"
|
||||
"install": "安装",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "最近提交",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "IP地址...",
|
||||
"port_placeholder": "通訊埠...",
|
||||
"files_downloading": "檔案下載中:",
|
||||
"files_extracting": "檔案解壓縮中:"
|
||||
"files_extracting": "檔案解壓縮中:",
|
||||
"game_path_notify": "找不到遊戲路徑,記得在設置裡設置!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "已啟用",
|
||||
@@ -24,17 +25,23 @@
|
||||
"grasscutter_with_game": "伴隨遊戲一起啟動Grasscutter",
|
||||
"language": "語言",
|
||||
"background": "選擇自定義背景(網址或檔案)",
|
||||
"use_theme_background": "使用所選主題提供的背景",
|
||||
"theme": "選擇主題",
|
||||
"patch_rsa": "自動修補RSA",
|
||||
"use_proxy": "使用內建代理伺服器",
|
||||
"wipe_login": "擦除登錄緩存",
|
||||
"horny_mode": "Horny模式",
|
||||
"auto_mongodb": "自動啟動 MongoDB",
|
||||
"un_elevated": "在不升高的情况下运行游戏(没有管理员)。"
|
||||
"un_elevated": "在不升高的情况下运行游戏(没有管理员)。",
|
||||
"redirect_more": "同時重定向其他 MHY 遊戲",
|
||||
"web_cache": "刪除 webCaches 文件夾",
|
||||
"launch_args": "啟動參數",
|
||||
"offline_mode": "離線模式",
|
||||
"fix_res": "修復登入逾時"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "下載Grasscutter多合一下載",
|
||||
"grasscutter_fullquest": "下载 Quest 一体化",
|
||||
"grasscutter_fullquest": "下载 5.0 一体化",
|
||||
"grasscutter_stable_data": "下載Grasscutter穩定版數據(Data)",
|
||||
"grasscutter_latest_data": "下載Grasscutter開發板數據(Data)",
|
||||
"grasscutter_stable_data_update": "更新Grasscutter穩定版數據(Data)",
|
||||
@@ -62,7 +69,8 @@
|
||||
"select_folder": "選擇資料夾...",
|
||||
"download": "下載",
|
||||
"delete": "刪除",
|
||||
"install": "安裝"
|
||||
"install": "安裝",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "最近的PR",
|
||||
|
||||
@@ -3,57 +3,67 @@
|
||||
"main": {
|
||||
"title": "Cultivation",
|
||||
"launch_button": "Starten",
|
||||
"gc_enable": "Über Grasscutter verbinden",
|
||||
"https_enable": "HTTPS nutzen",
|
||||
"ip_placeholder": "Server Adresse...",
|
||||
"port_placeholder": "Port...",
|
||||
"files_downloading": "Herunterladen von Dateien: ",
|
||||
"files_extracting": "Extrahieren von Dateien: "
|
||||
"gc_enable": "Mit Grasscutter verbinden",
|
||||
"https_enable": "HTTPS verwenden",
|
||||
"ip_placeholder": "Server-Adresse",
|
||||
"port_placeholder": "Port",
|
||||
"files_downloading": "Dateien herunterladen: ",
|
||||
"files_extracting": "Dateien extrahieren: ",
|
||||
"game_path_notify": "Spielverzeichnis nicht gefunden, bitte lege es in den Einstellungen fest!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Aktiviert",
|
||||
"disabled": "Deaktiviert",
|
||||
"game_path": "Spielpfad",
|
||||
"game_executable": "Spiel Datei auswählen",
|
||||
"recover_rsa": "Notfall Wiederherstellung der RSA",
|
||||
"grasscutter_jar": "Grasscuter JAR auswählen",
|
||||
"game_path": "Spielinstallationspfad festlegen",
|
||||
"game_command": "Spielstartbefehl",
|
||||
"game_executable": "Spiele Datei festlegen",
|
||||
"recover_rsa": "Notfall-RSA löschen",
|
||||
"grasscutter_jar": "Grasscutter-JAR festlegen",
|
||||
"toggle_encryption": "Verschlüsselung umschalten",
|
||||
"install_certificate": "Installeer proxy certificaat",
|
||||
"java_path": "Benutzerdefinierten Java Pfad setzen",
|
||||
"install_certificate": "Proxy-Zertifikat installieren",
|
||||
"java_path": "Benutzerdefinierten Java-Pfad festlegen",
|
||||
"grasscutter_with_game": "Grasscutter automatisch mit dem Spiel starten",
|
||||
"language": "Sprache auswählen",
|
||||
"background": "Benutzerdefinierten Hintergrund festlegen (link oder bild)",
|
||||
"theme": "Theme auswählen",
|
||||
"background": "Benutzerdefinierten Hintergrund festlegen (Link oder Bild-Datei)",
|
||||
"use_theme_background": "Hintergrund des ausgewählten Themes verwenden",
|
||||
"theme": "Theme festlegen",
|
||||
"patch_rsa": "RSA automatisch patchen",
|
||||
"use_proxy": "Gebruik interne proxy",
|
||||
"wipe_login": "Wis de inlogcache",
|
||||
"horny_mode": "Geile modus",
|
||||
"auto_mongodb": "Start automatisch MongoDB",
|
||||
"un_elevated": "Führen Sie das Spiel nicht erhöht aus (kein Admin)"
|
||||
"use_proxy": "Internen Proxy verwenden",
|
||||
"wipe_login": "Login-Cache löschen",
|
||||
"horny_mode": "Horny Modus",
|
||||
"auto_mongodb": "MongoDB automatisch starten",
|
||||
"un_elevated": "Spiel ohne Administratorrechte ausführen",
|
||||
"redirect_more": "Auch andere miHoYo-Spiele umleiten",
|
||||
"check_aagl": "Für weitere Optionen, schaue weiter",
|
||||
"grasscutter_elevation": "Methode zur Ausführung von GC auf eingeschränkten Ports",
|
||||
"web_cache": "WebCaches-Ordner löschen",
|
||||
"launch_args": "Start-Argumente",
|
||||
"offline_mode": "Offline-Modus",
|
||||
"fix_res": "Login-Zeitüberschreitung beheben"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Alles in Einem Grasscutter Daten herunterladen",
|
||||
"grasscutter_fullquest": "Alles in Einem Questing Daten herunterladen",
|
||||
"grasscutter_stable_data": "Stabile Grasscutter Daten herunterladen",
|
||||
"grasscutter_latest_data": "Aktuellste Grasscutter Daten herunterladen",
|
||||
"grasscutter_stable_data_update": "Stabile Grasscutter Daten aktualisieren",
|
||||
"grasscutter_latest_data_update": "Aktuellste Grasscutter Daten aktualisieren",
|
||||
"grasscutter_unstable": "Stabile Grasscutter Version herunterladen",
|
||||
"grasscutter_latest": "Aktuellste Grasscutter Version herunterladen",
|
||||
"grasscutter_unstable_update": "Stabile Grasscutter Version aktualisieren",
|
||||
"grasscutter_latest_update": "Aktuellste Grasscutter Version aktualisieren",
|
||||
"resources": "Grasscutter Ressourcen herunterladen",
|
||||
"grasscutter_fullbuild": "Grasscutter All-in-One herunterladen",
|
||||
"grasscutter_fullquest": "5.0 All-in-One herunterladen",
|
||||
"grasscutter_stable_data": "Stabile Grasscutter-Daten herunterladen",
|
||||
"grasscutter_latest_data": "Neueste Grasscutter-Daten herunterladen",
|
||||
"grasscutter_stable_data_update": "Stabile Grasscutter-Daten aktualisieren",
|
||||
"grasscutter_latest_data_update": "Neueste Grasscutter-Daten aktualisieren",
|
||||
"grasscutter_unstable": "Grasscutter Questing herunterladen",
|
||||
"grasscutter_latest": "Neueste Grasscutter-Version herunterladen",
|
||||
"grasscutter_unstable_update": "Grasscutter Questing aktualisieren",
|
||||
"grasscutter_latest_update": "Neueste Grasscutter-Version aktualisieren",
|
||||
"resources": "Grasscutter-Ressourcen herunterladen",
|
||||
"game": "Spiel herunterladen",
|
||||
"aio_header": "Alles in Einem herunterladen",
|
||||
"individual_header": "Einzelne Teile herunterladen:",
|
||||
"aio_header": "Alles-in-Einem Downloads:",
|
||||
"individual_header": "Einzelne Downloads:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "GIMI 3dmigoto herunterladen"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Lädt herunter",
|
||||
"extracting": "Extrahiert",
|
||||
"downloading": "Herunterladen",
|
||||
"extracting": "Extrahieren",
|
||||
"error": "Fehler",
|
||||
"finished": "Fertig",
|
||||
"finished": "Abgeschlossen",
|
||||
"stopped": "Gestoppt"
|
||||
},
|
||||
"components": {
|
||||
@@ -61,33 +71,36 @@
|
||||
"select_folder": "Ordner auswählen...",
|
||||
"download": "Herunterladen",
|
||||
"delete": "Löschen",
|
||||
"install": "Installieren"
|
||||
"install": "Installieren",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Letzte Commits",
|
||||
"latest_version": "Letzte Version"
|
||||
"latest_commits": "Neueste Commits",
|
||||
"latest_version": "Neueste Version"
|
||||
},
|
||||
"help": {
|
||||
"port_help_text": "Vergewissern Sie sich, dass es sich um den Port des Dispatch-Servers handelt, nicht um den Port des Spiel-Servers. Dieser ist fast immer '443'.",
|
||||
"game_help_text": "Sie müssen keine separate Kopie verwenden, um mit Grasscutter zu spielen. Dies ist entweder für ein Downgrade auf die Version 2.6 oder wenn Sie das Spiel nicht installiert haben.",
|
||||
"gc_stable_jar": "Laden Sie den aktuellen stabilen Grasscutter-Build herunter, der eine Jar-Datei und Datendateien enthält.",
|
||||
"gc_fullbuild": "Download een volledige Grasscutter-build, inclusief repo, jar en bronnen. Is volledig ingesteld en vereist geen andere downloads uit dit menu",
|
||||
"gc_dev_jar": "Laden Sie die neueste Grasscutter-Entwicklungsversion herunter, welche eine Jar-Datei und Datendateien enthält.",
|
||||
"gc_stable_data": "Laden Sie die stabilen Grasscutter Daten herunter, welche keine Jar-Datei enthalten. Dies ist nützlich zum Aktualisieren.",
|
||||
"gc_dev_data": "Laden Sie die neuesten Grasscutter-Entwicklungsdateien herunter, welche keine Jar-Datei enthält. Dies ist nützlich zum Aktualisieren.",
|
||||
"resources": "Diese werden auch benötigt, um einen Grasscutter-Server auszuführen. Diese Schaltfläche ist grau, wenn Sie einen bestehenden Ressourcenordner mit Inhalten haben",
|
||||
"emergency_rsa": "Im Fall, dass etwas schief laufen sollte, kannst du deine RSA auf die letzte offizielle Version zurücksetzen",
|
||||
"use_proxy": "Nutze den internen Proxy von Cultivation. Du solltest dies aktivieren, es sei denn du nutzt Programme wie Fiddler",
|
||||
"patch_rsa": "Patche und aktualisiere deine RSA automatisch. Solange du nicht mit einer alten/nicht offiziellen Version spielst oder deine RSA manuell gepatcht hast, sollte dies aktiviert sein.",
|
||||
"add_delay": "Verzögerung im 3dmigoto-Lader einstellen! \nDies sollte die Ladeprobleme beheben, führt aber zu einer kleinen Verzögerung, wenn 3dmigoto beim Start des Spiels geladen wird. \nSie können nun wieder mit 3dmigoto starten.",
|
||||
"migoto": "Zum Importieren von Modellen von GameBanana"
|
||||
"port_help_text": "Stelle sicher, dass dies der Port des Dispatch-Servers ist, nicht der des Spielservers. Dies ist fast immer '443'.",
|
||||
"game_help_text": "Du musst keine separate Kopie verwenden, um mit Grasscutter zu spielen. Dies ist entweder für ein Downgrade auf Version 2.6 oder wenn du das Spiel nicht installiert hast.",
|
||||
"gc_stable_jar": "Lade die aktuelle stabile Grasscutter-Version herunter, die die JAR-Datei und Daten enthält.",
|
||||
"gc_fullbuild": "Lade eine vollständige Grasscutter-Version herunter, inklusive Repository, JAR-Datei und Ressourcen. Sie ist vollständig eingerichtet und erfordert keine weiteren Downloads aus diesem Menü.",
|
||||
"gc_dev_jar": "Lade die neueste Entwicklungsversion von Grasscutter herunter, die die JAR-Datei und Daten enthält.",
|
||||
"gc_stable_data": "Lade die aktuellen stabilen Grasscutter-Daten herunter, die keine JAR-Datei enthalten. Dies ist nützlich für Updates.",
|
||||
"gc_dev_data": "Lade die neuesten Entwicklungsdetails von Grasscutter herunter, die keine JAR-Datei enthalten. Dies ist nützlich für Updates.",
|
||||
"encryption": "Dies sollte normalerweise deaktiviert sein.",
|
||||
"resources": "Diese werden auch benötigt, um einen Grasscutter-Server auszuführen. Diese Schaltfläche ist grau, wenn bereits ein Ressourcenordner mit Inhalten vorhanden ist.",
|
||||
"emergency_rsa": "Für den Fall, dass etwas schiefgegangen ist, erzwingt das Löschen des RSA-Patches.",
|
||||
"use_proxy": "Verwende den internen Cultivation-Proxy. Dies sollte aktiviert sein, es sei denn, du verwendest etwas wie Fiddler.",
|
||||
"patch_rsa": "Patche und entpatche dein Spiel-RSA automatisch. Dies sollte aktiviert sein, es sei denn, du spielst mit alten/nicht offiziellen Versionen (Versionen 3.0 und älter).",
|
||||
"add_delay": "Setze eine Verzögerung im 3dmigoto-Loader! Dies sollte Ladeprobleme beheben, fügt jedoch eine geringfügige Verzögerung hinzu, wenn 3dmigoto beim Starten des Spiels geladen wird. Du kannst jetzt wieder mit 3dmigoto starten.",
|
||||
"migoto": "Zum Importieren von Modellen von GameBanana",
|
||||
"grasscutter_elevation_help_text": "Die Methode, die verwendet wird, um Grasscutter zu ermöglichen, Port 443 zu binden (was für normale Benutzer unter Linux nicht erlaubt ist). Verfügbare Methoden:\n Capability - gewähre der Java Virtual Machine die Fähigkeit, Ports unter 1024 zu binden. Dies ermöglicht auch allen anderen Programmen, die auf dieser JVM ausgeführt werden, diese Ports zu binden.\n Root - führe GC als Root aus. Dies ermöglicht auch dem GC-Server, seinen Plugins und der JVM so ziemlich alles, einschließlich das Senden deiner Bilder an die NSA, CIA und die Alphabet-Boys.\n None - für keine Methode. Dies erfordert, dass du den GC-Dispatch-Port änderst."
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
"migoto_name": "Migoto",
|
||||
"reshade_name": "Reshade",
|
||||
"akebi": "Akebi.exe festlegen",
|
||||
"migoto": "Migoto.exe festlegen",
|
||||
"reshade": "Reshade injector festlegen"
|
||||
"akebi": "Akebi/Acrepi Ausführbare Datei festlegen",
|
||||
"migoto": "3DMigoto Ausführbare Datei festlegen",
|
||||
"reshade": "Reshade Injector festlegen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"port_placeholder": "Port...",
|
||||
"files_downloading": "Files Downloading: ",
|
||||
"files_extracting": "Files Extracting: ",
|
||||
"game_path_notify": "Game path not found, remember to set it in !"
|
||||
"game_path_notify": "Game path not found, remember to set it in settings!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Enabled",
|
||||
@@ -25,17 +25,25 @@
|
||||
"grasscutter_with_game": "Automatically launch Grasscutter with game",
|
||||
"language": "Select Language",
|
||||
"background": "Set Custom Background (link or image file)",
|
||||
"use_theme_background": "Use the background supplied by selected theme",
|
||||
"theme": "Set Theme",
|
||||
"patch_rsa": "Automatically Patch RSA",
|
||||
"use_proxy": "Use Internal Proxy",
|
||||
"wipe_login": "Wipe Login Cache",
|
||||
"horny_mode": "Horny Mode",
|
||||
"auto_mongodb": "Automatically Start MongoDB",
|
||||
"un_elevated": "Run the game non-elevated (no admin)"
|
||||
"un_elevated": "Run the game non-elevated (no admin)",
|
||||
"redirect_more": "Also redirect other MHY games",
|
||||
"check_aagl": "For more options, check the other launcher",
|
||||
"grasscutter_elevation": "Method of running GC on restricted ports",
|
||||
"web_cache": "Delete webCaches folder",
|
||||
"launch_args": "Launch Args",
|
||||
"offline_mode": "Offline Mode",
|
||||
"fix_res": "Fix Login Timeout"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Download Grasscutter All-in-One",
|
||||
"grasscutter_fullquest": "Download Questing All-in-One",
|
||||
"grasscutter_fullquest": "Download 5.0 All-in-One",
|
||||
"grasscutter_stable_data": "Download Grasscutter Stable Data",
|
||||
"grasscutter_latest_data": "Download Grasscutter Latest Data",
|
||||
"grasscutter_stable_data_update": "Update Grasscutter Stable Data",
|
||||
@@ -63,7 +71,8 @@
|
||||
"select_folder": "Select folder...",
|
||||
"download": "Download",
|
||||
"delete": "Delete",
|
||||
"install": "Install"
|
||||
"install": "Install",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Recent Commits",
|
||||
@@ -83,13 +92,14 @@
|
||||
"use_proxy": "Use the Cultivation internal proxy. You should have this enabled unless you use something like Fiddler",
|
||||
"patch_rsa": "Patch and unpatch your game RSA automatically. Unless playing with old/non-official versions (3.0 and older), this should be enabled.",
|
||||
"add_delay": "Set delay in 3dmigoto loader! \nThis should fix loading issues, but will add a small delay to when 3dmigoto is loaded upon launching the game. \nYou can now launch with 3dmigoto again.",
|
||||
"migoto": "For importing models from GameBanana"
|
||||
"migoto": "For importing models from GameBanana",
|
||||
"grasscutter_elevation_help_text": "The method used to allow Grasscutter to bind port 443 (which is not allowed for regular users on Linux)\nAvailable methods:\n Capability - grant the Java Virtual Machine the capability to bind ports below 1024. This also allows all other programs running on that JVM to bind these ports.\n Root - run GC as root. This also allows the GC server, its plugins and the JVM to do pretty much anything, including sending your nudes to the NSA, CIA, and the alphabet boys.\n None - for no method. This requires you to change the GC Dispatch port."
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
"migoto_name": "Migoto",
|
||||
"reshade_name": "Reshade",
|
||||
"akebi": "Set Akebi/Acrepi Executable",
|
||||
"akebi": "Set Akebi/Other Cheat Executable",
|
||||
"migoto": "Set 3DMigoto Executable",
|
||||
"reshade": "Set Reshade Injector"
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "Dirección del servidor...",
|
||||
"port_placeholder": "Puerto...",
|
||||
"files_downloading": "Archivos Descargandose: ",
|
||||
"files_extracting": "Archivos Extrayendose: "
|
||||
"files_extracting": "Archivos Extrayendose: ",
|
||||
"game_path_notify": "Ruta de juego no encontrada, ¡recuerda configurarla en ajustes!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Activado",
|
||||
@@ -19,31 +20,37 @@
|
||||
"recover_rsa": "Recuperación de RSA de Emergencia",
|
||||
"grasscutter_jar": "Establecer JAR de Grasscutter",
|
||||
"toggle_encryption": "Alternar Cifrado",
|
||||
"install_certificate": "Instalar Certificado Proxie",
|
||||
"java_path": "Establecer Ruta Personalizada de Java",
|
||||
"install_certificate": "Instalar Certificado Proxy",
|
||||
"java_path": "Establecer ruta personalizada de Java",
|
||||
"grasscutter_with_game": "Iniciar automáticamente Grasscutter con el juego",
|
||||
"language": "Seleccionar Idioma",
|
||||
"background": "Establecer Fondo Personalizado (link o archivo de imagen)",
|
||||
"language": "Seleccionar idioma",
|
||||
"background": "Establecer fondo personalizado (link o archivo de imagen)",
|
||||
"use_theme_background": "Usar fondo proporcionado por el tema seleccionado",
|
||||
"patch_rsa": "Parchear RSA automáticamente",
|
||||
"theme": "Establecer Tema",
|
||||
"theme": "Establecer tema",
|
||||
"use_proxy": "Usar proxy interno",
|
||||
"wipe_login": "Borrar caché de inicio de sesión",
|
||||
"horny_mode": "Modo cachondo",
|
||||
"auto_mongodb": "Iniciar automáticamente MongoDB",
|
||||
"un_elevated": "Ejecutar el juego no elevado (no admin)"
|
||||
"un_elevated": "Ejecutar el juego sin permisos de administrador",
|
||||
"redirect_more": "También redirigir otros juegos MHY",
|
||||
"web_cache": "Eliminar la carpeta webCaches",
|
||||
"launch_args": "Args de lanzamiento",
|
||||
"offline_mode": "Modo sin conexión",
|
||||
"fix_res": "Reparar el tiempo de espera"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Descargar Datos todo en uno de Grasscutter",
|
||||
"grasscutter_fullquest": "Descargar Datos todo en uno de Questing",
|
||||
"grasscutter_stable_data": "Descargar Datos Estables de Grasscutter",
|
||||
"grasscutter_latest_data": "Descargar Datos más Recientes de Grasscutter",
|
||||
"grasscutter_stable_data_update": "Actualizar Datos Estables de Grasscutter",
|
||||
"grasscutter_latest_data_update": "Actualizar Datos más Recientes de Grasscutter",
|
||||
"grasscutter_unstable": "Descargar Grasscutter Estable",
|
||||
"grasscutter_fullbuild": "Descargar datos todo en uno de Grasscutter",
|
||||
"grasscutter_fullquest": "Descargar datos todo en uno de 5.0",
|
||||
"grasscutter_stable_data": "Descargar datos Estables de Grasscutter",
|
||||
"grasscutter_latest_data": "Descargar datos más Recientes de Grasscutter",
|
||||
"grasscutter_stable_data_update": "Actualizar datos estables de Grasscutter",
|
||||
"grasscutter_latest_data_update": "Actualizar datos más recientes de Grasscutter",
|
||||
"grasscutter_unstable": "Descargar Grasscutter estable",
|
||||
"grasscutter_latest": "Descargar Grasscutter más reciente",
|
||||
"grasscutter_unstable_update": "Actualizar Grasscutter Estable",
|
||||
"grasscutter_unstable_update": "Actualizar Grasscutter estable",
|
||||
"grasscutter_latest_update": "Actualizar Grasscutter más reciente",
|
||||
"resources": "Descargar Recursos de Grasscutter",
|
||||
"resources": "Descargar recursos de Grasscutter",
|
||||
"game": "Descarga el juego",
|
||||
"aio_header": "Descargas todo en uno:",
|
||||
"individual_header": "Descargas de piezas individuales:",
|
||||
@@ -58,24 +65,25 @@
|
||||
"stopped": "Detenido"
|
||||
},
|
||||
"components": {
|
||||
"select_file": "Seleccionar el archivo o carpeta...",
|
||||
"select_folder": "Seleccionar la carpeta...",
|
||||
"select_file": "Seleccionar el archivo o carpeta",
|
||||
"select_folder": "Seleccionar la carpeta",
|
||||
"download": "Descargar",
|
||||
"delete": "Borrar",
|
||||
"install": "Instalar"
|
||||
"install": "Instalar",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Commits Recientes",
|
||||
"latest_commits": "Commits recientes",
|
||||
"latest_version": "Ultima versión"
|
||||
},
|
||||
"help": {
|
||||
"port_help_text": "Asegúrese de que este sea el Dispatch server port, no el Game server port. Este es casi siempre '443'.",
|
||||
"port_help_text": "Asegúrese de que este sea el puerto del servidor Dispatch, no el Game server port. Este es casi siempre '443'.",
|
||||
"game_help_text": "No necesitas usar una copia separada para jugar con Grasscutter. Esto es para cambiar a 2.6 o si no tienes el juego instalado.",
|
||||
"gc_stable_jar": "Descargue la versión Estable actual de Grasscutter, que incluye el archivo jar y los archivos de datos.",
|
||||
"gc_stable_jar": "Descargue la versión estable actual de Grasscutter, que incluye el archivo .jar y los archivos de datos.",
|
||||
"gc_fullbuild": "Descarga una compilación completa de Grasscutter, incluyendo repo, jar y recursos. Está totalmente configurado y no requiere ninguna otra descarga desde este menú.",
|
||||
"gc_dev_jar": "Descargue la última versión de Desarrollo de Grasscutter, que incluye archivos jar y archivos de datos.",
|
||||
"gc_stable_data": "Descargue los archivos de Datos Estables actuales de Grasscutter, que no vienen con un archivo jar. Esto es útil para actualizar.",
|
||||
"gc_dev_data": "Descargue los últimos archivos de Datos de Desarrollo de Grasscutter, que no vienen con un archivo jar. Esto es útil para actualizar.",
|
||||
"gc_dev_jar": "Descargue la última versión de desarrollo de Grasscutter, que incluye archivos .jar y archivos de datos.",
|
||||
"gc_stable_data": "Descargue los archivos de datos estables actuales de Grasscutter, que no vienen con un archivo .jar. Esto es útil para actualizar.",
|
||||
"gc_dev_data": "Descargue los últimos archivos de datos de desarrollo de Grasscutter, que no vienen con un archivo .jar. Esto es útil para actualizar.",
|
||||
"resources": "Estos también son necesarios para ejecutar un servidor Grasscutter. Este botón estará gris si tiene una carpeta de recursos existente con contenido dentro.",
|
||||
"add_delay": "¡Retraso en el cargador de 3dmigoto! \nEsto debería solucionar los problemas de carga, pero añadirá un pequeño retraso cuando 3dmigoto se cargue al iniciar el juego. \nAhora puede iniciar con 3dmigoto de nuevo.",
|
||||
"migoto": "Para importar modelos de GameBanana"
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "Adresse du serveur...",
|
||||
"port_placeholder": "Port...",
|
||||
"files_downloading": "Fichiers en cours de telechargement: ",
|
||||
"files_extracting": "Fichiers en cours d'extraction: "
|
||||
"files_extracting": "Fichiers en cours d'extraction: ",
|
||||
"game_path_notify": "Chemin d'accès au jeu non trouvé, n'oubliez pas de le définir dans les options !"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Activé",
|
||||
@@ -24,17 +25,23 @@
|
||||
"grasscutter_with_game": "Lancer Grasscutter automatiquement avec le jeu",
|
||||
"language": "Choisir la langue",
|
||||
"background": "Définir un arriere plan personnalisé (lien ou fichier image)",
|
||||
"use_theme_background": "Utiliser l'arrière-plan fourni par le thème sélectionné",
|
||||
"theme": "Définir un theme",
|
||||
"patch_rsa": "Patcher automatiquement les clés RSA",
|
||||
"use_proxy": "Utiliser le proxy interne",
|
||||
"wipe_login": "Effacer le cache de connexion",
|
||||
"horny_mode": "Mode horny",
|
||||
"auto_mongodb": "Démarrer automatiquement MongoDB",
|
||||
"un_elevated": "Exécuter le jeu sans élévation (pas d'administrateur)"
|
||||
"un_elevated": "Exécuter le jeu sans élévation (pas d'administrateur)",
|
||||
"redirect_more": "Réorienter également les autres jeux MHY",
|
||||
"web_cache": "Supprimer le dossier webCaches",
|
||||
"launch_args": "Arguments de lancement",
|
||||
"offline_mode": "Mode hors ligne",
|
||||
"fix_res": "Réparation du login"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Telecharger Grasscutter tout-en-un",
|
||||
"grasscutter_fullquest": "Télécharger les Quêtes tout-en-un",
|
||||
"grasscutter_fullquest": "Télécharger les 5.0 tout-en-un",
|
||||
"grasscutter_stable_data": "Télécharger les donnees de Grasscutter (version stable)",
|
||||
"grasscutter_latest_data": "Télécharger les donnees de Grasscutter (derniere version)",
|
||||
"grasscutter_stable_data_update": "Mettre à jour les données de Grasscutter (version stable)",
|
||||
@@ -61,7 +68,8 @@
|
||||
"select_folder": "Choisir un dossier...",
|
||||
"download": "Télécharger",
|
||||
"delete": "Supprimer",
|
||||
"install": "Installer"
|
||||
"install": "Installer",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Commits récents",
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
"ip_placeholder": "Alamat Server...",
|
||||
"port_placeholder": "Port...",
|
||||
"files_downloading": "Mendownload File Yang Diperlukan: ",
|
||||
"files_extracting": "MengExtract File: "
|
||||
"files_extracting": "MengExtract File: ",
|
||||
"game_path_notify": "Jalur permainan tidak ditemukan, ingatlah untuk mengaturnya dalam pengaturan!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Diaktifkan",
|
||||
@@ -23,17 +24,23 @@
|
||||
"grasscutter_with_game": "Otomatis Menjalankan Grasscutter Dengan Game",
|
||||
"language": "Pilih Bahasa",
|
||||
"background": "Atur Kustom Latar Belakang (link atau gambar file)",
|
||||
"use_theme_background": "Gunakan latar belakang yang disediakan oleh tema yang dipilih",
|
||||
"theme": "Atur Tema",
|
||||
"patch_rsa": "Automatically Patch RSA",
|
||||
"use_proxy": "Gunakan Proxy Internal",
|
||||
"wipe_login": "Menghapus Cache Login",
|
||||
"horny_mode": "Mode Terangsang",
|
||||
"auto_mongodb": "Mulai MongoDB secara otomatis",
|
||||
"un_elevated": "Jalankan game yang tidak ditinggikan (tanpa admin)"
|
||||
"un_elevated": "Jalankan game yang tidak ditinggikan (tanpa admin)",
|
||||
"redirect_more": "Juga mengarahkan ulang game MHY lainnya",
|
||||
"web_cache": "Hapus folder webCaches",
|
||||
"launch_args": "Luncurkan Args",
|
||||
"offline_mode": "Mode Offline",
|
||||
"fix_res": "Perbaiki batas waktu login"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Sedang Mendownload Grasscutter Semua Dalam Satu",
|
||||
"grasscutter_fullquest": "Unduh pencarian semua dalam satu",
|
||||
"grasscutter_fullquest": "Unduh 5.0 semua dalam satu",
|
||||
"grasscutter_stable_data": "Sedang Mendownload Grasscutter Versi Stabil",
|
||||
"grasscutter_latest_data": "Sedang Mendownload Grasscutter Data Terbaru",
|
||||
"grasscutter_stable_data_update": "Memperbaharui Grasscutter Data Stabil",
|
||||
@@ -59,7 +66,8 @@
|
||||
"select_file": "Pilih File Atau Folder...",
|
||||
"select_folder": "Pilih Folder...",
|
||||
"download": "download",
|
||||
"delete": "Menghapus"
|
||||
"delete": "Menghapus",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Commit Terbaru",
|
||||
|
||||
103
src-tauri/lang/it.json
Normal file
103
src-tauri/lang/it.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"lang_name": "Italiano",
|
||||
"main": {
|
||||
"title": "Cultivation",
|
||||
"launch_button": "Avvia",
|
||||
"gc_enable": "Connettiti a Grasscutter",
|
||||
"https_enable": "Usa HTTPS",
|
||||
"ip_placeholder": "Indirizzo Del Server...",
|
||||
"port_placeholder": "Porta...",
|
||||
"files_downloading": "File in Download: ",
|
||||
"files_extracting": "File in Estrazione: ",
|
||||
"game_path_notify": "Percorso del gioco non trovato, ricordati di impostarlo nelle impostazioni!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Abilitato",
|
||||
"disabled": "Disabilitato",
|
||||
"game_path": "Imposta percorso di installazione del gioco",
|
||||
"game_command": "Commando d'avvio del gioco",
|
||||
"game_executable": "Imposta l'executable del gioco",
|
||||
"recover_rsa": "Eliminazione d'emergenza dell'RSA",
|
||||
"grasscutter_jar": "Imposta il file JAR di Grasscutter",
|
||||
"toggle_encryption": "Cittografia",
|
||||
"install_certificate": "Installa il Certificato del Proxy",
|
||||
"java_path": "Imposta il percorso personalizzato di Java",
|
||||
"grasscutter_with_game": "Avvia automaticamente Grasscutter con il gioco",
|
||||
"language": "Imposta lingua",
|
||||
"background": "Imposta sfondo personalizzato (link o immagine)",
|
||||
"use_theme_background": "Usa lo sfondo fornito dal tema selezionato",
|
||||
"theme": "Imposta tema",
|
||||
"patch_rsa": "Patch RSA automaticamente",
|
||||
"use_proxy": "Usa Proxy Interno",
|
||||
"wipe_login": "Cancella la cache dell'accesso",
|
||||
"horny_mode": "Modalità Horny",
|
||||
"auto_mongodb": "Avvia Automaticamente MongoDB",
|
||||
"un_elevated": "Avvia il gioco non-elevato (non admin)",
|
||||
"redirect_more": "Reindirizza anche altri giochi MHY",
|
||||
"web_cache": "Elimina la cartella webCaches",
|
||||
"launch_args": "Argomenti di lancio",
|
||||
"offline_mode": "Modalità Offline",
|
||||
"fix_res": "Correggere il timeout dell'accesso"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Scarica Grasscutter Tutto-in-Uno",
|
||||
"grasscutter_fullquest": "Scarica 5.0 Tutto-in-Uno",
|
||||
"grasscutter_stable_data": "Scarica i dati di Grasscutter Stabili",
|
||||
"grasscutter_latest_data": "Scarica i dati di Grasscutter Più Recenti",
|
||||
"grasscutter_stable_data_update": "Aggiorna i dati di Grasscutter Stabili",
|
||||
"grasscutter_latest_data_update": "Aggiorna i dati di Grasscutter Più Recenti",
|
||||
"grasscutter_unstable": "Scarica Grasscutter Questing",
|
||||
"grasscutter_latest": "Scarica Grasscutter Più Recente",
|
||||
"grasscutter_unstable_update": "Aggiorna Grasscutter Questing",
|
||||
"grasscutter_latest_update": "Aggiorna Grasscutter più Recente",
|
||||
"resources": "Scarica le Risorse di Grasscutter",
|
||||
"game": "Scarica il gioco",
|
||||
"aio_header": "Tutto-in-Uno Download:",
|
||||
"individual_header": "Download individuali:",
|
||||
"mods_header": "Mod:",
|
||||
"migoto": "Scarica GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Scaricando",
|
||||
"extracting": "Estraendo",
|
||||
"error": "Errore",
|
||||
"finished": "Completato",
|
||||
"stopped": "Interrotto"
|
||||
},
|
||||
"components": {
|
||||
"select_file": "Seleziona file o cartella...",
|
||||
"select_folder": "Seleziona cartella...",
|
||||
"download": "Scarica",
|
||||
"delete": "Cancella",
|
||||
"install": "Installa",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Commit Recenti",
|
||||
"latest_version": "Ultima Versione"
|
||||
},
|
||||
"help": {
|
||||
"port_help_text": "Assicurati che questa sia la porta del server Dispatch, non la porta del server di gioco. È quasi sempre '443'.",
|
||||
"game_help_text": "Non ti serve una copia separata per giocare con Grasscutter. Questo è per fare il downgrade a 2.6 o se non hai il gioco installato.",
|
||||
"gc_stable_jar": "Scarica la build stabile di Grasscutter più recente, che include il file jar e i dati.",
|
||||
"gc_fullbuild": "Scarica la build completa di Grasscutter più recente, che include repo, jar e risorse. È completamente configurato e non richiede altri download da questo menu.",
|
||||
"gc_dev_jar": "Scarica la build in sviluppo di Grasscutter più recente, che include il file jar e i dati.",
|
||||
"gc_stable_data": "Scarica i dati della build stabile di Grasscutter più recente, che non include il file jar. È utile per aggiornare.",
|
||||
"gc_dev_data": "Scarica i dati della build in sviluppo di Grasscutter più recente, che non include il file jar. È utile per aggiornare.",
|
||||
"encryption": "Di solito questo dovrebbe essere disabilitato.",
|
||||
"resources": "Queste sono anche necessari per eseguire un server Grasscutter. Questo bottone è grigio se hai una cartella delle risorse esistente con contenuto all'interno.",
|
||||
"emergency_rsa": "In caso qualcosa è andato storto, forza l'eliminazione dell'RSA.",
|
||||
"use_proxy": "Usa il proxy interno di Cultivation. Dovresti averlo attivato a meno che tu non usi qualcosa come Fiddler.",
|
||||
"patch_rsa": "Patch e unpatch l'RSA del gioco automaticamente. A meno che tu non usi versioni vecchie/non ufficiali del gioco (3.0 e precedenti), questo dovrebbe essere attivato.",
|
||||
"add_delay": "Imposta il ritardo nel caricatore 3dmigoto! \nQuesto dovrebbe risolvere i problemi di caricamento, ma aggiungerà un piccolo ritardo al caricamento di 3dmigoto all'avvio del gioco. \nOra puoi avviare il gioco con 3dmigoto di nuovo.",
|
||||
"migoto": "Per importare modelli da GameBanana"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
"migoto_name": "Migoto",
|
||||
"reshade_name": "Reshade",
|
||||
"akebi": "Imposta l'Executable di Akebi/Acrepi",
|
||||
"migoto": "Imposta l'Executable di 3DMigoto",
|
||||
"reshade": "Imposta l'Injector di Reshade"
|
||||
}
|
||||
}
|
||||
103
src-tauri/lang/ja.json
Normal file
103
src-tauri/lang/ja.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"lang_name": "日本語",
|
||||
"main": {
|
||||
"title": "Cultivation",
|
||||
"launch_button": "起動",
|
||||
"gc_enable": "Grasscutterに接続",
|
||||
"https_enable": "HTTPS接続を使用",
|
||||
"ip_placeholder": "サーバーアドレス...",
|
||||
"port_placeholder": "ポート...",
|
||||
"files_downloading": "ファイルをダウンロード中: ",
|
||||
"files_extracting": "ファイルを展開中: ",
|
||||
"game_path_notify": "ゲームのパスが見つかりません!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
"game_path": "ゲームのインストールパスを設定",
|
||||
"game_command": "ゲームの実行コマンド",
|
||||
"game_executable": "ゲームの実行ファイルパスを設定",
|
||||
"recover_rsa": "RSAを強制削除",
|
||||
"grasscutter_jar": "Grasscutter jarファイルを設定",
|
||||
"toggle_encryption": "暗号化の有無",
|
||||
"install_certificate": "プロキシの証明書をインストール",
|
||||
"java_path": "カスタムJavaパスを設定",
|
||||
"grasscutter_with_game": "ゲーム起動時にGrasscutterを自動起動",
|
||||
"language": "言語を設定",
|
||||
"background": "カスタムの背景を設定 (画像ファイルまたはリンク)",
|
||||
"use_theme_background": "選択したテーマが提供する背景を使用",
|
||||
"theme": "テーマを設定",
|
||||
"patch_rsa": "自動的にRSAにパッチを適用",
|
||||
"use_proxy": "内部プロキシを使用",
|
||||
"wipe_login": "ログインキャッシュを削除",
|
||||
"horny_mode": "Hornyモード",
|
||||
"auto_mongodb": "MongoDBを自動起動",
|
||||
"un_elevated": "昇格せずにゲームを実行 (非管理者権限)",
|
||||
"redirect_more": "他のmhyゲームもリダイレクト",
|
||||
"check_aagl": "その他のオプションは、他のランチャーをチェックしてください",
|
||||
"grasscutter_elevation": "制限されたポートでのGCの実行方法",
|
||||
"web_cache": "webCachesフォルダを削除",
|
||||
"launch_args": "Launch Args"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Grasscutter All-in-Oneをダウンロード",
|
||||
"grasscutter_fullquest": "Questing All-in-Oneをダウンロード",
|
||||
"grasscutter_stable_data": "Grasscutter安定版データファイルをダウンロード",
|
||||
"grasscutter_latest_data": "Grasscutter最新版データファイルをダウンロード",
|
||||
"grasscutter_stable_data_update": "Grasscutter安定版データファイルをアップデート",
|
||||
"grasscutter_latest_data_update": "Grasscutter最新版データファイルをアップデート",
|
||||
"grasscutter_unstable": "Grasscutter Questingをダウンロード",
|
||||
"grasscutter_latest": "Grasscutter最新版をダウンロード",
|
||||
"grasscutter_unstable_update": "Grasscutter Questingをアップデート",
|
||||
"grasscutter_latest_update": "Grasscutter最新版をアップデート",
|
||||
"resources": "Grasscutter Resourcesをダウンロード",
|
||||
"game": "ゲームをダウンロード",
|
||||
"aio_header": "All-in-Oneダウンロード:",
|
||||
"individual_header": "個別ダウンロード:",
|
||||
"mods_header": "Mod:",
|
||||
"migoto": "GIMI 3Dmigotoをダウンロード"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "ダウンロード中",
|
||||
"extracting": "展開中",
|
||||
"error": "エラー",
|
||||
"finished": "完了しました",
|
||||
"stopped": "停止しました"
|
||||
},
|
||||
"components": {
|
||||
"select_file": "ファイルまたはフォルダーを選択...",
|
||||
"select_folder": "フォルダーを選択...",
|
||||
"download": "ダウンロード",
|
||||
"delete": "削除",
|
||||
"install": "インストール"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "最新のコミット",
|
||||
"latest_version": "最新のバージョン"
|
||||
},
|
||||
"help": {
|
||||
"port_help_text": "ゲームサーバーのポートではなく、Dispatchサーバーのポートです。これは大抵'443'です。",
|
||||
"game_help_text": "Grasscutterでプレイするために別のコピーを使用する必要はありません。これは、ゲームがインストールされていない場合か、ver 2.6にダウングレードするためにあります。",
|
||||
"gc_stable_jar": "Grasscutterの現時点での安定版 (jarファイルとデータファイルを含む) をダウンロードします。",
|
||||
"gc_fullbuild": "repo、jar、resourcesを含む完全なGrasscutterビルドをダウンロードします。これは完全にセットアップされており、他のダウンロードを行う必要はありません。",
|
||||
"gc_dev_jar": "Grasscutterの現時点での最新版 (jarファイルとデータファイルを含む) をダウンロードします。",
|
||||
"gc_stable_data": "Grasscutterの現時点での安定版データファイルをダウンロードします。jarファイルは含まれません。アップデートのために使用します。",
|
||||
"gc_dev_data": "Grasscutterの現時点での最新版データファイルをダウンロードします。jarファイルは含まれません。アップデートのために使用します。",
|
||||
"encryption": "これは通常は無効にするべきです。",
|
||||
"resources": "これはGrasscutterサーバーを実行するために必要です。既存のresourcesフォルダ内にファイルがある場合、このボタンはグレーアウトします。",
|
||||
"emergency_rsa": "何か問題が起きた場合に、RSAパッチを強制的に削除します。",
|
||||
"use_proxy": "Cultivationの内部プロキシを使用します。Fiddlerのような外部のプロキシを使わない限り、これを有効にしておく必要があります。",
|
||||
"patch_rsa": "ゲームのRSAに自動的にパッチを適用/解除します。古い(ver 3.0以前)又は非公式のバージョンでプレイしない限り、これは有効にしておくべきです。",
|
||||
"add_delay": "3Dmigoto Loaderに遅延を設定しました!\nこれはロード時の問題を解決しますが、ゲーム起動時に3Dmigotoがロードされる際に遅延が発生します。\nもう一度3Dmigotoを使用して起動できます。",
|
||||
"migoto": "GameBananaからモデルをインポートするために使用します。",
|
||||
"grasscutter_elevation_help_text": "Grasscutterがポート443をバインド(Linuxでは一般ユーザーは許可されていません)できるようにするための方法を指定します。\n利用可能な方法:\n「Capability」1024以下のポートをバインドする権限をJava仮想マシンに与えます。これは、そのJVM上で実行されている他のすべてのプログラムがこれらのポートをバインドできるようになることを意味します。\n「Root」Grasscutterをrootとして実行します。これは、GCサーバー、そのプラグイン、およびJVMが制限なくほとんど何でもできるようになることを意味します。\n「None」なし。この場合、GrasscutterのDispatchポートを変更する必要があります。"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
"migoto_name": "3Dmigoto",
|
||||
"reshade_name": "Reshade",
|
||||
"akebi": "Akebi実行ファイルを設定",
|
||||
"migoto": "3Dmigoto実行ファイルを設定",
|
||||
"reshade": "Reshadeインジェクターを設定"
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "서버 주소",
|
||||
"port_placeholder": "포트",
|
||||
"files_downloading": "파일 다운로드 중: ",
|
||||
"files_extracting": "파일 추출 중: "
|
||||
"files_extracting": "파일 추출 중: ",
|
||||
"game_path_notify": "게임 경로를 찾을 수 없습니다. 설정에서 설정하는 것을 잊지 마세요!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "활성",
|
||||
@@ -24,17 +25,23 @@
|
||||
"grasscutter_with_game": "게임에서 자동으로 그래스커터 실행",
|
||||
"language": "언어 선택",
|
||||
"background": "사용자 지정 배경 설정(링크 또는 이미지 파일)",
|
||||
"use_theme_background": "선택한 테마에서 제공하는 배경 사용",
|
||||
"theme": "테마 설정",
|
||||
"patch_rsa": "RSA 패치 자동 적용",
|
||||
"use_proxy": "내부 프록시 사용",
|
||||
"wipe_login": "로그인 캐시 지우기",
|
||||
"horny_mode": "Horny 모드",
|
||||
"auto_mongodb": "MongoDB 자동 시작",
|
||||
"un_elevated": "게임 비상승 실행(관리자 없음)"
|
||||
"un_elevated": "게임 비상승 실행(관리자 없음)",
|
||||
"redirect_more": "다른 MHY 게임도 리디렉션",
|
||||
"web_cache": "webCaches 폴더 삭제",
|
||||
"launch_args": "실행 인수",
|
||||
"offline_mode": "오프라인 모드",
|
||||
"fix_res": "로그인 시간 초과 수정"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "올인원 Grasscutter 다운로드",
|
||||
"grasscutter_fullquest": "퀘스트 올인원 다운로드",
|
||||
"grasscutter_fullquest": "5.0 올인원 다운로드",
|
||||
"grasscutter_stable_data": "안정적인 데이터 다운로드",
|
||||
"grasscutter_latest_data": "최신 데이터 다운로드",
|
||||
"grasscutter_stable_data_update": "안정적 데이터 업데이트",
|
||||
@@ -62,7 +69,8 @@
|
||||
"select_folder": "폴더 선택...",
|
||||
"download": "다운로드",
|
||||
"delete": "삭제",
|
||||
"install": "설치"
|
||||
"install": "설치",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "공지 사항",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "Servera Adrese...",
|
||||
"port_placeholder": "Ports...",
|
||||
"files_downloading": "Failu Lejupielāde: ",
|
||||
"files_extracting": "Failu Izvilkšana: "
|
||||
"files_extracting": "Failu Izvilkšana: ",
|
||||
"game_path_notify": "Spēles ceļš nav atrasts, atcerieties to iestatījumos!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Iespējots",
|
||||
@@ -22,17 +23,23 @@
|
||||
"grasscutter_with_game": "Automātiski palaidiet Grasscutter ar spēli",
|
||||
"language": "Izvēlēties valodu",
|
||||
"background": "Iestatīt pielāgotu fonu (saite vai attēla fails)",
|
||||
"use_theme_background": "Izmantojiet atlasītā motīva nodrošināto fonu",
|
||||
"theme": "Iestatīt tēmu",
|
||||
"patch_rsa": "Automātiski ielāpot RSA",
|
||||
"use_proxy": "Izmantot iekšējo starpniekserveri",
|
||||
"wipe_login": "Noslaucīt pieteikšanās kešatmiņu",
|
||||
"horny_mode": "Uzbudināts režīms",
|
||||
"auto_mongodb": "Automātiski startējiet MongoDB",
|
||||
"un_elevated": "Palaist spēli bez paaugstinājuma (bez administratora)"
|
||||
"un_elevated": "Palaist spēli bez paaugstinājuma (bez administratora)",
|
||||
"redirect_more": "Arī novirzīt citas MHY spēles",
|
||||
"web_cache": "Dzēsiet mapi WebCaches",
|
||||
"launch_args": "Palaišanas args",
|
||||
"offline_mode": "Bezsaistes režīms",
|
||||
"fix_res": "Fiksēt pieteikšanās laika"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Lejupielādējiet Grasscutter viss vienā",
|
||||
"grasscutter_fullquest": "Lejupielādēt questing viss vienā",
|
||||
"grasscutter_fullquest": "Lejupielādēt 5.0 viss vienā",
|
||||
"grasscutter_stable_data": "Lejupielādējiet Grasscutter stabilos datus",
|
||||
"grasscutter_latest_data": "Lejupielādējiet Grasscutter jaunākos datus",
|
||||
"grasscutter_stable_data_update": "Atjauniniet Grasscutter stabilos datus",
|
||||
@@ -58,7 +65,8 @@
|
||||
"select_file": "Izvēlēties failu vai mapu...",
|
||||
"select_folder": "Izvēlēties mapu...",
|
||||
"download": "Lejupielādēt",
|
||||
"delete": "Dzēst"
|
||||
"delete": "Dzēst",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Nesen kommitus",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "Server Address...",
|
||||
"port_placeholder": "Poort...",
|
||||
"files_downloading": "Bestanden Aan Downloaden: ",
|
||||
"files_extracting": "Bestanden Uitpakken: "
|
||||
"files_extracting": "Bestanden Uitpakken: ",
|
||||
"game_path_notify": "Spelpad niet gevonden, denk eraan dit in te stellen in instellingen!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Ingeschakeld",
|
||||
@@ -23,17 +24,23 @@
|
||||
"grasscutter_with_game": "Start Automatisch Grasscutter Met Spel",
|
||||
"language": "Selecteer Taal",
|
||||
"background": "Aangepaste Achtergrond Instellen (link of afbeeldingsbestand)",
|
||||
"use_theme_background": "Gebruik de achtergrond geleverd door het geselecteerde thema",
|
||||
"theme": "Thema instellen",
|
||||
"patch_rsa": "RSA Automatisch Bijwerken",
|
||||
"use_proxy": "Gebruik Interne Proxy",
|
||||
"wipe_login": "Login cache wissen",
|
||||
"horny_mode": "Geile modus",
|
||||
"auto_mongodb": "Start automatisch MongoDB",
|
||||
"un_elevated": "Voer het spel uit zonder hoogtevrees (geen admin)"
|
||||
"un_elevated": "Voer het spel uit zonder hoogtevrees (geen admin)",
|
||||
"redirect_more": "Richt ook andere MHY-spellen",
|
||||
"web_cache": "Verwijder de webCaches-map",
|
||||
"launch_args": "Args starten",
|
||||
"offline_mode": "Offline Modus",
|
||||
"fix_res": "Time-out inloggen verhelpen"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Grasscutter Alles-in-één Downloaden",
|
||||
"grasscutter_fullquest": "Alles-in-één zoeken downloaden",
|
||||
"grasscutter_fullquest": "Alles-in-één 5.0 downloaden",
|
||||
"grasscutter_stable_data": "Download Stabiele Gegevens Van Grasscutter",
|
||||
"grasscutter_latest_data": "Download De Nieuwste Gegevens Van Grasscutter",
|
||||
"grasscutter_stable_data_update": "Stabiele gegevens Van Grasscutter bijwerken",
|
||||
@@ -61,7 +68,8 @@
|
||||
"select_folder": "Select folder...",
|
||||
"download": "Download",
|
||||
"delete": "Verwijder",
|
||||
"install": "Install"
|
||||
"install": "Install",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Recente Opdrachten",
|
||||
|
||||
106
src-tauri/lang/pl.json
Normal file
106
src-tauri/lang/pl.json
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"lang_name": "Polski",
|
||||
"main": {
|
||||
"title": "Cultivation",
|
||||
"launch_button": "Uruchom",
|
||||
"gc_enable": "Połącz z Grasscutter",
|
||||
"https_enable": "Używaj HTTPS",
|
||||
"ip_placeholder": "Adres Serwera...",
|
||||
"port_placeholder": "Port...",
|
||||
"files_downloading": "Pobierane pliki: ",
|
||||
"files_extracting": "Wypakowywane pliki: ",
|
||||
"game_path_notify": "Ścieżka gry nie znaleziona. Pamiętaj by ustawić ją w ustawieniach!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Włączone",
|
||||
"disabled": "Wyłączone",
|
||||
"game_path": "Ustaw ścieżkę instalacji gry",
|
||||
"game_command": "Komenda uruchamiania gry",
|
||||
"game_executable": "Ustaw plik wykonywalny gry",
|
||||
"recover_rsa": "Awaryjne usunięcie patcha RSA",
|
||||
"grasscutter_jar": "Ustaw plik JAR Grasscuttera",
|
||||
"toggle_encryption": "Włącz szyfrowanie",
|
||||
"install_certificate": "Zainstaluj certyfikat proxy",
|
||||
"java_path": "Ustaw własną ścieżkę Javy",
|
||||
"grasscutter_with_game": "Automatycznie uruchom Grasscutter z grą",
|
||||
"language": "Wybierz Język",
|
||||
"background": "Ustaw własne tło (link lub plik graficzny)",
|
||||
"use_theme_background": "Użyj tła dostarczonego przez wybrany motyw",
|
||||
"theme": "Ustaw motyw",
|
||||
"patch_rsa": "Automatycznie patchuj RSA",
|
||||
"use_proxy": "Używaj wewnętrznego Proxy",
|
||||
"wipe_login": "Wyczyść pamięć podręczną logowania",
|
||||
"horny_mode": "Tryb 34",
|
||||
"auto_mongodb": "Automatycznie uruchamiaj MongoDB",
|
||||
"un_elevated": "Uruchamiaj grę bez uprawnień administratora/roota",
|
||||
"redirect_more": "Przekieruj też inne gry MHY",
|
||||
"check_aagl": "Więcej opcji znajdziesz w drugim launcherze",
|
||||
"grasscutter_elevation": "Sposób uruchomienia GC na ograniczonym porcie",
|
||||
"web_cache": "Usuń folder webCaches",
|
||||
"launch_args": "Argumenty uruchamiania",
|
||||
"offline_mode": "Tryb offline",
|
||||
"fix_res": "Napraw limit czasu logowania"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Pobierz Grasscutter (wszystko w jednym)",
|
||||
"grasscutter_fullquest": "Pobierz 5.0 (wszystko w jednym)",
|
||||
"grasscutter_stable_data": "Pobierz stabilne dane Grasscuttera",
|
||||
"grasscutter_latest_data": "Pobierz najnowsze dane Grasscuttera",
|
||||
"grasscutter_stable_data_update": "Zaaktualizuj stabilne dane Grasscuttera",
|
||||
"grasscutter_latest_data_update": "Zaaktualizuj najnowsze dane Grasscuttera",
|
||||
"grasscutter_unstable": "Pobierz Grasscutter Questing",
|
||||
"grasscutter_latest": "Pobierz Grasscutter Latest",
|
||||
"grasscutter_unstable_update": "Zaaktualizuj Grasscutter Questing",
|
||||
"grasscutter_latest_update": "Zaaktualizuj Grasscutter Latest",
|
||||
"resources": "Pobierz zasoby Grasscuttera",
|
||||
"game": "Pobierz grę",
|
||||
"aio_header": "Grupowe pobierania:",
|
||||
"individual_header": "Pojedyńcze pobierania:",
|
||||
"mods_header": "Mody:",
|
||||
"migoto": "Pobierz GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Pobieranie",
|
||||
"extracting": "Wypakowywanie",
|
||||
"error": "Błąd",
|
||||
"finished": "Zakończono",
|
||||
"stopped": "Zatrzymano"
|
||||
},
|
||||
"components": {
|
||||
"select_file": "Wybierz plik lub folder...",
|
||||
"select_folder": "Wybierz folder...",
|
||||
"download": "Pobierz",
|
||||
"delete": "Usuń",
|
||||
"install": "Zainstaluj",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Ostatnie Commity",
|
||||
"latest_version": "Najnowsza Wersja"
|
||||
},
|
||||
"help": {
|
||||
"port_help_text": "Upewnij się, że to jest port serwera Dispatch, a nie port serwera gry. To prawie zawsze '443'.",
|
||||
"game_help_text": "Nie potrzebujesz osobnej kopii gry, żeby używać Grasscuttera. To służy do deaktualizowania do wersji 2.6 albo jeśli nie masz zainstalowanej gry.",
|
||||
"gc_stable_jar": "Pobierz ostatni stabilny build Grasscuttera, który nie zawiera pliku jar i plików danych.",
|
||||
"gc_fullbuild": "Pobierz pełen build Grasscuttera, wliczając repo, plik jar i zasoby. Jest w pełni ustawiony i nie wymaga żadnych innych pobierań z tego menu.",
|
||||
"gc_dev_jar": "Pobierz najnowszy deweloperski build Grasscuttera, który nie zawiera pliku jar i plików danych.",
|
||||
"gc_stable_data": "Pobierz ostatnie stabilne pliki danych Grasscuttera, które nie zawierają pliku jar. Ta opcja jest przydatna do aktualizowania.",
|
||||
"gc_dev_data": "Pobierz najnowsze deweloperskie pliki danych Grasscuttera, które nie zawierają pliku jar. Ta opcja jest przydatna do aktualizowania.",
|
||||
"encryption": "To zazwyczaj powinno być wyłączone.",
|
||||
"resources": "One są potrzebne do uruchomienia serwera Grasscutter. Ten przycisk będzie szary, jeśli już będziesz miałx folder z zasobami",
|
||||
"emergency_rsa": "Jeżeli coś poszło nie tak, wymuś usunięcie patcha RSA.",
|
||||
"use_proxy": "Używaj wewnętrznego proxy Cultivation. To powinno być włączone, chyba że używasz czegoś jak np. Fiddler",
|
||||
"patch_rsa": "Patchuj i odpatchuj RSA gry automatycznie. Jeżeli nie grasz w starą lub nieoficjalną wersję (3.0 lub starszą), to powinno być włączone.",
|
||||
"add_delay": "Ustaw opóźnienie 3dmigoto loadera! \nTo powinno naprawić problemy z ładowaniem, ale doda małe opóźnienie do czasu ładowania 3dmigoto do gry. \nTeraz możecie uruchamiać grę z 3dmigoto.",
|
||||
"migoto": "Do importowania modeli z GameBanana",
|
||||
"grasscutter_elevation_help_text": "Metoda używana przez Grasscuttera do zbindowania portu 443 (co nie jest dozwolone dla zywkłych użytkowników w Linuxie)\nDostępne metody:\n Capability - daje wirtualnej maszynie Javy możliwość zbindowania portów poniżej 1024. To też pozwala wszystkim innym programom odpalonym na tej maszynie JVM zbindować te porty.\n Root - uruchamia GC jako root. To pozwala serwerowi GC, jego pluginom i maszynie JVM zrobić praktycznie wszystko, wliczając w to wysyłanie twoich nudesów do ABW, CBŚ, i innych trzyliterowych służb.\n None - czyli żadna metoda. Ta opcja wymaga zmiana portu Dispatch serwera GC."
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
"migoto_name": "Migoto",
|
||||
"reshade_name": "Reshade",
|
||||
"akebi": "Ustaw plik wykonywalny Akebi/Acrepi",
|
||||
"migoto": "Ustaw plik wykonywalny 3DMigoto",
|
||||
"reshade": "Ustaw Reshade Injector"
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "Endereço do Servidor...",
|
||||
"port_placeholder": "Porta...",
|
||||
"files_downloading": "Baixando Arquivos: ",
|
||||
"files_extracting": "Extraindo Arquivos: "
|
||||
"files_extracting": "Extraindo Arquivos: ",
|
||||
"game_path_notify": "Caminho do jogo não encontrado, lembre-se de defini-lo nas configurações!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Habilitado",
|
||||
@@ -24,17 +25,23 @@
|
||||
"grasscutter_with_game": "Iniciar automaticamente o Grasscutter com o Jogo",
|
||||
"language": "Selecionar Idioma",
|
||||
"background": "Definir Fundo Customizado (link ou arquivo de imagem)",
|
||||
"use_theme_background": "Use o plano de fundo fornecido pelo tema selecionado",
|
||||
"theme": "Definir Tema",
|
||||
"patch_rsa": "Automaticamente Corrigir RSA",
|
||||
"use_proxy": "Usar Proxy Interno",
|
||||
"wipe_login": "Limpar Cache de Login",
|
||||
"horny_mode": "Modo com tesão",
|
||||
"auto_mongodb": "Iniciar MongoDB Automaticamente",
|
||||
"un_elevated": "Executar o jogo não-elevated (sem admin)"
|
||||
"un_elevated": "Executar o jogo não-elevated (sem admin)",
|
||||
"redirect_more": "Também redirecionar outros jogos MHY",
|
||||
"web_cache": "Excluir pasta webCaches",
|
||||
"launch_args": "Argumentos de lançamento",
|
||||
"offline_mode": "Modo offline",
|
||||
"fix_res": "Corrigir o tempo limite de login"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Baixar o Grasscutter Tudo-em-Um",
|
||||
"grasscutter_fullquest": "Baixar de missões em um só lugar",
|
||||
"grasscutter_fullquest": "Baixar de 5.0 em um só lugar",
|
||||
"grasscutter_stable_data": "Baixar os Dados do Grasscutter Estável",
|
||||
"grasscutter_latest_data": "Baixar os Dados do Grasscutter Mais Recente",
|
||||
"grasscutter_stable_data_update": "Atualizar os Dados do Grasscutter Estável",
|
||||
@@ -62,7 +69,8 @@
|
||||
"select_folder": "Selecione a pasta...",
|
||||
"download": "Baixar",
|
||||
"delete": "Deletar",
|
||||
"install": "Instalar"
|
||||
"install": "Instalar",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Commits Recentes",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "Айпи адрес...",
|
||||
"port_placeholder": "Порт...",
|
||||
"files_downloading": "Файлов скачано: ",
|
||||
"files_extracting": "Извлечено файлов: "
|
||||
"files_extracting": "Извлечено файлов: ",
|
||||
"game_path_notify": "Путь к игре не найден, не забудьте установить его в настройках!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Включено",
|
||||
@@ -23,17 +24,23 @@
|
||||
"grasscutter_with_game": "Автоматически запускать Grasscutter вместе с игрой",
|
||||
"language": "Установить язык",
|
||||
"background": "Установить свой фон (ссылка или файл)",
|
||||
"use_theme_background": "Использовать фон из выбранной темы",
|
||||
"theme": "Установить тему",
|
||||
"patch_rsa": "Автоматическое исправление RSA",
|
||||
"use_proxy": "Использовать встроенный Прокси",
|
||||
"wipe_login": "Очистить кэш входа в систему",
|
||||
"horny_mode": "роговой режим",
|
||||
"auto_mongodb": "Автоматически запускать MongoDB",
|
||||
"un_elevated": "Запустите игру в неэлегантном режиме (без администратора)"
|
||||
"un_elevated": "Запустите игру в неэлегантном режиме (без администратора)",
|
||||
"redirect_more": "Также перенаправьте другие игры MHY",
|
||||
"web_cache": "Удалить папку webCaches",
|
||||
"launch_args": "Параметры запуска",
|
||||
"offline_mode": "Автономный режим",
|
||||
"fix_res": "Исправить таймаут входа в систему"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Скачать все в одном Grasscutter",
|
||||
"grasscutter_fullquest": "Скачать квесты все в одном",
|
||||
"grasscutter_fullquest": "Скачать 5.0 все в одном",
|
||||
"grasscutter_stable_data": "Скачать стабильные данные Grasscutter",
|
||||
"grasscutter_latest_data": "Скачать последние данные Grasscutter",
|
||||
"grasscutter_stable_data_update": "Обновить стабильные данные Grasscutter",
|
||||
@@ -61,7 +68,8 @@
|
||||
"select_folder": "Выберите папку...",
|
||||
"download": "Скачать",
|
||||
"delete": "Удалить",
|
||||
"install": "Установить"
|
||||
"install": "Установить",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Последние коммиты",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"ip_placeholder": "Địa chỉ máy chủ...",
|
||||
"port_placeholder": "Cổng...",
|
||||
"files_downloading": "Đang tải tập tin: ",
|
||||
"files_extracting": "Đang giải nén tập tin: "
|
||||
"files_extracting": "Đang giải nén tập tin: ",
|
||||
"game_path_notify": "Không tìm thấy đường dẫn trò chơi, hãy nhớ đặt nó trong cài đặt!"
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Bật",
|
||||
@@ -24,17 +25,23 @@
|
||||
"grasscutter_with_game": "Tự động chạy Grasscutter cùng với game",
|
||||
"language": "Ngôn ngữ",
|
||||
"background": "Hình nền tùy chỉnh (liên kết hoặc tập tin hình ảnh)",
|
||||
"use_theme_background": "Sử dụng nền được cung cấp bởi chủ đề đã chọn",
|
||||
"theme": "Giao diện",
|
||||
"patch_rsa": "Tự động vá RSA",
|
||||
"use_proxy": "Sử dụng proxy nội bộ",
|
||||
"wipe_login": "Tẩy sạch cache đăng nhập",
|
||||
"horny_mode": "Chế độ hứng tình",
|
||||
"auto_mongodb": "Tự động khởi động MongoDB",
|
||||
"un_elevated": "Chạy trò chơi không nâng cao (không có quản trị viên)"
|
||||
"un_elevated": "Chạy trò chơi không nâng cao (không có quản trị viên)",
|
||||
"redirect_more": "Đồng thời chuyển hướng các trò chơi MHY khác",
|
||||
"web_cache": "Xóa thư mục webCaches",
|
||||
"launch_args": "Khởi chạy đối số",
|
||||
"offline_mode": "Chế độ ngoại tuyến",
|
||||
"fix_res": "Sửa lỗi hết thời gian đăng nhập"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Tải Grasscutter tất cả trong một",
|
||||
"grasscutter_fullquest": "Tải xuống truy vấn tất cả trong một",
|
||||
"grasscutter_fullquest": "Tải 5.0 tất cả trong một",
|
||||
"grasscutter_stable_data": "Tải dữ liệu Grasscutter bản ổn định",
|
||||
"grasscutter_latest_data": "Tải dữ liệu Grasscutter bản mới nhất",
|
||||
"grasscutter_stable_data_update": "Cập nhật dữ liệu Grasscutter bản ổn định",
|
||||
@@ -62,7 +69,8 @@
|
||||
"select_folder": "Chọn thư mục...",
|
||||
"download": "Tải",
|
||||
"delete": "Xóa bỏ",
|
||||
"install": "Cài"
|
||||
"install": "Cài",
|
||||
"fix": "Fix"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Thay Đổi Gần Đây",
|
||||
|
||||
BIN
src-tauri/patch/46version.dll
Normal file
BIN
src-tauri/patch/46version.dll
Normal file
Binary file not shown.
BIN
src-tauri/patch/47version.dll
Normal file
BIN
src-tauri/patch/47version.dll
Normal file
Binary file not shown.
BIN
src-tauri/patch/50version.dll
Normal file
BIN
src-tauri/patch/50version.dll
Normal file
Binary file not shown.
@@ -18,8 +18,5 @@ pub fn reopen_as_admin() {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn reopen_as_admin() {}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn reopen_as_admin() {}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||
use std::string::String;
|
||||
|
||||
// Config may not exist, or may be old, so it's okay if these are optional
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct Configuration {
|
||||
pub toggle_grasscutter: Option<bool>,
|
||||
pub game_install_path: Option<String>,
|
||||
@@ -16,6 +16,7 @@ pub struct Configuration {
|
||||
pub last_port: Option<String>,
|
||||
pub language: Option<String>,
|
||||
pub custom_background: Option<String>,
|
||||
pub use_theme_background: Option<bool>,
|
||||
pub cert_generated: Option<bool>,
|
||||
pub theme: Option<String>,
|
||||
pub https_enabled: Option<bool>,
|
||||
@@ -26,6 +27,9 @@ pub struct Configuration {
|
||||
pub horny_mode: Option<bool>,
|
||||
pub auto_mongodb: Option<bool>,
|
||||
pub un_elevated: Option<bool>,
|
||||
pub redirect_more: Option<bool>,
|
||||
pub launch_args: Option<String>,
|
||||
pub offline_mode: Option<bool>,
|
||||
}
|
||||
|
||||
pub fn config_path() -> PathBuf {
|
||||
@@ -39,7 +43,7 @@ pub fn config_path() -> PathBuf {
|
||||
pub fn get_config() -> Configuration {
|
||||
let path = config_path();
|
||||
let config = std::fs::read_to_string(path).unwrap_or("{}".to_string());
|
||||
let config: Configuration = serde_json::from_str(&config).unwrap();
|
||||
let config: Configuration = serde_json::from_str(&config).unwrap_or_default();
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use file_diff::diff;
|
||||
use std::fs;
|
||||
use std::io::{Read, Write};
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[tauri::command]
|
||||
@@ -57,6 +57,11 @@ pub fn are_files_identical(path1: &str, path2: &str) -> bool {
|
||||
diff(path1, path2)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn does_file_exist(path1: &str) -> bool {
|
||||
fs::metadata(path1).is_ok()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn copy_file(path: String, new_path: String) -> bool {
|
||||
let filename = &path.split('/').last().unwrap();
|
||||
@@ -127,22 +132,46 @@ pub fn delete_file(path: String) -> bool {
|
||||
#[tauri::command]
|
||||
pub fn read_file(path: String) -> String {
|
||||
let path_buf = PathBuf::from(&path);
|
||||
|
||||
let mut file = match fs::File::open(path_buf) {
|
||||
Ok(file) => file,
|
||||
Err(e) => {
|
||||
if path.contains("config") {
|
||||
// Server.ts won't print the error so handle the message here for the user
|
||||
println!("Server config not found or invalid. Be sure to run the server at least once to generate it before making edits.");
|
||||
} else {
|
||||
println!("Failed to open file: {}", e);
|
||||
}
|
||||
return String::new(); // Send back error for handling by the caller
|
||||
}
|
||||
};
|
||||
println!("Debug: Reading file of path {}", path.clone(),);
|
||||
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
|
||||
// Version data is 3 bytes long, 3 bytes in
|
||||
let ext = path_buf.extension().unwrap();
|
||||
if ext.eq("bytes") {
|
||||
let offset_bytes = 3;
|
||||
let num_bytes = 3;
|
||||
|
||||
let mut byte_file = match std::fs::File::open(path_buf) {
|
||||
Ok(byte_file) => byte_file,
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
return String::new();
|
||||
}
|
||||
};
|
||||
byte_file
|
||||
.seek(SeekFrom::Start(offset_bytes))
|
||||
.unwrap_or_default();
|
||||
let mut buf = vec![0; num_bytes];
|
||||
byte_file.read_exact(&mut buf).unwrap_or_default();
|
||||
|
||||
contents = String::from_utf8_lossy(&buf).to_string();
|
||||
} else {
|
||||
let mut file = match fs::File::open(path_buf) {
|
||||
Ok(file) => file,
|
||||
Err(e) => {
|
||||
if path.contains("config") {
|
||||
// Server.ts won't print the error so handle the message here for the user
|
||||
println!("Server config not found or invalid. Be sure to run the server at least once to generate it before making edits.");
|
||||
} else {
|
||||
println!("Failed to open file: {}", e);
|
||||
}
|
||||
return String::new(); // Send back error for handling by the caller
|
||||
}
|
||||
};
|
||||
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
}
|
||||
|
||||
contents
|
||||
}
|
||||
|
||||
@@ -28,12 +28,7 @@ pub async fn get_languages() -> std::collections::HashMap<String, String> {
|
||||
for entry in lang_files {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
let filename = path
|
||||
.file_name()
|
||||
.unwrap_or_else(|| panic!("Failed to get filename from path: {:?}", path))
|
||||
.to_str()
|
||||
.unwrap_or_else(|| panic!("Failed to convert filename to string: {:?}", path))
|
||||
.to_string();
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let content = match std::fs::read_to_string(&path) {
|
||||
Ok(x) => x,
|
||||
|
||||
@@ -11,14 +11,22 @@ use proxy::set_proxy_addr;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
use system_helpers::is_elevated;
|
||||
use tauri::api::path::data_dir;
|
||||
use tauri::async_runtime::block_on;
|
||||
|
||||
use std::thread;
|
||||
use sysinfo::{Pid, ProcessExt, System, SystemExt};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use crate::admin::reopen_as_admin;
|
||||
#[cfg(target_os = "windows")]
|
||||
use system_helpers::is_elevated;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::{
|
||||
thread::{sleep, JoinHandle},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
mod admin;
|
||||
mod config;
|
||||
@@ -37,6 +45,9 @@ static WATCH_GAME_PROCESS: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new(String:
|
||||
static WATCH_GRASSCUTTER_PROCESS: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new(String::new()));
|
||||
static GC_PID: std::sync::Mutex<usize> = Mutex::new(696969);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub static AAGL_THREAD: Lazy<Mutex<Option<JoinHandle<()>>>> = Lazy::new(|| Mutex::new(None));
|
||||
|
||||
fn try_flush() {
|
||||
std::io::stdout().flush().unwrap_or(())
|
||||
}
|
||||
@@ -49,6 +60,7 @@ async fn parse_args(inp: &Vec<String>) -> Result<Args, ArgsError> {
|
||||
args.flag("h", "help", "Print various CLI args");
|
||||
args.flag("p", "proxy", "Start the proxy server");
|
||||
args.flag("G", "launch-game", "Launch the game");
|
||||
args.flag("o", "other-redirects", "Redirect other certain anime games");
|
||||
args.flag(
|
||||
"A",
|
||||
"no-admin",
|
||||
@@ -96,15 +108,15 @@ async fn parse_args(inp: &Vec<String>) -> Result<Args, ArgsError> {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// Patch if needed
|
||||
if args.value_of("patch")? {
|
||||
patch::patch_game(false, 0.to_string()).await;
|
||||
}
|
||||
|
||||
if args.value_of("launch-game")? {
|
||||
let game_path = config.game_install_path;
|
||||
let game_args: String = args.value_of("game-args").unwrap_or_default();
|
||||
|
||||
// Patch if needed
|
||||
if args.value_of("patch")? {
|
||||
patch::patch_game().await;
|
||||
}
|
||||
|
||||
if game_path.is_some() {
|
||||
if args.value_of("non-elevated-game")? {
|
||||
system_helpers::run_un_elevated(game_path.unwrap(), Some(game_args))
|
||||
@@ -142,6 +154,10 @@ async fn parse_args(inp: &Vec<String>) -> Result<Args, ArgsError> {
|
||||
pathbuf.push("cultivation");
|
||||
pathbuf.push("ca");
|
||||
|
||||
if args.value_of("other-redirects")? {
|
||||
// proxy::set_redirect_more(); // Unused
|
||||
}
|
||||
|
||||
connect(8035, pathbuf.to_str().unwrap().to_string()).await;
|
||||
}
|
||||
|
||||
@@ -152,6 +168,7 @@ fn main() -> Result<(), ArgsError> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let parsed_args = block_on(parse_args(&args)).unwrap();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
if !is_elevated() && !parsed_args.value_of("no-admin")? {
|
||||
println!("===============================================================================");
|
||||
println!("You running as a non-elevated user. Some stuff will almost definitely not work.");
|
||||
@@ -197,14 +214,18 @@ fn main() -> Result<(), ArgsError> {
|
||||
system_helpers::service_status,
|
||||
system_helpers::stop_service,
|
||||
system_helpers::run_jar,
|
||||
system_helpers::run_jar_root,
|
||||
system_helpers::open_in_browser,
|
||||
system_helpers::install_location,
|
||||
system_helpers::is_elevated,
|
||||
system_helpers::set_migoto_target,
|
||||
system_helpers::set_migoto_delay,
|
||||
system_helpers::wipe_registry,
|
||||
system_helpers::get_platform,
|
||||
system_helpers::run_un_elevated,
|
||||
system_helpers::jvm_add_cap,
|
||||
system_helpers::jvm_remove_cap,
|
||||
patch::patch_game,
|
||||
patch::unpatch_game,
|
||||
proxy::set_proxy_addr,
|
||||
proxy::generate_ca_files,
|
||||
release::get_latest_release,
|
||||
@@ -220,6 +241,7 @@ fn main() -> Result<(), ArgsError> {
|
||||
file_helpers::are_files_identical,
|
||||
file_helpers::read_file,
|
||||
file_helpers::write_file,
|
||||
file_helpers::does_file_exist,
|
||||
downloader::download_file,
|
||||
downloader::stop_download,
|
||||
lang::get_lang,
|
||||
@@ -230,12 +252,11 @@ fn main() -> Result<(), ArgsError> {
|
||||
gamebanana::list_submissions,
|
||||
gamebanana::list_mods
|
||||
])
|
||||
.on_window_event(|event| match event.event() {
|
||||
tauri::WindowEvent::CloseRequested { api, .. } => {
|
||||
.on_window_event(|event| {
|
||||
if let tauri::WindowEvent::CloseRequested { .. } = event.event() {
|
||||
// Ensure all proxy stuff is handled
|
||||
disconnect();
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
@@ -262,6 +283,7 @@ fn is_game_running() -> bool {
|
||||
!proc.is_empty()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[tauri::command]
|
||||
fn enable_process_watcher(window: tauri::Window, process: String) {
|
||||
*WATCH_GAME_PROCESS.lock().unwrap() = process;
|
||||
@@ -274,7 +296,7 @@ fn enable_process_watcher(window: tauri::Window, process: String) {
|
||||
|
||||
thread::spawn(move || {
|
||||
// Initial sleep for 8 seconds, since running 20 different injectors or whatever can take a while
|
||||
std::thread::sleep(std::time::Duration::from_secs(10));
|
||||
std::thread::sleep(std::time::Duration::from_secs(60));
|
||||
|
||||
let mut system = System::new_all();
|
||||
|
||||
@@ -307,6 +329,41 @@ fn enable_process_watcher(window: tauri::Window, process: String) {
|
||||
});
|
||||
}
|
||||
|
||||
// The library takes care of it
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
fn enable_process_watcher(window: tauri::Window, process: String) {
|
||||
drop(process);
|
||||
thread::spawn(move || {
|
||||
let end_time = Instant::now() + Duration::from_secs(90);
|
||||
let game_thread = loop {
|
||||
let mut lock = AAGL_THREAD.lock().unwrap();
|
||||
if lock.is_some() {
|
||||
break lock.take().unwrap();
|
||||
}
|
||||
drop(lock);
|
||||
if end_time < Instant::now() {
|
||||
// If more than 60 seconds pass something has gone wrong
|
||||
println!("Waiting for game thread timed out");
|
||||
return;
|
||||
}
|
||||
// Otherwhise wait in order to not use too many CPU cycles
|
||||
sleep(Duration::from_millis(128));
|
||||
};
|
||||
game_thread.join().unwrap();
|
||||
println!("Game closed");
|
||||
|
||||
*WATCH_GAME_PROCESS.lock().unwrap() = "".to_string();
|
||||
disconnect();
|
||||
|
||||
window.emit("game_closed", &()).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[tauri::command]
|
||||
fn enable_process_watcher(window: tauri::Window, process: String) {}
|
||||
|
||||
#[tauri::command]
|
||||
fn is_grasscutter_running() -> bool {
|
||||
// Grab the grasscutter process name
|
||||
@@ -356,7 +413,6 @@ fn restart_grasscutter(_window: tauri::Window) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
fn enable_grasscutter_watcher(window: tauri::Window, process: String) {
|
||||
let grasscutter_name = process.clone();
|
||||
@@ -417,13 +473,6 @@ fn enable_grasscutter_watcher(window: tauri::Window, process: String) {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tauri::command]
|
||||
fn enable_grasscutter_watcher(_window: tauri::Window, _process: String) {
|
||||
let gc_pid = Pid::from(696969);
|
||||
*GC_PID.lock().unwrap() = gc_pid.into();
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn connect(port: u16, certificate_path: String) {
|
||||
// Log message to console.
|
||||
|
||||
@@ -3,8 +3,137 @@ use crate::file_helpers;
|
||||
use crate::system_helpers;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub async fn patch_game() -> bool {
|
||||
let patch_path = PathBuf::from(system_helpers::install_location()).join("patch/version.dll");
|
||||
#[cfg(target_os = "linux")]
|
||||
use once_cell::sync::Lazy;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(target_os = "linux")]
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
static PATCH_STATE: Lazy<Arc<Mutex<Option<PatchState>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum PatchState {
|
||||
NotExist,
|
||||
Same,
|
||||
BakNotExist,
|
||||
BakExist,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use PatchState::*;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl PatchState {
|
||||
fn to_wta(self) -> WhatToUnpach {
|
||||
let (mhyp_renamed, game_was_patched) = match self {
|
||||
NotExist => (false, true),
|
||||
Same => (false, true),
|
||||
BakNotExist => (true, true),
|
||||
BakExist => (false, false),
|
||||
};
|
||||
WhatToUnpach {
|
||||
mhyp_renamed,
|
||||
game_was_patched,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[derive(Debug, Clone)]
|
||||
struct WhatToUnpach {
|
||||
mhyp_renamed: bool,
|
||||
game_was_patched: bool,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
pub async fn patch_game(newer_game: bool, version: String) -> bool {
|
||||
let mut patch_path;
|
||||
// Altpatch first - Now using as hoyonet switch
|
||||
if newer_game {
|
||||
let alt_patch_path = PathBuf::from(system_helpers::install_location()).join("altpatch");
|
||||
|
||||
// Should handle overwriting backup with new version backup later
|
||||
let backup_path = PathBuf::from(system_helpers::install_location())
|
||||
.join("altpatch/original-mihoyonet.dll")
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
let backup_exists = file_helpers::does_file_exist(&backup_path);
|
||||
|
||||
if !backup_exists {
|
||||
let backup = file_helpers::copy_file_with_new_name(
|
||||
get_game_rsa_path().await.unwrap()
|
||||
+ &String::from("/GenshinImpact_Data/Plugins/mihoyonet.dll"),
|
||||
alt_patch_path.clone().to_str().unwrap().to_string(),
|
||||
String::from("original-mihoyonet.dll"),
|
||||
);
|
||||
|
||||
if !backup {
|
||||
println!("Unable to backup file!");
|
||||
}
|
||||
}
|
||||
|
||||
patch_path = PathBuf::from(system_helpers::install_location()).join("altpatch/mihoyonet.dll");
|
||||
// Copy the other part of patch to game files
|
||||
let alt_replaced = file_helpers::copy_file_with_new_name(
|
||||
patch_path.clone().to_str().unwrap().to_string(),
|
||||
get_game_rsa_path().await.unwrap() + &String::from("/GenshinImpact_Data/Plugins"),
|
||||
String::from("mihoyonet.dll"),
|
||||
);
|
||||
|
||||
if !alt_replaced {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*** For replacing old backup file with new one, for example when version changes
|
||||
* Currently replaces when it shouldn't. Will figure it out when it matters
|
||||
* ***/
|
||||
// else {
|
||||
// // Check if game file matches backup
|
||||
// let matching_alt_backup = file_helpers::are_files_identical(
|
||||
// &backup_path.clone(),
|
||||
// PathBuf::from(get_game_rsa_path().await.unwrap())
|
||||
// .join("/GenshinImpact_Data/Plugins/mihoyonet.dll")
|
||||
// .to_str()
|
||||
// .unwrap(),
|
||||
// );
|
||||
|
||||
// let is_alt_patched = file_helpers::are_files_identical(
|
||||
// PathBuf::from(system_helpers::install_location()).join("altpatch/mihoyonet.dll").to_str().unwrap(),
|
||||
// PathBuf::from(get_game_rsa_path().await.unwrap())
|
||||
// .join("/GenshinImpact_Data/Plugins/mihoyonet.dll")
|
||||
// .to_str()
|
||||
// .unwrap(),
|
||||
// );
|
||||
|
||||
// // Check if already alt patched
|
||||
// if !matching_alt_backup {
|
||||
// // Copy new backup if it is not patched
|
||||
// if !is_alt_patched {
|
||||
// file_helpers::copy_file_with_new_name(
|
||||
// get_game_rsa_path().await.unwrap() + &String::from("/GenshinImpact_Data/Plugins/mihoyonet.dll"),
|
||||
// alt_patch_path.clone().to_str().unwrap().to_string(),
|
||||
// String::from("original-mihoyonet.dll"),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// Standard patch
|
||||
patch_path = PathBuf::from(system_helpers::install_location()).join("patch/version.dll");
|
||||
|
||||
let i_ver = version.parse::<i32>().unwrap();
|
||||
|
||||
// For newer than 4.0, use specific patch files
|
||||
if i_ver > 40 {
|
||||
let patch_version = format!("patch/{version}version.dll");
|
||||
patch_path = PathBuf::from(system_helpers::install_location()).join(patch_version);
|
||||
}
|
||||
|
||||
// Are we already patched with mhypbase? If so, that's fine, just continue as normal
|
||||
let game_is_patched = file_helpers::are_files_identical(
|
||||
@@ -23,6 +152,17 @@ pub async fn patch_game() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For 5.0 and up
|
||||
if i_ver > 49 {
|
||||
let replaced50 = file_helpers::copy_file_with_new_name(
|
||||
patch_path.clone().to_str().unwrap().to_string(),
|
||||
get_game_rsa_path().await.unwrap(),
|
||||
String::from("Astrolabe.dll"),
|
||||
);
|
||||
|
||||
return replaced50;
|
||||
}
|
||||
|
||||
// Copy the patch to game files
|
||||
let replaced = file_helpers::copy_file_with_new_name(
|
||||
patch_path.clone().to_str().unwrap().to_string(),
|
||||
@@ -37,6 +177,82 @@ pub async fn patch_game() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub async fn patch_game(_newer_game: bool, _version: String) -> bool {
|
||||
let mut patch_state_mutex = PATCH_STATE.lock().await;
|
||||
if patch_state_mutex.is_some() {
|
||||
println!("Game already patched!");
|
||||
}
|
||||
|
||||
let patch_path = PathBuf::from(system_helpers::install_location()).join("patch/version.dll");
|
||||
let game_mhyp = PathBuf::from(get_game_rsa_path().await.unwrap()).join("mhypbase.dll");
|
||||
let game_mhyp_bak = PathBuf::from(get_game_rsa_path().await.unwrap()).join("mhypbase.dll.bak");
|
||||
|
||||
let patch_state = if !game_mhyp.exists() {
|
||||
NotExist
|
||||
} else if file_helpers::are_files_identical(
|
||||
patch_path.to_str().unwrap(),
|
||||
game_mhyp.to_str().unwrap(),
|
||||
) {
|
||||
Same
|
||||
} else if !game_mhyp_bak.exists() {
|
||||
BakNotExist
|
||||
} else {
|
||||
BakExist
|
||||
};
|
||||
|
||||
match patch_state {
|
||||
NotExist => {
|
||||
// No renaming needed.
|
||||
// Copy version.dll as mhypbase.dll
|
||||
file_helpers::copy_file_with_new_name(
|
||||
patch_path.clone().to_str().unwrap().to_string(),
|
||||
get_game_rsa_path().await.unwrap(),
|
||||
String::from("mhypbase.dll"),
|
||||
);
|
||||
}
|
||||
Same => {
|
||||
// No renaming needed.
|
||||
// No copying needed.
|
||||
println!("The game is already patched.");
|
||||
}
|
||||
BakNotExist => {
|
||||
// The current mhypbase.dll is most likely the original
|
||||
|
||||
// Rename mhypbase.dll to mhypbase.dll.bak
|
||||
file_helpers::rename(
|
||||
game_mhyp.to_str().unwrap().to_string(),
|
||||
game_mhyp_bak
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
);
|
||||
// Copy version.dll as mhypbase.dll
|
||||
file_helpers::copy_file_with_new_name(
|
||||
patch_path.clone().to_str().unwrap().to_string(),
|
||||
get_game_rsa_path().await.unwrap(),
|
||||
String::from("mhypbase.dll"),
|
||||
);
|
||||
}
|
||||
BakExist => {
|
||||
// Can't rename. mhypbase.dll.bak already exists.
|
||||
// Can't patch. mhypbase.dll exists.
|
||||
// This SHOULD NOT HAPPEN
|
||||
println!("The game directory contains a mhypbase.dll, but it's different from the patch.");
|
||||
println!("Make sure you have the original mhypbase.dll.");
|
||||
println!("Delete any other copy, and place the original copy in the game directory with the original name.");
|
||||
}
|
||||
}
|
||||
|
||||
patch_state_mutex.replace(patch_state);
|
||||
patch_state.to_wta().game_was_patched
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
pub async fn unpatch_game() -> bool {
|
||||
// Just delete patch since it's not replacing any existing file
|
||||
let deleted = file_helpers::delete_file(
|
||||
@@ -47,9 +263,84 @@ pub async fn unpatch_game() -> bool {
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
file_helpers::delete_file(
|
||||
PathBuf::from(get_game_rsa_path().await.unwrap())
|
||||
.join("Astrolabe.dll")
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
let core_patch_path = PathBuf::from(system_helpers::install_location());
|
||||
let patch_path = core_patch_path.clone().join("altpatch/mihoyonet.dll");
|
||||
let backup_path = core_patch_path
|
||||
.clone()
|
||||
.join("altpatch/original-mihoyonet.dll");
|
||||
|
||||
let is_alt_patched = file_helpers::are_files_identical(
|
||||
patch_path.clone().to_str().unwrap(),
|
||||
PathBuf::from(get_game_rsa_path().await.unwrap())
|
||||
.join("GenshinImpact_Data/Plugins/mihoyonet.dll")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
if is_alt_patched {
|
||||
file_helpers::copy_file_with_new_name(
|
||||
backup_path.clone().to_str().unwrap().to_string(),
|
||||
get_game_rsa_path().await.unwrap() + &String::from("/GenshinImpact_Data/Plugins"),
|
||||
String::from("mihoyonet.dll"),
|
||||
);
|
||||
}
|
||||
|
||||
deleted
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub async fn unpatch_game() -> bool {
|
||||
// TODO: Prevent the launcher from unpatching the game two times
|
||||
// This might be related to redirecting calls from the ts version of
|
||||
// unpatchGame to the rust version
|
||||
let mut patch_state_mutex = PATCH_STATE.lock().await;
|
||||
let patch_state = patch_state_mutex.take();
|
||||
if patch_state.is_none() {
|
||||
println!("Game not patched!");
|
||||
// NOTE: true is returned since otherwhise the launcher thinks unpatching failed
|
||||
// NOTE: actually it should be false since delete_file always returns false
|
||||
return false;
|
||||
}
|
||||
let patch_state = patch_state.unwrap();
|
||||
|
||||
let game_mhyp = PathBuf::from(get_game_rsa_path().await.unwrap()).join("mhypbase.dll");
|
||||
let game_mhyp_bak = PathBuf::from(get_game_rsa_path().await.unwrap()).join("mhypbase.dll.bak");
|
||||
|
||||
let WhatToUnpach {
|
||||
mhyp_renamed,
|
||||
game_was_patched,
|
||||
} = patch_state.to_wta();
|
||||
|
||||
// If the current mhypbase.dll is the patch, then delete it.
|
||||
let deleted = if game_was_patched {
|
||||
file_helpers::delete_file(game_mhyp.to_str().unwrap().to_string());
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// If we renamed the original mhypbase.dll to mhypbase.dll.bak
|
||||
// rename mhypbase.dll.bak back to mhypbase.dll
|
||||
if mhyp_renamed {
|
||||
file_helpers::rename(
|
||||
game_mhyp_bak.to_str().unwrap().to_string(),
|
||||
game_mhyp.to_str().unwrap().to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
// NOTE: As mentioned in a note above, false should be returned if the function succeded
|
||||
// and true if it failed
|
||||
!deleted
|
||||
}
|
||||
|
||||
pub async fn get_game_rsa_path() -> Option<String> {
|
||||
let config = config::get_config();
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
* https://github.com/omjadas/hudsucker/blob/main/examples/log.rs
|
||||
*/
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::system_helpers::run_command;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{path::PathBuf, str::FromStr, sync::Mutex};
|
||||
|
||||
@@ -27,6 +24,13 @@ use tauri::{api::path::data_dir, http::Uri};
|
||||
#[cfg(windows)]
|
||||
use registry::{Data, Hive, Security};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::system_helpers::{AsRoot, SpawnItsFineReally};
|
||||
#[cfg(target_os = "linux")]
|
||||
use anime_launcher_sdk::{config::ConfigExt, genshin::config::Config};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::{fs::File, io::Write, process::Command};
|
||||
|
||||
async fn shutdown_signal() {
|
||||
tokio::signal::ctrl_c()
|
||||
.await
|
||||
@@ -35,7 +39,6 @@ async fn shutdown_signal() {
|
||||
|
||||
// Global ver for getting server address.
|
||||
static SERVER: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new("http://localhost:443".to_string()));
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ProxyHandler;
|
||||
|
||||
@@ -60,7 +63,16 @@ impl HttpHandler for ProxyHandler {
|
||||
) -> RequestOrResponse {
|
||||
let uri = req.uri().to_string();
|
||||
|
||||
if uri.contains("hoyoverse.com") || uri.contains("mihoyo.com") || uri.contains("yuanshen.com") {
|
||||
if uri.contains("hoyoverse.com")
|
||||
|| uri.contains("mihoyo.com")
|
||||
|| uri.contains("yuanshen.com")
|
||||
|| uri.ends_with(".yuanshen.com:12401")
|
||||
|| uri.contains("starrails.com")
|
||||
|| uri.contains("bhsr.com")
|
||||
|| uri.contains("bh3.com")
|
||||
|| uri.contains("honkaiimpact3.com")
|
||||
|| uri.contains("zenlesszonezero.com")
|
||||
{
|
||||
// Handle CONNECTs
|
||||
if req.method().as_str() == "CONNECT" {
|
||||
let builder = Response::builder()
|
||||
@@ -95,7 +107,14 @@ impl HttpHandler for ProxyHandler {
|
||||
async fn should_intercept(&mut self, _ctx: &HttpContext, _req: &Request<Body>) -> bool {
|
||||
let uri = _req.uri().to_string();
|
||||
|
||||
uri.contains("hoyoverse.com") || uri.contains("mihoyo.com") || uri.contains("yuanshen.com")
|
||||
uri.contains("hoyoverse.com")
|
||||
|| uri.contains("mihoyo.com")
|
||||
|| uri.contains("yuanshen.com")
|
||||
|| uri.contains("starrails.com")
|
||||
|| uri.contains("bhsr.com")
|
||||
|| uri.contains("bh3.com")
|
||||
|| uri.contains("honkaiimpact3.com")
|
||||
|| uri.contains("zenlesszonezero.com")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,27 +207,26 @@ pub fn connect_to_proxy(proxy_port: u16) {
|
||||
println!("Connected to the proxy.");
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn connect_to_proxy(proxy_port: u16) {
|
||||
// Edit /etc/environment to set $http_proxy and $https_proxy
|
||||
let mut env_file = match fs::read_to_string("/etc/environment") {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
println!("Error opening /etc/environment: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Append the proxy configuration.
|
||||
// We will not remove the current proxy config if it exists, so we can just remove these last lines when we disconnect
|
||||
env_file += format!("\nhttps_proxy=127.0.0.1:{}", proxy_port).as_str();
|
||||
env_file += format!("\nhttp_proxy=127.0.0.1:{}", proxy_port).as_str();
|
||||
|
||||
// Save
|
||||
fs::write("/etc/environment", env_file).unwrap();
|
||||
let mut config = Config::get().unwrap();
|
||||
let proxy_addr = format!("127.0.0.1:{}", proxy_port);
|
||||
if !config.game.environment.contains_key("http_proxy") {
|
||||
config
|
||||
.game
|
||||
.environment
|
||||
.insert("http_proxy".to_string(), proxy_addr.clone());
|
||||
}
|
||||
if !config.game.environment.contains_key("https_proxy") {
|
||||
config
|
||||
.game
|
||||
.environment
|
||||
.insert("https_proxy".to_string(), proxy_addr);
|
||||
}
|
||||
Config::update(config);
|
||||
}
|
||||
|
||||
#[cfg(target_od = "macos")]
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn connect_to_proxy(_proxy_port: u16) {
|
||||
println!("No Mac support yet. Someone mail me a Macbook and I will do it B)")
|
||||
}
|
||||
@@ -234,21 +252,14 @@ pub fn disconnect_from_proxy() {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn disconnect_from_proxy() {
|
||||
println!("Re-writing environment variables");
|
||||
|
||||
let regexp = regex::Regex::new(
|
||||
// This has to be specific as possible or we risk fuckin up their environment LOL
|
||||
r"(https|http)_proxy=.*127.0.0.1:.*",
|
||||
)
|
||||
.unwrap();
|
||||
let environment = &fs::read_to_string("/etc/environment").expect("Failed to open environment");
|
||||
|
||||
let new_environment = regexp.replace_all(environment, "").to_string();
|
||||
|
||||
// Write new environment
|
||||
fs::write("/etc/environment", new_environment.trim_end()).expect(
|
||||
"Could not write environment, remove proxy declarations manually if they are still set",
|
||||
);
|
||||
let mut config = Config::get().unwrap();
|
||||
if config.game.environment.contains_key("http_proxy") {
|
||||
config.game.environment.remove("http_proxy");
|
||||
}
|
||||
if config.game.environment.contains_key("https_proxy") {
|
||||
config.game.environment.remove("https_proxy");
|
||||
}
|
||||
Config::update(config);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -354,18 +365,72 @@ pub fn install_ca_files(cert_path: &Path) {
|
||||
println!("Installed certificate.");
|
||||
}
|
||||
|
||||
// If this is borked on non-debian platforms, so be it
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn install_ca_files(cert_path: &Path) {
|
||||
let usr_certs = PathBuf::from("/usr/local/share/ca-certificates");
|
||||
let usr_cert_path = usr_certs.join("cultivation.crt");
|
||||
|
||||
// Create dir if it doesn't exist
|
||||
fs::create_dir_all(&usr_certs).expect("Unable to create local certificate directory");
|
||||
|
||||
fs::copy(cert_path, usr_cert_path).expect("Unable to copy cert to local certificate directory");
|
||||
run_command("update-ca-certificates", vec![], None);
|
||||
let platform = os_type::current_platform();
|
||||
use os_type::OSType::*;
|
||||
// TODO: Add more distros
|
||||
match &platform.os_type {
|
||||
// Debian-based
|
||||
Debian | Ubuntu | Kali => {
|
||||
let usr_certs = PathBuf::from("/usr/local/share/ca-certificates");
|
||||
let usr_cert_path = usr_certs.join("cultivation.crt");
|
||||
|
||||
// We want to execute multiple commands, but we don't want multiple pkexec prompts
|
||||
// so we have to use a script
|
||||
let script = Path::new("/tmp/cultivation-inject-ca-cert.sh");
|
||||
let mut scriptf = File::create(script).unwrap();
|
||||
#[cfg(debug_assertions)]
|
||||
let setflags = "xe";
|
||||
#[cfg(not(debug_assertions))]
|
||||
let setflags = "e";
|
||||
write!(
|
||||
scriptf,
|
||||
r#"#!/usr/bin/env bash
|
||||
set -{}
|
||||
CERT="{}"
|
||||
CERT_DIR="{}"
|
||||
CERT_TARGET="{}"
|
||||
# Create dir if it doesn't exist
|
||||
if ! [[ -d "$CERT_DIR" ]]; then
|
||||
mkdir -v "$CERT_DIR"
|
||||
fi
|
||||
cp -v "$CERT" "$CERT_TARGET"
|
||||
update-ca-certificates
|
||||
"#,
|
||||
setflags,
|
||||
cert_path.to_str().unwrap(),
|
||||
usr_certs.to_str().unwrap(),
|
||||
usr_cert_path.to_str().unwrap()
|
||||
)
|
||||
.unwrap();
|
||||
scriptf.flush().unwrap();
|
||||
drop(scriptf);
|
||||
let _ = Command::new("bash")
|
||||
.arg(script)
|
||||
.as_root_gui()
|
||||
.spawn_its_fine_really("Unable to install certificate");
|
||||
if let Err(e) = fs::remove_file(script) {
|
||||
println!("Unable to remove certificate install script: {}", e);
|
||||
};
|
||||
}
|
||||
// RedHat-based
|
||||
//Redhat | CentOS |
|
||||
// Arch-based
|
||||
Arch | Manjaro => {
|
||||
let _ = Command::new("trust")
|
||||
.arg("anchor")
|
||||
.arg("--store")
|
||||
.arg(cert_path)
|
||||
.as_root_gui()
|
||||
.spawn_its_fine_really("Unable to install certificate");
|
||||
}
|
||||
OSX => unreachable!(),
|
||||
_ => {
|
||||
println!("Unsupported Linux distribution.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
println!("Installed certificate.");
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ pub async fn get_latest_release() -> Release {
|
||||
.unwrap();
|
||||
let text = response.text().await.unwrap();
|
||||
|
||||
// This includes ip when github rate limits you, so avoid it for now to avoid leaks through screenshots
|
||||
//println!("Response: {}", text);
|
||||
|
||||
// Parse "tag_name" from JSON
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use ini::Ini;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(windows)]
|
||||
use {
|
||||
registry::{Data, Hive, Security},
|
||||
@@ -10,6 +11,103 @@ use {
|
||||
windows_service::service_manager::{ServiceManager, ServiceManagerAccess},
|
||||
};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::AAGL_THREAD;
|
||||
#[cfg(target_os = "linux")]
|
||||
use anime_launcher_sdk::{
|
||||
config::ConfigExt, genshin::config::Config, genshin::game, genshin::states::LauncherState,
|
||||
wincompatlib::prelude::*,
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::{path::Path, process::Stdio, thread};
|
||||
#[cfg(target_os = "linux")]
|
||||
use term_detect::get_terminal;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn guess_user_terminal() -> String {
|
||||
if let Ok(term) = get_terminal() {
|
||||
return term.0;
|
||||
}
|
||||
eprintln!("Could not guess default terminal. Try setting the $TERMINAL environment variable.");
|
||||
// If everything fails, default to xterm
|
||||
"xterm".to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn rawstrcmd(cmd: &Command) -> String {
|
||||
format!("{:?}", cmd)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn strcmd(cmd: &Command) -> String {
|
||||
format!("bash -c {:?}", rawstrcmd(cmd))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[allow(dead_code)]
|
||||
pub trait AsRoot {
|
||||
fn as_root(&self) -> Self;
|
||||
fn as_root_gui(&self) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl AsRoot for Command {
|
||||
fn as_root(&self) -> Self {
|
||||
let mut cmd = Command::new("sudo");
|
||||
cmd.arg("--").arg("bash").arg("-c").arg(rawstrcmd(self));
|
||||
cmd
|
||||
}
|
||||
fn as_root_gui(&self) -> Self {
|
||||
let mut cmd = Command::new("pkexec");
|
||||
cmd.arg("bash").arg("-c").arg(rawstrcmd(self));
|
||||
cmd
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[allow(dead_code)]
|
||||
trait InTerminalEmulator {
|
||||
fn in_terminal(&self) -> Self;
|
||||
fn in_terminal_noclose(&self) -> Self;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
impl InTerminalEmulator for Command {
|
||||
fn in_terminal(&self) -> Self {
|
||||
let mut cmd = Command::new(guess_user_terminal());
|
||||
cmd.arg("-e").arg(strcmd(self));
|
||||
cmd
|
||||
}
|
||||
fn in_terminal_noclose(&self) -> Self {
|
||||
let mut cmd = Command::new(guess_user_terminal());
|
||||
cmd.arg("--noclose");
|
||||
cmd.arg("-e").arg(strcmd(self));
|
||||
cmd
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub trait SpawnItsFineReally {
|
||||
fn spawn_its_fine_really(&mut self, msg: &str) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl SpawnItsFineReally for Command {
|
||||
fn spawn_its_fine_really(&mut self, msg: &str) -> anyhow::Result<()> {
|
||||
let res = self.status();
|
||||
let Ok(status) = res else {
|
||||
let error = res.unwrap_err();
|
||||
println!("{}: {}", msg, &error);
|
||||
return Err(error.into());
|
||||
};
|
||||
if !status.success() {
|
||||
println!("{}: {}", msg, status);
|
||||
Err(anyhow::anyhow!("{}: {}", msg, status))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn run_program(path: String, args: Option<String>) {
|
||||
// Without unwrap_or, this can crash when UAC prompt is denied
|
||||
@@ -22,6 +120,7 @@ pub fn run_program(path: String, args: Option<String>) {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[tauri::command]
|
||||
pub fn run_program_relative(path: String, args: Option<String>) {
|
||||
// Save the current working directory
|
||||
@@ -41,6 +140,13 @@ pub fn run_program_relative(path: String, args: Option<String>) {
|
||||
std::env::set_current_dir(cwd).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn run_program_relative(path: String, args: Option<String>) {
|
||||
// This program should not run as root
|
||||
run_un_elevated(path, args)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn run_command(program: &str, args: Vec<&str>, relative: Option<bool>) {
|
||||
let prog = program.to_string();
|
||||
@@ -81,6 +187,7 @@ pub fn run_jar(path: String, execute_in: String, java_path: String) {
|
||||
println!("Launching .jar with command: {}", &command);
|
||||
|
||||
// Open the program from the specified path.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
match open::with(
|
||||
format!("/k cd /D \"{}\" & {}", &execute_in, &command),
|
||||
"C:\\Windows\\System32\\cmd.exe",
|
||||
@@ -88,8 +195,58 @@ pub fn run_jar(path: String, execute_in: String, java_path: String) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Failed to open jar ({} from {}): {}", &path, &execute_in, e),
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
thread::spawn(move || {
|
||||
match Command::new(guess_user_terminal())
|
||||
.arg("-e")
|
||||
.arg(command)
|
||||
.current_dir(execute_in.clone())
|
||||
.spawn()
|
||||
{
|
||||
Ok(mut handler) => {
|
||||
// Prevent creation of zombie processes
|
||||
handler
|
||||
.wait()
|
||||
.expect("Grasscutter exited with non-zero exit code");
|
||||
}
|
||||
Err(e) => println!("Failed to open jar ({} from {}): {}", &path, &execute_in, e),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[tauri::command]
|
||||
pub fn run_jar_root(_path: String, _execute_in: String, _java_path: String) {
|
||||
panic!("Not implemented");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn run_jar_root(path: String, execute_in: String, java_path: String) {
|
||||
let mut command = if java_path.is_empty() {
|
||||
Command::new("java")
|
||||
} else {
|
||||
Command::new(java_path)
|
||||
};
|
||||
command.arg("-jar").arg(&path).current_dir(&execute_in);
|
||||
|
||||
println!("Launching .jar with command: {}", strcmd(&command));
|
||||
|
||||
// Open the program from the specified path.
|
||||
thread::spawn(move || {
|
||||
match command.as_root_gui().in_terminal().spawn() {
|
||||
Ok(mut handler) => {
|
||||
// Prevent creation of zombie processes
|
||||
handler
|
||||
.wait()
|
||||
.expect("Grasscutter exited with non-zero exit code");
|
||||
}
|
||||
Err(e) => println!("Failed to open jar ({} from {}): {}", &path, &execute_in, e),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[tauri::command]
|
||||
pub fn run_un_elevated(path: String, args: Option<String>) {
|
||||
// Open the program non-elevated.
|
||||
@@ -106,6 +263,98 @@ pub fn run_un_elevated(path: String, args: Option<String>) {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn aagl_wine_run<P: AsRef<Path>>(path: P, args: Option<String>) -> Command {
|
||||
let config = Config::get().unwrap();
|
||||
let wine = config.get_selected_wine().unwrap().unwrap();
|
||||
let wine_run = wine
|
||||
.to_wine(
|
||||
config.components.path,
|
||||
Some(config.game.wine.builds.join(&wine.name)),
|
||||
)
|
||||
.with_prefix(config.game.wine.prefix)
|
||||
.with_loader(WineLoader::Current)
|
||||
.with_arch(WineArch::Win64);
|
||||
let env: Vec<(String, String)> = config
|
||||
.game
|
||||
.wine
|
||||
.sync
|
||||
.get_env_vars()
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect();
|
||||
use anime_launcher_sdk::components::wine::UnifiedWine::*;
|
||||
let wined = match wine_run {
|
||||
Default(wine) => wine,
|
||||
Proton(proton) => proton.wine().clone(),
|
||||
};
|
||||
let mut cmd = Command::new(&wined.binary);
|
||||
cmd.arg(path.as_ref()).envs(wined.get_envs()).envs(env);
|
||||
if let Some(args) = args {
|
||||
let mut args: Vec<String> = args.split(' ').map(|x| x.to_string()).collect();
|
||||
cmd.args(&mut args);
|
||||
};
|
||||
cmd
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn run_un_elevated(path: String, args: Option<String>) {
|
||||
let path = Path::new(&path);
|
||||
let exec_name = path.file_name().unwrap().to_str().unwrap();
|
||||
if exec_name == ["Yuan", "Shen", ".exe"].join("").as_str()
|
||||
|| exec_name == ["Gen", "shin", "Impact", ".exe"].join("").as_str()
|
||||
{
|
||||
let game_thread = thread::spawn(|| {
|
||||
'statechk: {
|
||||
let state = LauncherState::get_from_config(|_| {});
|
||||
let Ok(state) = state else {
|
||||
println!("Failed to get state: {}", state.unwrap_err());
|
||||
break 'statechk;
|
||||
};
|
||||
use anime_launcher_sdk::genshin::states::LauncherState::*;
|
||||
match state {
|
||||
FolderMigrationRequired { from, .. } => Err(format!(
|
||||
"A folder migration is required ({:?} needs to be moved)",
|
||||
from
|
||||
)),
|
||||
WineNotInstalled => Err("Wine is not installed".to_string()),
|
||||
PrefixNotExists => Err("The Wine prefix does not exist".to_string()),
|
||||
GameNotInstalled(_) => Err("The game is not installed".to_string()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
.expect("Can't launch game. Check the other launcher.");
|
||||
}
|
||||
if let Err(e) = game::run() {
|
||||
println!("An error occurred while running the game: {}", e);
|
||||
}
|
||||
});
|
||||
{
|
||||
let mut game_thead_lock = AAGL_THREAD.lock().unwrap();
|
||||
game_thead_lock.replace(game_thread);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Run exe with wine
|
||||
if path.extension().unwrap() == "exe" {
|
||||
let path = path.to_owned().clone();
|
||||
thread::spawn(move || {
|
||||
let _ = aagl_wine_run(&path, args)
|
||||
.current_dir(path.parent().unwrap())
|
||||
.in_terminal()
|
||||
.spawn_its_fine_really(&format!(
|
||||
"Failed to open program ({})",
|
||||
path.to_str().unwrap()
|
||||
));
|
||||
});
|
||||
}
|
||||
println!(
|
||||
"Can't run {:?}. Running this type of file is not supported yet.",
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_in_browser(url: String) {
|
||||
// Open the URL in the default browser.
|
||||
@@ -119,47 +368,27 @@ pub fn open_in_browser(url: String) {
|
||||
pub fn install_location() -> String {
|
||||
let mut exe_path = std::env::current_exe().unwrap();
|
||||
|
||||
// Get the path to the executable.
|
||||
exe_path.pop();
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// Get the path to the executable.
|
||||
exe_path.pop();
|
||||
|
||||
return exe_path.to_str().unwrap().to_string();
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn set_migoto_target(window: tauri::Window, migoto_path: String) -> bool {
|
||||
let mut migoto_pathbuf = PathBuf::from(migoto_path);
|
||||
|
||||
migoto_pathbuf.pop();
|
||||
migoto_pathbuf.push("d3dx.ini");
|
||||
|
||||
let mut conf = match Ini::load_from_file(&migoto_pathbuf) {
|
||||
Ok(c) => {
|
||||
println!("Loaded migoto ini");
|
||||
c
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error loading migoto config: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
window.emit("migoto_set", &()).unwrap();
|
||||
|
||||
// Set options
|
||||
conf
|
||||
.with_section(Some("Loader"))
|
||||
.set("target", "GenshinImpact.exe");
|
||||
|
||||
// Write file
|
||||
match conf.write_to_file(&migoto_pathbuf) {
|
||||
Ok(_) => {
|
||||
println!("Wrote config!");
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error writing config: {}", e);
|
||||
false
|
||||
return exe_path.to_str().unwrap().to_string();
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let bin_name = exe_path.file_name().unwrap().to_str().unwrap().to_string();
|
||||
exe_path.pop();
|
||||
if exe_path.starts_with("/usr/bin") {
|
||||
let mut path = PathBuf::from("/usr/lib");
|
||||
path.push(bin_name);
|
||||
path
|
||||
} else {
|
||||
exe_path
|
||||
}
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,9 +412,18 @@ pub fn set_migoto_delay(migoto_path: String) -> bool {
|
||||
|
||||
// Set options
|
||||
conf.with_section(Some("Loader")).set("delay", "20");
|
||||
conf
|
||||
.with_section(Some("Include"))
|
||||
.set("include", "ShaderFixes\\help.ini");
|
||||
|
||||
// Write file
|
||||
match conf.write_to_file(&migoto_pathbuf) {
|
||||
match conf.write_to_file_opt(
|
||||
&migoto_pathbuf,
|
||||
ini::WriteOption {
|
||||
escape_policy: (ini::EscapePolicy::Nothing),
|
||||
line_separator: (ini::LineSeparator::SystemDefault),
|
||||
},
|
||||
) {
|
||||
Ok(_) => {
|
||||
println!("Wrote delay!");
|
||||
true
|
||||
@@ -218,6 +456,33 @@ pub fn wipe_registry(exec_name: String) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Error wiping registry: {}", e),
|
||||
}
|
||||
|
||||
match settings.set_value(
|
||||
"MIHOYOSDK_ADL_PROD_CN_h3123967166",
|
||||
&Data::String("".parse().unwrap()),
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Error wiping registry: {}", e),
|
||||
}
|
||||
|
||||
let hsr_settings = match Hive::CurrentUser.open(
|
||||
"Software\\Cognosphere\\Star Rail".to_string(),
|
||||
Security::Write,
|
||||
) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
println!("Error getting registry setting: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match hsr_settings.set_value(
|
||||
"MIHOYOSDK_ADL_PROD_OVERSEA_h1158948810",
|
||||
&Data::String("".parse().unwrap()),
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Error wiping registry: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -235,7 +500,7 @@ pub fn service_status(service: String) -> bool {
|
||||
}
|
||||
};
|
||||
let status_result = my_service.query_status();
|
||||
if let Ok(..) = status_result {
|
||||
if status_result.is_ok() {
|
||||
let status = status_result.unwrap();
|
||||
println!("{} service status: {:?}", service, status.current_state);
|
||||
if status.current_state == Stopped {
|
||||
@@ -248,9 +513,41 @@ pub fn service_status(service: String) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn to_linux_service_name(service: &str) -> Option<String> {
|
||||
Some(format!(
|
||||
"{}.service",
|
||||
match service {
|
||||
"MongoDB" => "mongod",
|
||||
_ => return None,
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn service_status(_service: String) {}
|
||||
pub fn service_status(service: String) -> bool {
|
||||
// Change Windows service name into Linux service name
|
||||
let service_lnx = to_linux_service_name(&service);
|
||||
if service_lnx.is_none() {
|
||||
return false;
|
||||
}
|
||||
let service_lnx = service_lnx.unwrap();
|
||||
let status = Command::new("systemctl")
|
||||
.arg("is-active")
|
||||
.arg(service_lnx)
|
||||
.stdout(Stdio::null())
|
||||
.status();
|
||||
if status.is_err() {
|
||||
return false;
|
||||
}
|
||||
let status = status.unwrap().success();
|
||||
if status {
|
||||
status
|
||||
} else {
|
||||
start_service(service)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
@@ -271,10 +568,20 @@ pub fn start_service(service: String) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn start_service(_service: String) {
|
||||
let _started = OsStr::new("Started service!");
|
||||
pub fn start_service(service: String) -> bool {
|
||||
println!("Starting service: {}", service);
|
||||
let service_lnx = to_linux_service_name(&service);
|
||||
if service_lnx.is_none() {
|
||||
return false;
|
||||
}
|
||||
let service_lnx = service_lnx.unwrap();
|
||||
Command::new("systemctl")
|
||||
.arg("start")
|
||||
.arg(service_lnx)
|
||||
.spawn_its_fine_really(&format!("Failed to stop service {}", service))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -296,11 +603,39 @@ pub fn stop_service(service: String) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn stop_service(_service: String) {}
|
||||
pub fn stop_service(service: String) -> bool {
|
||||
println!("Stopping service: {}", service);
|
||||
let service_lnx = to_linux_service_name(&service);
|
||||
if service_lnx.is_none() {
|
||||
return false;
|
||||
}
|
||||
let service_lnx = service_lnx.unwrap();
|
||||
Command::new("systemctl")
|
||||
.arg("stop")
|
||||
.arg(service_lnx)
|
||||
.spawn_its_fine_really(&format!("Failed to start service {}", service))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn wipe_registry(exec_name: String) {
|
||||
println!("Wiping registry");
|
||||
let regpath = format!("HKCU\\Software\\miHoYo\\{}", exec_name);
|
||||
let mut cmd = aagl_wine_run("reg", None);
|
||||
cmd.args([
|
||||
"DELETE",
|
||||
®path,
|
||||
"/f",
|
||||
"/v",
|
||||
"MIHOYOSDK_ADL_PROD_OVERSEA_h1158948810",
|
||||
]);
|
||||
let _ = cmd.spawn_its_fine_really("Error wiping registry");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[tauri::command]
|
||||
pub fn wipe_registry(_exec_name: String) {}
|
||||
|
||||
@@ -320,3 +655,55 @@ pub fn is_elevated() -> bool {
|
||||
pub fn get_platform() -> &'static str {
|
||||
std::env::consts::OS
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_add_cap(_java_path: String) -> bool {
|
||||
panic!("Not implemented");
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_remove_cap(_java_path: String) -> bool {
|
||||
panic!("Not implemented");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_add_cap(java_path: String) -> bool {
|
||||
let mut java_bin = if java_path.is_empty() {
|
||||
which::which("java").expect("Java is not installed")
|
||||
} else {
|
||||
PathBuf::from(&java_path)
|
||||
};
|
||||
while java_bin.is_symlink() {
|
||||
java_bin = java_bin.read_link().unwrap()
|
||||
}
|
||||
println!("Removing cap on {:?}", &java_bin);
|
||||
Command::new("setcap")
|
||||
.arg("CAP_NET_BIND_SERVICE=+eip")
|
||||
.arg(java_bin)
|
||||
.as_root_gui()
|
||||
.spawn_its_fine_really(&format!("Failed to add cap to {}", java_path))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_remove_cap(java_path: String) -> bool {
|
||||
let mut java_bin = if java_path.is_empty() {
|
||||
which::which("java").expect("Java is not installed")
|
||||
} else {
|
||||
PathBuf::from(&java_path)
|
||||
};
|
||||
while java_bin.is_symlink() {
|
||||
java_bin = java_bin.read_link().unwrap()
|
||||
}
|
||||
println!("Setting cap on {:?}", &java_bin);
|
||||
Command::new("setcap")
|
||||
.arg("-r")
|
||||
.arg(java_bin)
|
||||
.as_root_gui()
|
||||
.spawn_its_fine_really(&format!("Failed to remove cap from {}", java_path))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
@@ -107,7 +107,8 @@ pub fn unzip(
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if zipfile.contains("GrasscutterQuests") {
|
||||
// Alternate builds
|
||||
if zipfile.contains("GrasscutterQuests") || zipfile.contains("Grasscutter50") {
|
||||
window
|
||||
.emit("jar_extracted", destpath.to_string() + "grasscutter.jar")
|
||||
.unwrap();
|
||||
|
||||
@@ -36,8 +36,8 @@ pub(crate) async fn valid_url(url: String) -> bool {
|
||||
.await
|
||||
.ok();
|
||||
|
||||
if response.is_some() {
|
||||
return response.unwrap().status().as_str() == "200";
|
||||
if let Some(thing) = response {
|
||||
return thing.status().as_str() == "200";
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "Cultivation",
|
||||
"version": "1.1.1"
|
||||
"version": "1.5.1"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
@@ -53,7 +53,7 @@
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": "default-src 'self'; img-src 'self'; img-src https://* asset: https://asset.localhost; media-src https://* asset: https://asset.localhost; style-src-elem https://* asset https://asset.localhost; script-src-elem https://* asset https://asset.localhost;"
|
||||
"csp": "default-src 'self'; img-src 'self' https://* asset: https://asset.localhost tauri://localhost; media-src https://* asset: https://asset.localhost tauri://localhost; style-src-elem https://* asset: https://asset.localhost tauri://localhost; script-src-elem https://* asset: https://asset.localhost tauri://localhost;"
|
||||
},
|
||||
"updater": {
|
||||
"active": false,
|
||||
|
||||
@@ -17,7 +17,7 @@ interface IState {
|
||||
}
|
||||
|
||||
const downloadHandler = new DownloadHandler()
|
||||
const DEFAULT_BG = 'https://api.grasscutter.io/cultivation/bgfile'
|
||||
const WEB_BG = 'https://api.grasscutter.io/cultivation/bgfile'
|
||||
|
||||
class App extends React.Component<Readonly<unknown>, IState> {
|
||||
constructor(props: Readonly<unknown>) {
|
||||
@@ -25,7 +25,7 @@ class App extends React.Component<Readonly<unknown>, IState> {
|
||||
|
||||
this.state = {
|
||||
page: 'main',
|
||||
bgFile: DEFAULT_BG,
|
||||
bgFile: FALLBACK_BG,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,9 @@ class App extends React.Component<Readonly<unknown>, IState> {
|
||||
|
||||
// Get custom bg AFTER theme is loaded !! important !!
|
||||
const custom_bg = await getConfigOption('custom_background')
|
||||
const offline_mode = await getConfigOption('offline_mode')
|
||||
|
||||
if (custom_bg) {
|
||||
if (custom_bg || offline_mode) {
|
||||
const isUrl = /^http(s)?:\/\//gm.test(custom_bg)
|
||||
|
||||
if (!isUrl) {
|
||||
@@ -50,7 +51,7 @@ class App extends React.Component<Readonly<unknown>, IState> {
|
||||
|
||||
this.setState(
|
||||
{
|
||||
bgFile: isValid ? convertFileSrc(custom_bg) : DEFAULT_BG,
|
||||
bgFile: isValid ? convertFileSrc(custom_bg) : FALLBACK_BG,
|
||||
},
|
||||
this.forceUpdate
|
||||
)
|
||||
@@ -62,7 +63,7 @@ class App extends React.Component<Readonly<unknown>, IState> {
|
||||
|
||||
this.setState(
|
||||
{
|
||||
bgFile: isValid ? custom_bg : DEFAULT_BG,
|
||||
bgFile: isValid ? custom_bg : FALLBACK_BG,
|
||||
},
|
||||
this.forceUpdate
|
||||
)
|
||||
@@ -70,12 +71,12 @@ class App extends React.Component<Readonly<unknown>, IState> {
|
||||
} else {
|
||||
// Check if api bg is accessible
|
||||
const isDefaultValid = await invoke('valid_url', {
|
||||
url: DEFAULT_BG,
|
||||
url: WEB_BG,
|
||||
})
|
||||
|
||||
this.setState(
|
||||
{
|
||||
bgFile: isDefaultValid ? DEFAULT_BG : FALLBACK_BG,
|
||||
bgFile: isDefaultValid ? WEB_BG : FALLBACK_BG,
|
||||
},
|
||||
this.forceUpdate
|
||||
)
|
||||
@@ -86,6 +87,7 @@ class App extends React.Component<Readonly<unknown>, IState> {
|
||||
// @ts-expect-error - TS doesn't like our custom event
|
||||
page: e.detail,
|
||||
})
|
||||
this.forceUpdate
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
106
src/ui/Main.tsx
106
src/ui/Main.tsx
@@ -4,7 +4,7 @@ import React from 'react'
|
||||
import TopBar from './components/TopBar'
|
||||
import ServerLaunchSection from './components/ServerLaunchSection'
|
||||
import MainProgressBar from './components/common/MainProgressBar'
|
||||
import Options from './components/menu/Options'
|
||||
import Options, { GrasscutterElevation } from './components/menu/Options'
|
||||
import MiniDialog from './components/MiniDialog'
|
||||
import DownloadList from './components/common/DownloadList'
|
||||
import Downloads from './components/menu/Downloads'
|
||||
@@ -15,7 +15,7 @@ import { ExtrasMenu } from './components/menu/ExtrasMenu'
|
||||
import Notification from './components/common/Notification'
|
||||
import GamePathNotify from './components/menu/GamePathNotify'
|
||||
|
||||
import { getConfigOption, setConfigOption } from '../utils/configuration'
|
||||
import { getConfig, getConfigOption, setConfigOption } from '../utils/configuration'
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
@@ -45,6 +45,7 @@ interface IState {
|
||||
notification: React.ReactElement | null
|
||||
isGamePathSet: boolean
|
||||
game_install_path: string
|
||||
platform: string
|
||||
}
|
||||
|
||||
export class Main extends React.Component<IProps, IState> {
|
||||
@@ -64,6 +65,7 @@ export class Main extends React.Component<IProps, IState> {
|
||||
notification: null,
|
||||
isGamePathSet: true,
|
||||
game_install_path: '',
|
||||
platform: '',
|
||||
}
|
||||
|
||||
listen('lang_error', (payload) => {
|
||||
@@ -74,8 +76,10 @@ export class Main extends React.Component<IProps, IState> {
|
||||
setConfigOption('grasscutter_path', payload)
|
||||
})
|
||||
|
||||
listen('migoto_extracted', ({ payload }: { payload: string }) => {
|
||||
setConfigOption('migoto_path', payload)
|
||||
listen('migoto_extracted', async ({ payload }: { payload: string }) => {
|
||||
await setConfigOption('migoto_path', payload)
|
||||
this.setState({ migotoSet: true })
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
// Emitted for rsa replacing-purposes
|
||||
@@ -91,21 +95,31 @@ export class Main extends React.Component<IProps, IState> {
|
||||
}
|
||||
})
|
||||
|
||||
listen('migoto_set', async () => {
|
||||
this.setState({
|
||||
migotoSet: !!(await getConfigOption('migoto_path')),
|
||||
})
|
||||
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
// Emitted for automatic processes
|
||||
listen('grasscutter_closed', async () => {
|
||||
const autoService = await getConfigOption('auto_mongodb')
|
||||
const config = await getConfig()
|
||||
|
||||
if (autoService) {
|
||||
await invoke('stop_service', { service: 'MongoDB' })
|
||||
}
|
||||
|
||||
if ((await invoke('get_platform')) === 'linux') {
|
||||
switch (config.grasscutter_elevation) {
|
||||
case GrasscutterElevation.None:
|
||||
break
|
||||
|
||||
case GrasscutterElevation.Capability:
|
||||
await invoke('jvm_remove_cap', {
|
||||
javaPath: config.java_path,
|
||||
})
|
||||
break
|
||||
|
||||
default:
|
||||
console.error('Invalid grasscutter_elevation')
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let min = false
|
||||
@@ -134,10 +148,18 @@ export class Main extends React.Component<IProps, IState> {
|
||||
game_install_path: game_path,
|
||||
})
|
||||
|
||||
if (this.state.game_install_path === '') {
|
||||
this.setState({ isGamePathSet: false })
|
||||
}
|
||||
|
||||
this.setState({
|
||||
migotoSet: !!(await getConfigOption('migoto_path')),
|
||||
})
|
||||
|
||||
this.setState({
|
||||
platform: await invoke('get_platform'),
|
||||
})
|
||||
|
||||
if (!cert_generated) {
|
||||
// Generate the certificate
|
||||
await invoke('generate_ca_files', {
|
||||
@@ -151,33 +173,38 @@ export class Main extends React.Component<IProps, IState> {
|
||||
const updatedConfig = await getConfigOption('patch_rsa')
|
||||
await setConfigOption('patch_rsa', updatedConfig)
|
||||
|
||||
// Get latest version and compare to this version
|
||||
const latestVersion: {
|
||||
tag_name: string
|
||||
link: string
|
||||
} = await invoke('get_latest_release')
|
||||
const tagName = latestVersion?.tag_name.replace(/[^\d.]/g, '')
|
||||
// Update launch args to allow launching when updating from old versions
|
||||
await setConfigOption('launch_args', await getConfigOption('launch_args'))
|
||||
|
||||
// Check if tagName is different than current version
|
||||
if (tagName && tagName !== (await getVersion())) {
|
||||
// Display notification of new release
|
||||
this.setState({
|
||||
notification: (
|
||||
<>
|
||||
Cultivation{' '}
|
||||
<a href="#" onClick={() => invoke('open_in_browser', { url: latestVersion.link })}>
|
||||
{latestVersion?.tag_name}
|
||||
</a>{' '}
|
||||
is now available!
|
||||
</>
|
||||
),
|
||||
})
|
||||
if (!(await getConfigOption('offline_mode'))) {
|
||||
// Get latest version and compare to this version
|
||||
const latestVersion: {
|
||||
tag_name: string
|
||||
link: string
|
||||
} = await invoke('get_latest_release')
|
||||
const tagName = latestVersion?.tag_name.replace(/[^\d.]/g, '')
|
||||
|
||||
setTimeout(() => {
|
||||
// Check if tagName is different than current version
|
||||
if (tagName && tagName !== (await getVersion())) {
|
||||
// Display notification of new release
|
||||
this.setState({
|
||||
notification: null,
|
||||
notification: (
|
||||
<>
|
||||
Cultivation{' '}
|
||||
<a href="#" onClick={() => invoke('open_in_browser', { url: latestVersion.link })}>
|
||||
{latestVersion?.tag_name}
|
||||
</a>{' '}
|
||||
is now available!
|
||||
</>
|
||||
),
|
||||
})
|
||||
}, 6000)
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
notification: null,
|
||||
})
|
||||
}, 6000)
|
||||
}
|
||||
}
|
||||
|
||||
// Period check to only show progress bar when downloading files
|
||||
@@ -204,7 +231,7 @@ export class Main extends React.Component<IProps, IState> {
|
||||
})) as boolean
|
||||
|
||||
// Set no game path so the user understands it doesn't exist there
|
||||
if (!game_exists) {
|
||||
if (!game_exists && this.state.platform === 'windows') {
|
||||
setConfigOption('game_install_path', '')
|
||||
}
|
||||
|
||||
@@ -305,7 +332,10 @@ export class Main extends React.Component<IProps, IState> {
|
||||
this.state.optionsOpen ? (
|
||||
<Options
|
||||
downloadManager={this.props.downloadHandler}
|
||||
closeFn={() => this.setState({ optionsOpen: !this.state.optionsOpen })}
|
||||
closeFn={async () => {
|
||||
this.setState({ optionsOpen: !this.state.optionsOpen })
|
||||
this.setState({ migotoSet: !!(await getConfigOption('migoto_path')) })
|
||||
}}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
@@ -321,7 +351,7 @@ export class Main extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
<div className="BottomSection" id="bottomSectionContainer">
|
||||
<ServerLaunchSection openExtras={this.openExtrasMenu} />
|
||||
<ServerLaunchSection openExtras={this.openExtrasMenu} downloadHandler={this.props.downloadHandler} />
|
||||
|
||||
<div
|
||||
id="DownloadProgress"
|
||||
|
||||
@@ -151,7 +151,7 @@ export class Mods extends React.Component<IProps, IState> {
|
||||
},
|
||||
this.forceUpdate
|
||||
)
|
||||
}, 500)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -211,7 +211,7 @@ export class Mods extends React.Component<IProps, IState> {
|
||||
<TextInput
|
||||
id="search"
|
||||
key="search"
|
||||
placeholder={this.state.page.toString()}
|
||||
placeholder={'Search Mods - Page ' + this.state.page.toString()}
|
||||
onChange={(text: string) => {
|
||||
this.setSearch(text)
|
||||
}}
|
||||
|
||||
@@ -12,12 +12,16 @@ import Plus from '../../resources/icons/plus.svg'
|
||||
|
||||
import './ServerLaunchSection.css'
|
||||
import { dataDir } from '@tauri-apps/api/path'
|
||||
import { GrasscutterElevation } from './menu/Options'
|
||||
import { getGameExecutable, getGameVersion, getGrasscutterJar } from '../../utils/game'
|
||||
import { patchGame, unpatchGame } from '../../utils/rsa'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import { confirm } from '@tauri-apps/api/dialog'
|
||||
import DownloadHandler from '../../utils/download'
|
||||
|
||||
interface IProps {
|
||||
openExtras: (playGame: () => void) => void
|
||||
downloadHandler: DownloadHandler
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@@ -70,10 +74,15 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
this.setPort = this.setPort.bind(this)
|
||||
this.toggleHttps = this.toggleHttps.bind(this)
|
||||
this.launchServer = this.launchServer.bind(this)
|
||||
this.setButtonLabel = this.setButtonLabel.bind(this)
|
||||
|
||||
listen('start_grasscutter', async () => {
|
||||
this.launchServer()
|
||||
})
|
||||
|
||||
listen('set_game', async () => {
|
||||
this.setButtonLabel()
|
||||
})
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@@ -94,6 +103,8 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
migotoSet: config.migoto_path !== '',
|
||||
unElevated: config.un_elevated || false,
|
||||
})
|
||||
|
||||
this.setButtonLabel()
|
||||
}
|
||||
|
||||
async toggleGrasscutter() {
|
||||
@@ -117,9 +128,32 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
return
|
||||
}
|
||||
|
||||
// Check for HTTPS on local
|
||||
if (this.state.httpsEnabled) {
|
||||
if (this.state.ip == 'localhost') {
|
||||
if (
|
||||
await confirm(
|
||||
"Oops! HTTPS is enabled but you're connecting to localhost! \nHTTPS MUST be disabled for localhost. \n\nWould you like to disable HTTPS and continue?",
|
||||
{ title: 'WARNING!!', type: 'warning' }
|
||||
)
|
||||
) {
|
||||
this.toggleHttps()
|
||||
} else {
|
||||
if (!(await confirm('You have chosen to keep HTTPS enabled! \n\nYOU WILL ERROR ON LOGIN.'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to proxy
|
||||
if (config.toggle_grasscutter) {
|
||||
if (config.patch_rsa) {
|
||||
const game_exe = await getGameExecutable()
|
||||
let newerGame = false
|
||||
|
||||
const patchable = game_exe?.toLowerCase().includes('yuanshen') || game_exe?.toLowerCase().includes('genshin')
|
||||
|
||||
if (config.patch_rsa && patchable) {
|
||||
const gameVersion = await getGameVersion()
|
||||
console.log(gameVersion)
|
||||
|
||||
@@ -140,16 +174,62 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
return
|
||||
}
|
||||
|
||||
const patched = await patchGame()
|
||||
if (gameVersion?.major == 4 && gameVersion?.minor == 5) {
|
||||
await confirm(
|
||||
'Please use Cultivation version 1.4.0 for game version 4.5. You can find that here: https://github.com/NotThorny/Cultivation/releases/tag/1.4.0'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const versionString = gameVersion?.major.toString() + gameVersion?.minor.toString()
|
||||
|
||||
if ((gameVersion?.major == 4 && gameVersion?.minor > 5) || config.newer_game) {
|
||||
newerGame = true
|
||||
|
||||
const path = (await invoke('install_location')) as string
|
||||
|
||||
const patchstring = '\\altpatch\\'
|
||||
const altPatch = path + patchstring
|
||||
|
||||
const ALT_PATCH =
|
||||
'https://autopatchhk.yuanshen.com/client_app/download/pc_zip/20231030132335_iOEfPMcbrXpiA8Ca/ScatteredFiles/GenshinImpact_Data/Plugins/mihoyonet.dll'
|
||||
const pExists = (await invoke('dir_exists', {
|
||||
path: altPatch,
|
||||
})) as boolean
|
||||
|
||||
if (!pExists) {
|
||||
await invoke('dir_create', {
|
||||
path: altPatch,
|
||||
})
|
||||
this.props.downloadHandler.addDownload(ALT_PATCH, path + '/altpatch/mihoyonet.dll')
|
||||
await confirm('Please wait for the download in the bottom left to disappear, then click yes')
|
||||
}
|
||||
|
||||
/* For custom address patch only, used in 4.5 */
|
||||
// let httpString = 'http://'
|
||||
// if (this.state.httpsEnabled) {
|
||||
// httpString = 'https://'
|
||||
// }
|
||||
// config.launch_args = '-server=' + httpString + this.state.ip + ':' + this.state.port
|
||||
}
|
||||
|
||||
const patched = await patchGame(newerGame, versionString)
|
||||
|
||||
if (!patched) {
|
||||
alert('Could not patch! Try launching again, or patching manually.')
|
||||
alert(
|
||||
"Could not patch! You're trying to launch a version that you don't have a patch for!" +
|
||||
"\nEnsure you're using a valid game version, and have the patch for this version in your Cultivation install folder." +
|
||||
'\n\nIf this means nothing to you, YOU HAVE THE WRONG GAME VERSION.' +
|
||||
// Add game version due to overwhelming number of people saying they are using a version they are not using
|
||||
'\n\nYOUR GAME VERSION: ' +
|
||||
gameVersion?.major +
|
||||
'.' +
|
||||
gameVersion?.minor
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const game_exe = await getGameExecutable()
|
||||
|
||||
// Save last connected server and port
|
||||
await setConfigOption('last_ip', this.state.ip)
|
||||
await setConfigOption('last_port', this.state.port)
|
||||
@@ -192,9 +272,19 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
if (config.un_elevated) {
|
||||
await invoke('run_un_elevated', {
|
||||
path: config.game_install_path,
|
||||
args: config.launch_args,
|
||||
})
|
||||
} else {
|
||||
await invoke('run_program_relative', { path: exe || config.game_install_path })
|
||||
if (config.launch_args.length < 1) {
|
||||
// Run relative when there are no args
|
||||
await invoke('run_program_relative', { path: exe || config.game_install_path })
|
||||
} else {
|
||||
// Run directly when there are args
|
||||
await invoke('run_program', {
|
||||
path: exe || config.game_install_path,
|
||||
args: config.launch_args,
|
||||
})
|
||||
}
|
||||
}
|
||||
else alert('Game not found! At: ' + (exe || config.game_install_path))
|
||||
}
|
||||
@@ -208,13 +298,14 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
|
||||
if (!config.grasscutter_path) return alert('Grasscutter not installed or set!')
|
||||
|
||||
const grasscutter_jar = await getGrasscutterJar()
|
||||
await invoke('enable_grasscutter_watcher', {
|
||||
process: proc_name || grasscutter_jar,
|
||||
})
|
||||
|
||||
if (config.auto_mongodb) {
|
||||
const grasscutter_jar = await getGrasscutterJar()
|
||||
await invoke('enable_grasscutter_watcher', {
|
||||
process: proc_name || grasscutter_jar,
|
||||
})
|
||||
// Check if MongoDB is running and start it if not
|
||||
await invoke('service_status', { service: 'MongoDB' })
|
||||
invoke('service_status', { service: 'MongoDB' })
|
||||
}
|
||||
|
||||
let jarFolder = config.grasscutter_path
|
||||
@@ -225,8 +316,31 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
jarFolder = jarFolder.substring(0, config.grasscutter_path.lastIndexOf('\\'))
|
||||
}
|
||||
|
||||
let cmd = 'run_jar'
|
||||
|
||||
if ((await invoke('get_platform')) === 'linux') {
|
||||
switch (config.grasscutter_elevation) {
|
||||
case GrasscutterElevation.None:
|
||||
break
|
||||
|
||||
case GrasscutterElevation.Capability:
|
||||
await invoke('jvm_add_cap', {
|
||||
javaPath: config.java_path,
|
||||
})
|
||||
break
|
||||
|
||||
case GrasscutterElevation.Root:
|
||||
cmd = 'run_jar_root'
|
||||
break
|
||||
|
||||
default:
|
||||
console.error('Invalid grasscutter_elevation')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Launch the jar
|
||||
await invoke('run_jar', {
|
||||
await invoke(cmd, {
|
||||
path: config.grasscutter_path,
|
||||
executeIn: jarFolder,
|
||||
javaPath: config.java_path || '',
|
||||
@@ -258,6 +372,19 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
await saveConfig(config)
|
||||
}
|
||||
|
||||
async setButtonLabel() {
|
||||
const ver = await getGameVersion()
|
||||
if (ver != null) {
|
||||
this.setState({
|
||||
buttonLabel: (await translate('main.launch_button')) + ' ' + ver?.major + '.' + ver?.minor,
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
buttonLabel: await translate('main.launch_button'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="playButton">
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import React from 'react'
|
||||
import { app } from '@tauri-apps/api'
|
||||
import { app, invoke } from '@tauri-apps/api'
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
import { getConfig, setConfigOption } from '../../utils/configuration'
|
||||
import Tr from '../../utils/language'
|
||||
import { confirm } from '@tauri-apps/api/dialog'
|
||||
|
||||
import './TopBar.css'
|
||||
import closeIcon from '../../resources/icons/close.svg'
|
||||
import minIcon from '../../resources/icons/min.svg'
|
||||
import { unpatchGame } from '../../utils/rsa'
|
||||
|
||||
interface IProps {
|
||||
children?: React.ReactNode | React.ReactNode[]
|
||||
@@ -36,7 +38,19 @@ export default class TopBar extends React.Component<IProps, IState> {
|
||||
this.setState({ version })
|
||||
}
|
||||
|
||||
handleClose() {
|
||||
async handleClose() {
|
||||
if (await invoke('is_game_running')) {
|
||||
const confirmed = await confirm(
|
||||
'Game is running. You WILL NOT be unpatched. Would you like to exit?',
|
||||
'WARNING!!'
|
||||
)
|
||||
if (!confirmed) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
await invoke('disconnect')
|
||||
unpatchGame()
|
||||
appWindow.close()
|
||||
}
|
||||
|
||||
|
||||
@@ -8,19 +8,23 @@ import { dataDir } from '@tauri-apps/api/path'
|
||||
|
||||
import './Downloads.css'
|
||||
import Divider from './Divider'
|
||||
import { getConfigOption } from '../../../utils/configuration'
|
||||
import { getConfigOption, setConfigOption } from '../../../utils/configuration'
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import HelpButton from '../common/HelpButton'
|
||||
import { ask } from '@tauri-apps/api/dialog'
|
||||
|
||||
const FULL_BUILD_DOWNLOAD = 'https://github.com/NotThorny/Grasscutter/releases/download/culti-aio/GrasscutterCulti.zip'
|
||||
const FULL_BUILD_DOWNLOAD = 'https://github.com/NotThorny/Grasscutter/releases/download/culti-aio/GrasscutterCulti.zip' // Change to link that can be updated without modifying here
|
||||
const FULL_QUEST_DOWNLOAD = 'https://github.com/NotThorny/Grasscutter/releases/download/culti-aio/GrasscutterQuests.zip'
|
||||
const FULL_50_DOWNLOAD = 'https://github.com/NotThorny/Grasscutter/releases/download/culti-aio/GrasscutterLunaGC50.zip' // https://github.com/Kei-Luna/LunaGC_5.0.0
|
||||
const STABLE_REPO_DOWNLOAD = 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/stable.zip'
|
||||
const DEV_REPO_DOWNLOAD = 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/development.zip'
|
||||
const UNSTABLE_DOWNLOAD = 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/unstable/Grasscutter.zip'
|
||||
const DEV_DOWNLOAD = 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/development/Grasscutter.zip'
|
||||
const RESOURCES_DOWNLOAD = 'https://gitlab.com/api/v4/projects/35984297/repository/archive.zip' // Use Yuuki res as grasscutter crepe res are broken
|
||||
const MIGOTO_DOWNLOAD =
|
||||
'https://github.com/SilentNightSound/GI-Model-Importer/releases/download/V7.0/3dmigoto-GIMI-for-playing-mods.zip'
|
||||
'https://github.com/SilentNightSound/GI-Model-Importer/releases/download/v7.0/3dmigoto-GIMI-for-playing-mods.zip'
|
||||
const MIGOTO_FALLBACK = 'https://cdn.discordapp.com/attachments/615655311960965130/1177724469847003268/GIMI7.zip' // Since main dl fails for a few too many users
|
||||
|
||||
interface IProps {
|
||||
closeFn: () => void
|
||||
@@ -55,6 +59,8 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
|
||||
this.getGrasscutterFolder = this.getGrasscutterFolder.bind(this)
|
||||
this.downloadGrasscutterFullBuild = this.downloadGrasscutterFullBuild.bind(this)
|
||||
this.downloadGrasscutterFullQuest = this.downloadGrasscutterFullQuest.bind(this)
|
||||
this.downloadGrasscutterFull50 = this.downloadGrasscutterFull50.bind(this)
|
||||
this.downloadGrasscutterStableRepo = this.downloadGrasscutterStableRepo.bind(this)
|
||||
this.downloadGrasscutterDevRepo = this.downloadGrasscutterDevRepo.bind(this)
|
||||
this.downloadGrasscutterUnstable = this.downloadGrasscutterUnstable.bind(this)
|
||||
@@ -76,6 +82,19 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
this.setState({ grasscutter_set: true }, this.forceUpdate)
|
||||
})
|
||||
|
||||
// Listen for GIMI failure to initiate fallback
|
||||
listen('download_error', ({ payload }) => {
|
||||
// @ts-expect-error shut up typescript
|
||||
const errorData: {
|
||||
path: string
|
||||
error: string
|
||||
} = payload
|
||||
|
||||
if (errorData.path.includes('GIMI.zip')) {
|
||||
this.downloadMigotoFallback()
|
||||
}
|
||||
})
|
||||
|
||||
if (!gc_path || gc_path === '') {
|
||||
this.setState({
|
||||
grasscutter_set: false,
|
||||
@@ -141,6 +160,26 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
this.toggleButtons()
|
||||
}
|
||||
|
||||
async downloadGrasscutterFullQuest() {
|
||||
const folder = await this.getGrasscutterFolder()
|
||||
this.props.downloadManager.addDownload(FULL_QUEST_DOWNLOAD, folder + '\\GrasscutterQuests.zip', async () => {
|
||||
await unzip(folder + '\\GrasscutterQuests.zip', folder + '\\', true)
|
||||
this.toggleButtons()
|
||||
})
|
||||
|
||||
this.toggleButtons()
|
||||
}
|
||||
|
||||
async downloadGrasscutterFull50() {
|
||||
const folder = await this.getGrasscutterFolder()
|
||||
this.props.downloadManager.addDownload(FULL_50_DOWNLOAD, folder + '\\Grasscutter50.zip', async () => {
|
||||
await unzip(folder + '\\Grasscutter50.zip', folder + '\\', true)
|
||||
this.toggleButtons()
|
||||
})
|
||||
|
||||
this.toggleButtons()
|
||||
}
|
||||
|
||||
async downloadGrasscutterStableRepo() {
|
||||
const folder = await this.getGrasscutterFolder()
|
||||
this.props.downloadManager.addDownload(STABLE_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', async () => {
|
||||
@@ -185,13 +224,23 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
async downloadResources() {
|
||||
// Tell the user this is not needed in most cases
|
||||
if (
|
||||
!(await ask(
|
||||
'These are not needed if you have already downloaded the All-in-One!! \nAre you sure you want to continue this download?'
|
||||
))
|
||||
) {
|
||||
// If refusing confirmation
|
||||
return
|
||||
}
|
||||
|
||||
// Tell the user this takes some time
|
||||
alert(
|
||||
'Extracting resources can take time! If your resources appear to be "stuck" extracting for less than 15-20 mins, they likely still are extracting.'
|
||||
)
|
||||
|
||||
const folder = await this.getGrasscutterFolder()
|
||||
this.props.downloadManager.addDownload(RESOURCES_DOWNLOAD, folder + '\\resources.zip', async () => {
|
||||
// Tell the user this takes some time
|
||||
alert(
|
||||
'Extracting resources can take time! If your resources appear to be "stuck" extracting for less than 15-20 mins, they likely still are extracting.'
|
||||
)
|
||||
|
||||
// Delete the existing folder if it exists
|
||||
if (
|
||||
await invoke('dir_exists', {
|
||||
@@ -217,13 +266,27 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
async downloadMigoto() {
|
||||
const folder = (await this.getCultivationFolder()) + '\\3dmigoto'
|
||||
await invoke('dir_create', {
|
||||
path: folder,
|
||||
if (!this.state.swag) {
|
||||
await setConfigOption('swag_mode', true)
|
||||
this.setState({ swag: true })
|
||||
await setConfigOption('last_extras', { migoto: true, akebi: false, reshade: false })
|
||||
}
|
||||
|
||||
const folder = await this.getCultivationFolder()
|
||||
|
||||
this.props.downloadManager.addDownload(MIGOTO_DOWNLOAD, folder + '\\GIMI.zip', async () => {
|
||||
await unzip(folder + '\\GIMI.zip', folder + '\\', true, true)
|
||||
this.toggleButtons()
|
||||
})
|
||||
|
||||
this.props.downloadManager.addDownload(MIGOTO_DOWNLOAD, folder + '\\GIMI-3dmigoto.zip', async () => {
|
||||
await unzip(folder + '\\GIMI-3dmigoto.zip', folder + '\\', true)
|
||||
this.toggleButtons()
|
||||
}
|
||||
|
||||
async downloadMigotoFallback() {
|
||||
const folder = await this.getCultivationFolder()
|
||||
|
||||
this.props.downloadManager.addDownload(MIGOTO_FALLBACK, folder + '\\GIMI7.zip', async () => {
|
||||
await unzip(folder + '\\GIMI7.zip', folder + '\\', true, true)
|
||||
this.toggleButtons()
|
||||
})
|
||||
|
||||
@@ -267,12 +330,28 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
</BigButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerGCFullQuest">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelGCFullQuest">
|
||||
<Tr text={'downloads.grasscutter_fullquest'} />
|
||||
<HelpButton contents="help.gc_fullbuild" />
|
||||
</div>
|
||||
<div className="DownloadValue" id="downloadMenuButtonGCFullQuest">
|
||||
<BigButton
|
||||
disabled={this.state.grasscutter_downloading}
|
||||
onClick={this.downloadGrasscutterFull50}
|
||||
id="grasscutterFullBuildBtn"
|
||||
>
|
||||
<Tr text="components.download" />
|
||||
</BigButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="HeaderText" id="downloadMenuIndividualHeader">
|
||||
<Tr text="downloads.individual_header" />
|
||||
</div>
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerGCUnstable">
|
||||
{/* <div className="DownloadMenuSection" id="downloadMenuContainerGCUnstable">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelGCUnstable">
|
||||
<Tr
|
||||
text={
|
||||
@@ -290,7 +369,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
<Tr text="components.download" />
|
||||
</BigButton>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerGCDev">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelGCDev">
|
||||
<Tr
|
||||
@@ -330,7 +409,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
</BigButton>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerGCDevData">
|
||||
{/* <div className="DownloadMenuSection" id="downloadMenuContainerGCDevData">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelGCDevData">
|
||||
<Tr
|
||||
text={
|
||||
@@ -350,7 +429,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
<Tr text="components.download" />
|
||||
</BigButton>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerResources">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelResources">
|
||||
@@ -368,25 +447,23 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.swag && (
|
||||
<>
|
||||
<Divider />
|
||||
<div className="HeaderText" id="downloadMenuModsHeader">
|
||||
<Tr text="downloads.mods_header" />
|
||||
<>
|
||||
<Divider />
|
||||
<div className="HeaderText" id="downloadMenuModsHeader">
|
||||
<Tr text="downloads.mods_header" />
|
||||
</div>
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerMigoto">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelMigoto">
|
||||
<Tr text={'downloads.migoto'} />
|
||||
<HelpButton contents="help.migoto" />
|
||||
</div>
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerMigoto">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelMigoto">
|
||||
<Tr text={'downloads.migoto'} />
|
||||
<HelpButton contents="help.migoto" />
|
||||
</div>
|
||||
<div className="DownloadValue" id="downloadMenuButtonMigoto">
|
||||
<BigButton disabled={this.state.migoto_downloading} onClick={this.downloadMigoto} id="migotoBtn">
|
||||
<Tr text="components.download" />
|
||||
</BigButton>
|
||||
</div>
|
||||
<div className="DownloadValue" id="downloadMenuButtonMigoto">
|
||||
<BigButton disabled={this.state.migoto_downloading} onClick={this.downloadMigoto} id="migotoBtn">
|
||||
<Tr text="components.download" />
|
||||
</BigButton>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,18 @@ import BigButton from '../common/BigButton'
|
||||
import DownloadHandler from '../../../utils/download'
|
||||
import * as meta from '../../../utils/rsa'
|
||||
import HelpButton from '../common/HelpButton'
|
||||
import TextInput from '../common/TextInput'
|
||||
import SmallButton from '../common/SmallButton'
|
||||
import { ask, confirm } from '@tauri-apps/api/dialog'
|
||||
import TextInput from '../common/TextInput'
|
||||
import { unzip } from '../../../utils/zipUtils'
|
||||
import { getGameExecutable } from '../../../utils/game'
|
||||
import { emit } from '@tauri-apps/api/event'
|
||||
|
||||
export enum GrasscutterElevation {
|
||||
None = 'None',
|
||||
Capability = 'Capability',
|
||||
Root = 'Root',
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
closeFn: () => void
|
||||
@@ -33,6 +43,7 @@ interface IState {
|
||||
bg_url_or_path: string
|
||||
themes: string[]
|
||||
theme: string
|
||||
use_theme_background: boolean
|
||||
encryption: boolean
|
||||
patch_rsa: boolean
|
||||
use_internal_proxy: boolean
|
||||
@@ -42,6 +53,13 @@ interface IState {
|
||||
swag: boolean
|
||||
platform: string
|
||||
un_elevated: boolean
|
||||
redirect_more: boolean
|
||||
launch_args: string
|
||||
offline_mode: boolean
|
||||
newer_game: boolean
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: string
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: string
|
||||
@@ -63,6 +81,7 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
bg_url_or_path: '',
|
||||
themes: ['default'],
|
||||
theme: '',
|
||||
use_theme_background: false,
|
||||
encryption: false,
|
||||
patch_rsa: false,
|
||||
use_internal_proxy: false,
|
||||
@@ -72,6 +91,13 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
auto_mongodb: false,
|
||||
platform: '',
|
||||
un_elevated: false,
|
||||
redirect_more: false,
|
||||
launch_args: '',
|
||||
offline_mode: false,
|
||||
newer_game: false,
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: GrasscutterElevation.None,
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: '',
|
||||
@@ -88,8 +114,10 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
this.setCustomBackground = this.setCustomBackground.bind(this)
|
||||
this.toggleEncryption = this.toggleEncryption.bind(this)
|
||||
this.removeRSA = this.removeRSA.bind(this)
|
||||
this.deleteWebCache = this.deleteWebCache.bind(this)
|
||||
this.addMigotoDelay = this.addMigotoDelay.bind(this)
|
||||
this.toggleUnElevatedGame = this.toggleUnElevatedGame.bind(this)
|
||||
this.setLaunchArgs = this.setLaunchArgs.bind(this)
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@@ -114,6 +142,7 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
bg_url_or_path: config.custom_background || '',
|
||||
themes: (await getThemeList()).map((t) => t.name),
|
||||
theme: config.theme || 'default',
|
||||
use_theme_background: config.use_theme_background || false,
|
||||
encryption: encEnabled || false,
|
||||
patch_rsa: config.patch_rsa || false,
|
||||
use_internal_proxy: config.use_internal_proxy || false,
|
||||
@@ -123,6 +152,13 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
auto_mongodb: config.auto_mongodb || false,
|
||||
platform,
|
||||
un_elevated: config.un_elevated || false,
|
||||
redirect_more: config.redirect_more || false,
|
||||
launch_args: config.launch_args,
|
||||
offline_mode: config.offline_mode || false,
|
||||
newer_game: config.newer_game || false,
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: config.grasscutter_elevation || GrasscutterElevation.None,
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: config.akebi_path || '',
|
||||
@@ -133,43 +169,54 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
this.forceUpdate()
|
||||
}
|
||||
|
||||
setGameExecutable(value: string) {
|
||||
setConfigOption('game_install_path', value)
|
||||
async setGameExecutable(value: string) {
|
||||
await setConfigOption('game_install_path', value)
|
||||
|
||||
// I hope this stops people setting launcher.exe because oml it's annoying
|
||||
if (value.endsWith('launcher.exe')) {
|
||||
if (value.endsWith('launcher.exe') || value.endsWith('.lnk')) {
|
||||
const pathArr = value.replace(/\\/g, '/').split('/')
|
||||
pathArr.pop()
|
||||
const path = pathArr.join('/') + '/Genshin Impact Game/'
|
||||
|
||||
alert(
|
||||
`You have set your game execuatable to "launcher.exe". You should not do this. Your game executable is located in:\n\n${path}`
|
||||
)
|
||||
if (value.endsWith('.lnk')) {
|
||||
alert(
|
||||
'You have set your game executable to a shortcut. You should not do this. Your patching will not work, and your proxy may shut off unexpectedly.'
|
||||
)
|
||||
} else {
|
||||
alert(
|
||||
`You have set your game execuatable to "launcher.exe". You should not do this. Your game executable is located in:\n\n${path}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// If setting any other game, automatically set to redirect more
|
||||
if (!value.toLowerCase().includes('genshin') || !value.toLowerCase().includes('yuanshen')) {
|
||||
if (!this.state.redirect_more) {
|
||||
this.toggleOption('redirect_more')
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
game_install_path: value,
|
||||
})
|
||||
|
||||
emit('set_game', { game_path: value })
|
||||
}
|
||||
|
||||
async setGrasscutterJar(value: string) {
|
||||
setConfigOption('grasscutter_path', value)
|
||||
|
||||
this.setState({
|
||||
grasscutter_path: value,
|
||||
})
|
||||
|
||||
const config = await getConfig()
|
||||
const path = config.grasscutter_path.replace(/\\/g, '/')
|
||||
const folderPath = path.substring(0, path.lastIndexOf('/'))
|
||||
const encEnabled = await server.encryptionEnabled(folderPath + '/config.json')
|
||||
|
||||
// Update encryption button when setting new jar
|
||||
this.setState({
|
||||
grasscutter_path: value,
|
||||
encryption: encEnabled,
|
||||
})
|
||||
|
||||
window.location.reload()
|
||||
// Encryption refuses to re-render w/o reload unless updated twice
|
||||
this.forceUpdateEncyption()
|
||||
}
|
||||
|
||||
setJavaPath(value: string) {
|
||||
@@ -247,6 +294,16 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
async forceUpdateEncyption() {
|
||||
const config = await getConfig()
|
||||
const path = config.grasscutter_path.replace(/\\/g, '/')
|
||||
const folderPath = path.substring(0, path.lastIndexOf('/'))
|
||||
|
||||
this.setState({
|
||||
encryption: await server.encryptionEnabled(folderPath + '/config.json'),
|
||||
})
|
||||
}
|
||||
|
||||
async toggleEncryption() {
|
||||
const config = await getConfig()
|
||||
|
||||
@@ -260,6 +317,17 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
const path = config.grasscutter_path.replace(/\\/g, '/')
|
||||
const folderPath = path.substring(0, path.lastIndexOf('/'))
|
||||
|
||||
if (!(await server.encryptionEnabled(folderPath + '/config.json'))) {
|
||||
if (
|
||||
!(await confirm(
|
||||
'Cultivation requires encryption DISABLED to connect and play locally. \n\n Are you sure you want to enable encryption?',
|
||||
'Warning!'
|
||||
))
|
||||
) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
await server.toggleEncryption(folderPath + '/config.json')
|
||||
|
||||
this.setState({
|
||||
@@ -282,11 +350,28 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
})
|
||||
}
|
||||
|
||||
async setGCElevation(value: string) {
|
||||
setConfigOption('grasscutter_elevation', value)
|
||||
|
||||
this.setState({
|
||||
grasscutter_elevation: value,
|
||||
})
|
||||
}
|
||||
|
||||
async removeRSA() {
|
||||
await meta.unpatchGame()
|
||||
}
|
||||
|
||||
async addMigotoDelay() {
|
||||
if (
|
||||
!(await ask(
|
||||
'Set delay for 3dmigoto loader? This is specifically made for GIMI v6 and earlier. Using it on latest GIMI or SRMI will cause issues!!! \n\nWould you like to continue?',
|
||||
{ title: 'GIMI Delay', type: 'warning' }
|
||||
))
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
invoke('set_migoto_delay', {
|
||||
migotoPath: this.state.migoto_path,
|
||||
})
|
||||
@@ -298,6 +383,91 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
})
|
||||
}
|
||||
|
||||
async deleteWebCache() {
|
||||
if (await ask('Would you like to clear login cache? Yes to clear login cache. No to clear web cache.')) {
|
||||
await invoke('wipe_registry', {
|
||||
// The exe is always PascalCase so we can get the dir using regex
|
||||
execName: (await getGameExecutable())?.split('.exe')[0].replace(/([a-z\d])([A-Z])/g, '$1 $2'),
|
||||
})
|
||||
alert('Cleared login cache!')
|
||||
return
|
||||
}
|
||||
|
||||
alert('Cultivation may freeze for a moment while this occurs!')
|
||||
|
||||
// Get webCaches folder path
|
||||
const pathArr = this.state.game_install_path.replace(/\\/g, '/').split('/')
|
||||
pathArr.pop()
|
||||
const path = pathArr.join('/') + '/GenshinImpact_Data/webCaches'
|
||||
const path2 = pathArr.join('/') + '/Yuanshen_Data/webCaches'
|
||||
|
||||
// Delete the folder
|
||||
if (await invoke('dir_exists', { path: path })) {
|
||||
await invoke('dir_delete', { path: path })
|
||||
}
|
||||
if (await invoke('dir_exists', { path: path2 })) {
|
||||
await invoke('dir_delete', { path: path2 })
|
||||
}
|
||||
}
|
||||
|
||||
async fixRes() {
|
||||
const config = await getConfig()
|
||||
|
||||
const path = config.grasscutter_path.replace(/\\/g, '/')
|
||||
let folderPath = path.substring(0, path.lastIndexOf('/'))
|
||||
|
||||
// Set to default if not set
|
||||
if (!path || path === '') {
|
||||
const appdata = await dataDir()
|
||||
folderPath = appdata + 'cultivation\\grasscutter'
|
||||
}
|
||||
|
||||
if (path.includes('/')) {
|
||||
folderPath = path.substring(0, path.lastIndexOf('/'))
|
||||
} else {
|
||||
folderPath = path.substring(0, path.lastIndexOf('\\'))
|
||||
}
|
||||
|
||||
// Check if Grasscutter path exists
|
||||
if (folderPath.length < 1) {
|
||||
alert('Grasscutter not installed or not set! This option can only work when it is installed.')
|
||||
return
|
||||
}
|
||||
|
||||
// Check if resources zip exists
|
||||
if (
|
||||
!(await invoke('dir_exists', {
|
||||
path: folderPath + '\\GC-Resources-4.0.zip',
|
||||
}))
|
||||
) {
|
||||
alert('Resources are already unzipped or do not exist! Ensure your resources zip is named "GC-Resources-4.0.zip"')
|
||||
return
|
||||
}
|
||||
|
||||
alert(
|
||||
'This may fix white screen issues on login! Please be patient while extraction occurs, it may take some time (5-10 minutes). \n\n !! You will be alerted when it is done !!'
|
||||
)
|
||||
|
||||
// Unzip resources
|
||||
await unzip(folderPath + '\\GC-Resources-4.0.zip', folderPath + '\\', true)
|
||||
// Rename folder to resources
|
||||
invoke('rename', {
|
||||
path: folderPath + '\\Resources',
|
||||
newName: 'resources',
|
||||
})
|
||||
|
||||
// Update config.json to read from folder
|
||||
await server.changeResourcePath(folderPath + '/config.json')
|
||||
|
||||
// Check if Grasscutter is running, and restart if so to apply changes
|
||||
if (await invoke('is_grasscutter_running')) {
|
||||
alert('Automatically restarting Grasscutter for changes to apply!')
|
||||
await invoke('restart_grasscutter')
|
||||
}
|
||||
|
||||
alert('Resource fixing finished! Please launch the server again and try playing.')
|
||||
}
|
||||
|
||||
async toggleOption(opt: keyof Configuration) {
|
||||
const changedVal = !(await getConfigOption(opt))
|
||||
|
||||
@@ -309,28 +479,25 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
})
|
||||
}
|
||||
|
||||
async setLaunchArgs(value: string) {
|
||||
await setConfigOption('launch_args', value)
|
||||
|
||||
this.setState({
|
||||
launch_args: value,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Menu closeFn={this.props.closeFn} className="Options" heading="Options">
|
||||
{!this.state.platform || this.state.platform === 'windows' ? (
|
||||
<div className="OptionSection" id="menuOptionsContainerGamePath">
|
||||
<div className="OptionLabel" id="menuOptionsLabelGamePath">
|
||||
<Tr text="options.game_path" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsDirGamePath">
|
||||
<DirInput onChange={this.setGameExecutable} value={this.state?.game_install_path} extensions={['exe']} />
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainerGamePath">
|
||||
<div className="OptionLabel" id="menuOptionsLabelGamePath">
|
||||
<Tr text="options.game_path" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="OptionSection" id="menuOptionsContainerGameCommand">
|
||||
<div className="OptionLabel" id="menuOptionsLabelGameCommand">
|
||||
<Tr text="options.game_command" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsGameCommand">
|
||||
<TextInput />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsDirGamePath">
|
||||
<DirInput onChange={this.setGameExecutable} value={this.state?.game_install_path} extensions={['exe']} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainermetaDownload">
|
||||
<div className="OptionLabel" id="menuOptionsLabelmetaDownload">
|
||||
<Tr text="options.recover_rsa" />
|
||||
@@ -388,6 +555,18 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainerRedirect">
|
||||
<div className="OptionLabel" id="menuOptionsLabelRedirect">
|
||||
<Tr text="options.redirect_more" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsCheckboxRedirect">
|
||||
<Checkbox
|
||||
onChange={() => this.toggleOption('redirect_more')}
|
||||
checked={this.state?.redirect_more}
|
||||
id="RedirectMore"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
@@ -418,6 +597,35 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
</BigButton>
|
||||
</div>
|
||||
</div>
|
||||
{this.state.platform === 'linux' && (
|
||||
<>
|
||||
<Divider />
|
||||
<div className="OptionSection" id="menuOptionsContainerGCElevation">
|
||||
<div className="OptionLabel" id="menuOptionsLabelGCElevation">
|
||||
<Tr text="options.grasscutter_elevation" />
|
||||
<HelpButton contents="help.grasscutter_elevation_help_text" />
|
||||
</div>
|
||||
<select
|
||||
value={this.state.grasscutter_elevation}
|
||||
id="menuOptionsSelectGCElevation"
|
||||
onChange={(event) => {
|
||||
this.setGCElevation(event.target.value)
|
||||
}}
|
||||
>
|
||||
{Object.keys(GrasscutterElevation).map((t) => (
|
||||
<option key={t} value={t}>
|
||||
{t}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainerCheckAAGL">
|
||||
<div className="OptionLabel" id="menuOptionsLabelCheckAAGL">
|
||||
<Tr text="options.check_aagl" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{this.state.swag && (
|
||||
<>
|
||||
<Divider />
|
||||
@@ -434,7 +642,7 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
<Tr text="swag.migoto" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsDirMigoto">
|
||||
<SmallButton onClick={this.addMigotoDelay} id="migotoDelay" contents="help.add_delay"></SmallButton>
|
||||
<SmallButton onClick={this.addMigotoDelay} id="migotoDelay"></SmallButton>
|
||||
<DirInput onChange={this.setMigoto} value={this.state?.migoto_path} extensions={['exe']} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -463,18 +671,20 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainerUEGame">
|
||||
<div className="OptionLabel" id="menuOptionsLabelUEGame">
|
||||
<Tr text="options.un_elevated" />
|
||||
{this.state.platform !== 'linux' && (
|
||||
<div className="OptionSection" id="menuOptionsContainerUEGame">
|
||||
<div className="OptionLabel" id="menuOptionsLabelUEGame">
|
||||
<Tr text="options.un_elevated" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsCheckboxUEGame">
|
||||
<Checkbox
|
||||
onChange={() => this.toggleOption('un_elevated')}
|
||||
checked={this.state?.un_elevated}
|
||||
id="unElevatedGame"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsCheckboxUEGame">
|
||||
<Checkbox
|
||||
onChange={() => this.toggleOption('un_elevated')}
|
||||
checked={this.state?.un_elevated}
|
||||
id="unElevatedGame"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{this.state.swag ? (
|
||||
<div className="OptionSection" id="menuOptionsContainerHorny">
|
||||
<div className="OptionLabel" id="menuOptionsLabelHorny">
|
||||
@@ -489,6 +699,31 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="OptionSection" id="menuOptionsContainerOffline">
|
||||
<div className="OptionLabel" id="menuOptionsLabelOffline">
|
||||
<Tr text="options.offline_mode" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsCheckboxOffline">
|
||||
<Checkbox
|
||||
onChange={() => this.toggleOption('offline_mode')}
|
||||
checked={this.state?.offline_mode}
|
||||
id="offlineMode"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="OptionSection" id="menuOptionsContainerNewerGame">
|
||||
<div className="OptionLabel" id="menuOptionsLabelNewerGame">
|
||||
<Tr text="Patch Mihoyonet" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsCheckboxNewerGame">
|
||||
<Checkbox
|
||||
onChange={() => this.toggleOption('newer_game')}
|
||||
checked={this.state?.newer_game}
|
||||
id="newerGame"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
@@ -513,6 +748,19 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="OptionSection" id="menuOptionsContainerUseThemeBG">
|
||||
<div className="OptionLabel" id="menuOptionsLabelUseThemeBG">
|
||||
<Tr text="options.use_theme_background" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsUseThemeBG">
|
||||
<Checkbox
|
||||
onChange={() => this.toggleOption('use_theme_background')}
|
||||
checked={this.state?.use_theme_background}
|
||||
id="useThemeBG"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="OptionSection" id="menuOptionsContainerJavaPath">
|
||||
@@ -563,6 +811,38 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="OptionSection" id="menuOptionsContainerAdvanced">
|
||||
<div className="OptionLabel" id="menuOptionsLabelWebCache">
|
||||
<Tr text="options.web_cache" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsButtondeleteWebcache">
|
||||
<BigButton onClick={this.deleteWebCache} id="deleteWebcache">
|
||||
<Tr text="components.delete" />
|
||||
</BigButton>
|
||||
</div>
|
||||
<div className="OptionLabel" id="menuOptionsLaunchArgs">
|
||||
<Tr text="options.launch_args" />
|
||||
</div>
|
||||
<TextInput
|
||||
id="launch_args"
|
||||
key="launch_args"
|
||||
placeholder={'-arg=value'}
|
||||
onChange={this.setLaunchArgs}
|
||||
value={this.state.launch_args}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="OptionLabel" id="menuOptionsLabelFixRes">
|
||||
<Tr text="options.fix_res" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsButtonfixRes">
|
||||
<BigButton onClick={this.fixRes} id="fixRes">
|
||||
<Tr text="components.fix" />
|
||||
</BigButton>
|
||||
</div>
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { invoke } from '@tauri-apps/api/tauri'
|
||||
import React from 'react'
|
||||
import Tr from '../../../utils/language'
|
||||
import { getConfig, getConfigOption } from '../../../utils/configuration'
|
||||
|
||||
import './NewsSection.css'
|
||||
|
||||
@@ -10,6 +11,7 @@ interface IProps {
|
||||
}
|
||||
|
||||
interface IState {
|
||||
offline: boolean
|
||||
selected: string
|
||||
news?: JSX.Element
|
||||
commitList?: JSX.Element[]
|
||||
@@ -40,6 +42,7 @@ export default class NewsSection extends React.Component<IProps, IState> {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
offline: false,
|
||||
selected: props.selected || 'commits',
|
||||
}
|
||||
|
||||
@@ -47,7 +50,16 @@ export default class NewsSection extends React.Component<IProps, IState> {
|
||||
this.showNews = this.showNews.bind(this)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
async componentDidMount() {
|
||||
const config = await getConfig()
|
||||
this.setState({
|
||||
offline: config.offline_mode || false,
|
||||
})
|
||||
|
||||
// If offline, don't call news
|
||||
if (this.state.offline) {
|
||||
return
|
||||
}
|
||||
// Call showNews off the bat
|
||||
this.showNews()
|
||||
this.setSelected('commits')
|
||||
@@ -110,6 +122,11 @@ export default class NewsSection extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
async showNews() {
|
||||
const offline_mode = await getConfigOption('offline_mode')
|
||||
if (offline_mode) {
|
||||
return
|
||||
}
|
||||
|
||||
let news: JSX.Element | JSX.Element[] = <tr></tr>
|
||||
|
||||
switch (this.state.selected) {
|
||||
@@ -124,7 +141,10 @@ export default class NewsSection extends React.Component<IProps, IState> {
|
||||
case 'latest_version':
|
||||
news = (
|
||||
<tr>
|
||||
<td>Latest version: Grasscutter 1.5.0 - Cultivation 1.1.1</td>
|
||||
<td>
|
||||
Work in progress area! These numbers may be outdated, so please do not use them as reference. Latest
|
||||
version: Grasscutter 1.7.4 - Cultivation 1.5.1
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
break
|
||||
@@ -144,6 +164,10 @@ export default class NewsSection extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.offline) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="NewsSection" id="newsContainer">
|
||||
<div className="NewsTabs" id="newsTabsContainer">
|
||||
|
||||
@@ -16,6 +16,7 @@ let defaultConfig: Configuration
|
||||
last_port: '443',
|
||||
language: 'en',
|
||||
custom_background: '',
|
||||
use_theme_background: false,
|
||||
cert_generated: false,
|
||||
theme: 'default',
|
||||
https_enabled: false,
|
||||
@@ -26,6 +27,13 @@ let defaultConfig: Configuration
|
||||
horny_mode: false,
|
||||
auto_mongodb: false,
|
||||
un_elevated: false,
|
||||
redirect_more: false,
|
||||
launch_args: '',
|
||||
offline_mode: false,
|
||||
newer_game: false,
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: 'None',
|
||||
}
|
||||
})()
|
||||
|
||||
@@ -44,6 +52,7 @@ export interface Configuration {
|
||||
last_port: string
|
||||
language: string
|
||||
custom_background: string
|
||||
use_theme_background: boolean
|
||||
cert_generated: boolean
|
||||
theme: string
|
||||
https_enabled: boolean
|
||||
@@ -55,6 +64,13 @@ export interface Configuration {
|
||||
swag_mode?: boolean
|
||||
auto_mongodb: boolean
|
||||
un_elevated: boolean
|
||||
redirect_more: boolean
|
||||
launch_args: string
|
||||
offline_mode: boolean
|
||||
newer_game: boolean
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: string
|
||||
|
||||
// Swag stuff
|
||||
akebi_path?: string
|
||||
|
||||
@@ -73,6 +73,11 @@ export default class DownloadHandler {
|
||||
const index = this.downloads.findIndex((download) => download.path === errorData.path)
|
||||
this.downloads[index].status = 'error'
|
||||
this.downloads[index].error = errorData.error
|
||||
|
||||
// Remove GIMI from list as fallback will replace it
|
||||
if (errorData.path.includes('GIMI.zip')) {
|
||||
this.downloads.splice(index, 1)
|
||||
}
|
||||
})
|
||||
|
||||
// Extraction events
|
||||
@@ -92,6 +97,9 @@ export default class DownloadHandler {
|
||||
// Find the download that is not extracting and set it's status as such
|
||||
const index = this.downloads.findIndex((download) => download.path === obj.file)
|
||||
this.downloads[index].status = 'finished'
|
||||
|
||||
// Remove completed extraction from list
|
||||
this.downloads.splice(index, 1)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,30 @@ export async function getGameVersion() {
|
||||
return null
|
||||
}
|
||||
|
||||
const hasAsb = await invoke('dir_exists', {
|
||||
path: GameData + '\\StreamingAssets\\asb_settings.json',
|
||||
})
|
||||
|
||||
if (!hasAsb) {
|
||||
// For games that cannot determine game version
|
||||
const otherGameVer: string = await invoke('read_file', {
|
||||
path: GameData + '\\StreamingAssets\\BinaryVersion.bytes',
|
||||
})
|
||||
const versionRaw = otherGameVer.split('.')
|
||||
const version = {
|
||||
major: parseInt(versionRaw[0]),
|
||||
minor: parseInt(versionRaw[1]),
|
||||
// This will probably never matter, just use major/minor. If needed, full version values are near EOF
|
||||
release: 0,
|
||||
}
|
||||
|
||||
if (otherGameVer == null || otherGameVer.length < 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
const settings = JSON.parse(
|
||||
await invoke('read_file', {
|
||||
path: GameData + '\\StreamingAssets\\asb_settings.json',
|
||||
|
||||
@@ -65,7 +65,7 @@ export default class Tr extends React.Component<IProps, IState> {
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
translated_text: translation_obj[text] || '',
|
||||
translated_text: translation_obj[text] || text,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +1,10 @@
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { getGameFolder } from './game'
|
||||
// Patch file from: https://github.com/34736384/RSAPatch/
|
||||
|
||||
export async function patchGame() {
|
||||
const patchPath = (await invoke('install_location')) + '\\patch\\version.dll'
|
||||
// Are we already patched with mhypbase? If so, that's fine, just continue as normal
|
||||
const gameIsPatched = await invoke('are_files_identical', {
|
||||
path1: patchPath,
|
||||
path2: (await getGameRSAPath()) + '\\mhypbase.dll',
|
||||
})
|
||||
|
||||
// Tell user they won't be unpatched with manual mhypbase patch
|
||||
if (gameIsPatched) {
|
||||
console.log('You are already patched using mhypbase, so you will not be auto patched and unpatched!')
|
||||
return true
|
||||
}
|
||||
|
||||
// Copy the patch to game files
|
||||
const replaced = await invoke('copy_file_with_new_name', {
|
||||
path: patchPath,
|
||||
newPath: await getGameRSAPath(),
|
||||
newName: 'version.dll',
|
||||
})
|
||||
|
||||
if (!replaced) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
export async function patchGame(newerGame: boolean, version: string) {
|
||||
return invoke('patch_game', { newerGame, version })
|
||||
}
|
||||
|
||||
export async function unpatchGame() {
|
||||
// Just delete patch since it's not replacing any existing file
|
||||
const deleted = await invoke('delete_file', {
|
||||
path: (await getGameRSAPath()) + '\\version.dll',
|
||||
})
|
||||
|
||||
return deleted
|
||||
}
|
||||
|
||||
export async function getGameRSAPath() {
|
||||
const gameData = await getGameFolder()
|
||||
|
||||
if (!gameData) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (gameData + '\\').replace(/\\/g, '/')
|
||||
return invoke('unpatch_game')
|
||||
}
|
||||
|
||||
@@ -40,5 +40,32 @@ export async function encryptionEnabled(path: string) {
|
||||
return false
|
||||
}
|
||||
|
||||
return serverConf.server.http.encryption.useEncryption
|
||||
if ('server' in serverConf) {
|
||||
return serverConf.server.http.encryption.useEncryption
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export async function changeResourcePath(path: string) {
|
||||
let serverConf
|
||||
|
||||
try {
|
||||
serverConf = JSON.parse(
|
||||
await invoke('read_file', {
|
||||
path,
|
||||
})
|
||||
)
|
||||
} catch (e) {
|
||||
console.log(`Server config at ${path} not found or invalid. Be sure to run the server at least once to generate it`)
|
||||
return
|
||||
}
|
||||
|
||||
serverConf.folderStructure.resources = './resources/'
|
||||
|
||||
// Write file
|
||||
await invoke('write_file', {
|
||||
path,
|
||||
contents: JSON.stringify(serverConf, null, 2),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -115,8 +115,8 @@ export async function loadTheme(theme: ThemeList, document: Document) {
|
||||
|
||||
// Set custom background
|
||||
if (theme.customBackgroundURL) {
|
||||
// If the custom bg is already set don't overwrite
|
||||
if (config.custom_background === '') {
|
||||
// If the custom bg is already set don't overwrite unless user wants to force the new background
|
||||
if (config.custom_background === '' || config.use_theme_background) {
|
||||
config.custom_background = theme.customBackgroundURL
|
||||
}
|
||||
}
|
||||
@@ -133,8 +133,8 @@ export async function loadTheme(theme: ThemeList, document: Document) {
|
||||
})
|
||||
|
||||
// Set the background
|
||||
// If the custom bg is already set don't overwrite
|
||||
if (config.custom_background === '') {
|
||||
// If the custom bg is already set don't overwrite unless user wants to force the new background
|
||||
if (config.custom_background === '' || config.use_theme_background) {
|
||||
config.custom_background = bgPath + imageName
|
||||
}
|
||||
}
|
||||
|
||||
185
yarn.lock
185
yarn.lock
@@ -26,6 +26,14 @@
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.18.6"
|
||||
|
||||
"@babel/code-frame@^7.22.13":
|
||||
version "7.22.13"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
|
||||
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.22.13"
|
||||
chalk "^2.4.2"
|
||||
|
||||
"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.18.8":
|
||||
version "7.18.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
|
||||
@@ -70,6 +78,16 @@
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/generator@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
|
||||
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.23.0"
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
"@jridgewell/trace-mapping" "^0.3.17"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
|
||||
@@ -135,6 +153,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
|
||||
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
|
||||
|
||||
"@babel/helper-environment-visitor@^7.22.20":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
|
||||
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
|
||||
|
||||
"@babel/helper-explode-assignable-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
|
||||
@@ -150,6 +173,14 @@
|
||||
"@babel/template" "^7.18.6"
|
||||
"@babel/types" "^7.18.9"
|
||||
|
||||
"@babel/helper-function-name@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
|
||||
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
|
||||
dependencies:
|
||||
"@babel/template" "^7.22.15"
|
||||
"@babel/types" "^7.23.0"
|
||||
|
||||
"@babel/helper-hoist-variables@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
|
||||
@@ -157,6 +188,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-hoist-variables@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
|
||||
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
|
||||
@@ -239,11 +277,28 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-split-export-declaration@^7.22.6":
|
||||
version "7.22.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
|
||||
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/helper-string-parser@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
|
||||
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
|
||||
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.22.20":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
|
||||
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||
|
||||
"@babel/helper-validator-option@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
|
||||
@@ -277,11 +332,25 @@
|
||||
chalk "^2.0.0"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/highlight@^7.22.13":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
|
||||
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
chalk "^2.4.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.6", "@babel/parser@^7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
|
||||
integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
|
||||
|
||||
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
|
||||
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
|
||||
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
|
||||
@@ -1043,19 +1112,28 @@
|
||||
"@babel/parser" "^7.18.6"
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98"
|
||||
integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==
|
||||
"@babel/template@^7.22.15":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
|
||||
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.18.6"
|
||||
"@babel/generator" "^7.18.9"
|
||||
"@babel/helper-environment-visitor" "^7.18.9"
|
||||
"@babel/helper-function-name" "^7.18.9"
|
||||
"@babel/helper-hoist-variables" "^7.18.6"
|
||||
"@babel/helper-split-export-declaration" "^7.18.6"
|
||||
"@babel/parser" "^7.18.9"
|
||||
"@babel/types" "^7.18.9"
|
||||
"@babel/code-frame" "^7.22.13"
|
||||
"@babel/parser" "^7.22.15"
|
||||
"@babel/types" "^7.22.15"
|
||||
|
||||
"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2":
|
||||
version "7.23.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
|
||||
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.22.13"
|
||||
"@babel/generator" "^7.23.0"
|
||||
"@babel/helper-environment-visitor" "^7.22.20"
|
||||
"@babel/helper-function-name" "^7.23.0"
|
||||
"@babel/helper-hoist-variables" "^7.22.5"
|
||||
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||
"@babel/parser" "^7.23.0"
|
||||
"@babel/types" "^7.23.0"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
@@ -1067,6 +1145,15 @@
|
||||
"@babel/helper-validator-identifier" "^7.18.6"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
|
||||
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.22.5"
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
@@ -1446,6 +1533,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||
|
||||
"@jridgewell/resolve-uri@^3.1.0":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
|
||||
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
|
||||
|
||||
"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||
@@ -1464,6 +1556,19 @@
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.14":
|
||||
version "1.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
|
||||
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.17":
|
||||
version "0.3.20"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
|
||||
integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
|
||||
@@ -2986,7 +3091,7 @@ case-sensitive-paths-webpack-plugin@^2.4.0:
|
||||
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
|
||||
integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==
|
||||
|
||||
chalk@^2.0.0, chalk@^2.4.1:
|
||||
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
@@ -4875,9 +4980,9 @@ http-proxy-agent@^4.0.1:
|
||||
debug "4"
|
||||
|
||||
http-proxy-middleware@^2.0.3:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f"
|
||||
integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz#915f236d92ae98ef48278a95dedf17e991936ec6"
|
||||
integrity sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==
|
||||
dependencies:
|
||||
"@types/http-proxy" "^1.17.8"
|
||||
http-proxy "^1.18.1"
|
||||
@@ -7381,6 +7486,11 @@ qs@6.10.3:
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
querystringify@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
|
||||
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
|
||||
|
||||
queue-microtask@^1.2.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
@@ -7925,14 +8035,14 @@ semver@7.0.0:
|
||||
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
|
||||
|
||||
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
version "6.3.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.3.2, semver@^7.3.5, semver@^7.3.7:
|
||||
version "7.3.7"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
|
||||
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
@@ -8568,13 +8678,14 @@ toidentifier@1.0.1:
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
tough-cookie@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
|
||||
integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
|
||||
integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
|
||||
dependencies:
|
||||
psl "^1.1.33"
|
||||
punycode "^2.1.1"
|
||||
universalify "^0.1.2"
|
||||
universalify "^0.2.0"
|
||||
url-parse "^1.5.3"
|
||||
|
||||
tr46@^1.0.1:
|
||||
version "1.0.1"
|
||||
@@ -8716,10 +8827,10 @@ unique-string@^2.0.0:
|
||||
dependencies:
|
||||
crypto-random-string "^2.0.0"
|
||||
|
||||
universalify@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
||||
universalify@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
|
||||
integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -8756,6 +8867,14 @@ uri-js@^4.2.2:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
url-parse@^1.5.3:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
|
||||
integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
|
||||
dependencies:
|
||||
querystringify "^2.1.1"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
@@ -9041,9 +9160,9 @@ which@^2.0.1:
|
||||
isexe "^2.0.0"
|
||||
|
||||
word-wrap@^1.2.3, word-wrap@~1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
|
||||
integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
|
||||
|
||||
workbox-background-sync@6.5.3:
|
||||
version "6.5.3"
|
||||
|
||||
Reference in New Issue
Block a user