Compare commits

...

122 Commits

Author SHA1 Message Date
SpikeHD
a29fdf3d9c fix(all): version bump 2023-09-07 17:47:15 -07:00
SpikeHD
a86055cce9 Merge pull request #195 from fnr1r/linux/main
Linux support
2023-09-07 17:20:26 -07:00
SpikeHD
014641307e Merge pull request #198 from root-mega/main
Fix spanish translation
2023-09-01 12:02:38 -07:00
mega
51da474b2a Fix spanish translation 2023-09-01 20:58:01 +02:00
mega
97bbfea694 Update es.json 2023-09-01 20:51:45 +02:00
SpikeHD
1d4cf94643 Merge pull request #197 from NotThorny/Config-Fix
Fix crashing on null configs
2023-08-30 12:24:44 -07:00
Thoronium
843913a664 Fix crashing on null configs 2023-08-29 15:54:09 -06:00
fnrir
3875599c5f Implement CA installation 2023-08-23 15:36:16 +02:00
fnrir
bc1df1f5e1 Make sure it's safe to run the game 2023-08-23 15:36:16 +02:00
fnrir
4ea9df5db7 Implement wipe_registry 2023-08-23 15:36:16 +02:00
fnrir
b81beb0971 Add generic version of run_un_elevated 2023-08-23 15:36:16 +02:00
fnrir
62b54f33df Add an option that allows binding port 443
Kinda everts some changes of
"Implement MongoDB autostart and GC watching".
This commit makes launching MongoDB async
2023-08-23 15:36:16 +02:00
fnrir
2c07cf90bd Implement MongoDB autostart and GC watching
Windows's implementation of enable_grasscutter_watcher works just fine.
systemd is pretty much standart for handling services.
No "sudo" or "pkexec" is needed, systemd does that automatically, but
since the user needs to authenticate, we can’t await service_status.
2023-08-23 15:36:16 +02:00
fnrir
b179ccc1f0 Add Linux version of run_jar
This might not work on macOS
2023-08-23 15:36:16 +02:00
fnrir
699eb2838e Implement patching
Quick note: Patching works, but the launcher attempts to unpatch the
game two times.
2023-08-23 15:36:16 +02:00
fnrir
3ecc4f4231 Implement launching the game on Linux 2023-08-23 15:36:16 +02:00
fnrir
ef576e36b8 Hide un_elevated toggle on Linux 2023-08-18 15:29:40 +02:00
fnrir
75f3e829d5 Removed root requirement
Also disabled install_ca_files since this causes crashes when not run as
root
2023-08-18 15:29:40 +02:00
fnrir
dbbbb6603d Fix loading icons on Linux
On Linux URLs to app resources start with tauri://localhost instead of
https://tauri.localhost
2023-08-18 15:29:40 +02:00
fnrir
74c6dd6792 Use different resource path in certain cases
This is janky, but does not require AppHandle.
2023-08-18 15:29:40 +02:00
fnrir
ee9fe9e0a7 Fix empty game install path on Linux 2023-08-18 15:29:40 +02:00
SpikeHD
09f5e74b51 Merge pull request #193 from maximuslotro/main
Add Toggle to use theme BG in options menu
2023-08-14 23:16:10 -07:00
maximuslotro
a31bc46c39 Add Toggle to use theme BG in options menu 2023-08-15 00:15:22 -05:00
SpikeHD
a9b1fa0130 Merge pull request #188 from Grasscutters/dependabot/npm_and_yarn/semver-6.3.1
Bump semver from 6.3.0 to 6.3.1
2023-07-20 21:17:47 -07:00
SpikeHD
7d92586210 Merge pull request #187 from Grasscutters/dependabot/npm_and_yarn/tough-cookie-4.1.3
Bump tough-cookie from 4.0.0 to 4.1.3
2023-07-20 21:17:35 -07:00
SpikeHD
9f73883d59 Merge pull request #189 from Grasscutters/dependabot/npm_and_yarn/word-wrap-1.2.4
Bump word-wrap from 1.2.3 to 1.2.4
2023-07-20 21:17:22 -07:00
dependabot[bot]
3fee55a30b Bump word-wrap from 1.2.3 to 1.2.4
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-19 18:38:52 +00:00
dependabot[bot]
98661d1b2c Bump semver from 6.3.0 to 6.3.1
Bumps [semver](https://github.com/npm/node-semver) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v6.3.1/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v6.3.0...v6.3.1)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 09:46:11 +00:00
dependabot[bot]
ab22379694 Bump tough-cookie from 4.0.0 to 4.1.3
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.0.0 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.0.0...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-09 17:59:49 +00:00
SpikeHD
e4647a5811 Merge pull request #182 from Grasscutters/dependabot/cargo/src-tauri/openssl-0.10.55
Bump openssl from 0.10.52 to 0.10.55 in /src-tauri
2023-07-01 18:52:55 -07:00
SpikeHD
d94dbcf384 Merge pull request #186 from fnr1r/slashes
QOL and path changes
2023-06-28 11:49:20 -07:00
fnrir
b56ad4e465 Increase read_file verbosity
Changed the error message that gets printed when
Culti tries to read a file, but fails.
2023-06-27 10:51:35 +02:00
fnrir
b9b0929668 Fix trying to open nonexistant config
If you try to open settings, or change the
"Toggle Encryption" toggle, while GC's server
config does not exist it no longer throws an
error message.
2023-06-27 10:50:55 +02:00
fnrir
3ba467d03b Fix paths
Replaced backslashes in paths with slashes. I did
not touch function that do the same with paths.
Those can be removed manually.
Also dataDir() returns a path that ends with a
slash so I got rid of duplicated slashes.
2023-06-27 10:35:37 +02:00
SpikeHD
882bad370f Merge pull request #185 from fnr1r/lang-pl
Add Polish translation
2023-06-26 15:04:33 -07:00
fnrir
3eec0e4a11 Add Polish translation 2023-06-26 11:40:19 +02:00
SpikeHD
9798f6d0d3 Merge pull request #184 from NotThorny/Redirect-more-2
Update more redirecting
2023-06-25 14:35:40 -07:00
SpikeHD
a76f90c1d8 Merge pull request #183 from iidoki/main
Add italian language support
2023-06-25 13:31:16 -07:00
Thoronium
f1ecb1aab0 Fix handling 2023-06-25 14:25:14 -06:00
Thoronium
7c9b2f7335 Auto redirect more when setting other game 2023-06-25 14:25:13 -06:00
Thoronium
38436472e3 Skip patching on other anime games 2023-06-25 14:25:13 -06:00
Thoronium
db6f23dbad Update intercepts 2023-06-25 14:25:13 -06:00
laura o3o
d9dfb6ac4e Update it.json 2023-06-25 21:55:00 +02:00
laura o3o
981cb3180e Update it.json 2023-06-25 21:44:15 +02:00
laura o3o
d5187cb5d6 Create it.json 2023-06-25 21:34:51 +02:00
dependabot[bot]
5a1e7d105c Bump openssl from 0.10.52 to 0.10.55 in /src-tauri
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.52 to 0.10.55.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.52...openssl-v0.10.55)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-21 22:57:02 +00:00
SpikeHD
26d7ac2b11 Merge pull request #181 from NotThorny/Redirect-More
Redirect more domains
2023-06-18 20:36:47 -07:00
Thoronium
6b07ccf1b5 Add CLI flag 2023-06-18 21:31:08 -06:00
Thoronium
f6856431bd Update langs pt.2 2023-06-18 16:46:03 -06:00
Thoronium
f7e33d5035 Update langs 2023-06-18 16:29:33 -06:00
Thoronium
190adb1d52 Redirect more domains 2023-06-18 16:10:22 -06:00
SpikeHD
742a24df11 Merge pull request #180 from NotThorny/DL-Menu
Fix downloads menu
2023-06-09 15:06:37 -07:00
Thoronium
06e48e06b6 Remove unstable dl
Add back questing aio
2023-06-09 15:30:19 -06:00
SpikeHD
87b97c6824 fix: version bumps 2023-06-06 18:13:53 -07:00
SpikeHD
8b779bcb6b Merge pull request #179 from NotThorny/Res-Api
Update resources link
2023-06-06 18:10:10 -07:00
SpikeHD
fc7fb739e7 if I keep forgetting to re-set this I am going to explode 2023-06-06 18:08:28 -07:00
SpikeHD
044be37e9e fix: proper language export and restyle of game path notification 2023-06-06 18:07:54 -07:00
Thoronium
6f40e1789b Update link 2023-06-06 19:02:26 -06:00
SpikeHD
fe974a1ae1 Merge pull request #178 from Grasscutters/dependabot/cargo/src-tauri/xml-rs-0.8.14
Bump xml-rs from 0.8.4 to 0.8.14 in /src-tauri
2023-06-06 17:55:40 -07:00
SpikeHD
b5e48b6998 Merge branch 'main' of github.com:Grasscutters/Cultivation 2023-06-06 17:33:48 -07:00
SpikeHD
ed9fb9a644 fix: remove duct 2023-06-06 17:33:36 -07:00
dependabot[bot]
be3a1c6f6f Bump xml-rs from 0.8.4 to 0.8.14 in /src-tauri
Bumps [xml-rs](https://github.com/kornelski/xml-rs) from 0.8.4 to 0.8.14.
- [Changelog](https://github.com/kornelski/xml-rs/blob/main/Changelog.md)
- [Commits](https://github.com/kornelski/xml-rs/compare/0.8.4...0.8.14)

---
updated-dependencies:
- dependency-name: xml-rs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-06 02:25:39 +00:00
SpikeHD
158c82d959 Fix Thoros CATASTROPHIC mistake 2023-05-31 14:32:54 -07:00
SpikeHD
4cb8a27a9c Merge pull request #177 from wehigami/main
Final pull request for set game path notification
2023-05-31 08:55:06 -07:00
SpikeHD
9d26f6f146 Update src/ui/Main.tsx
Co-authored-by: Thoronium <107363768+NotThorny@users.noreply.github.com>
2023-05-31 08:54:47 -07:00
SpikeHD
277f009883 Update src/ui/Main.tsx
Co-authored-by: Thoronium <107363768+NotThorny@users.noreply.github.com>
2023-05-31 08:54:41 -07:00
Erik
05caa7c7a3 Update src/ui/Main.tsx
Co-authored-by: Thoronium <107363768+NotThorny@users.noreply.github.com>
2023-05-27 14:21:18 +00:00
Wehi
681c1fce3e final commit 2023-05-26 06:12:15 +02:00
SpikeHD
06e1ca23e1 csp for style/script elements 2023-05-20 16:58:29 -07:00
SpikeHD
053b4760b1 Merge pull request #170 from loulou310/main
Fix and update french TL
2023-05-17 17:14:42 -07:00
Xotak
79aa4ca61d Fix and update french TL 2023-05-17 10:45:41 +02:00
SpikeHD
bf4c1d87e8 Merge pull request #169 from NotThorny/Admin-Fix
Re-open as admin
2023-05-16 13:10:50 -07:00
Thoronium
3205c96a62 Open as admin
Set migoto exe when dl from menu
2023-05-16 13:56:40 -06:00
SpikeHD
d551344f39 version bump 2023-05-14 22:07:12 -07:00
SpikeHD
84a6267c65 Merge pull request #167 from NotThorny/All-in-Quest
Add questing all-in-one
2023-05-14 22:01:21 -07:00
Thoronium
4c9e70a8f8 Add questing all-in-one
Also fix GIMI v7 setting
2023-05-14 22:54:14 -06:00
SpikeHD
87897aabec remove logging 2023-05-14 21:37:57 -07:00
SpikeHD
acb9061d1c fix theme loading 2023-05-14 21:37:26 -07:00
SpikeHD
a954fcfc1c Merge branch 'main' of github.com:Grasscutters/Cultivation 2023-05-12 17:36:47 -07:00
SpikeHD
13dcbcd361 fix checkbox visibility 2023-05-12 17:36:07 -07:00
SpikeHD
302754d486 closing without waiting should still disconnect 2023-05-12 17:35:51 -07:00
dependabot[bot]
c2cbf4049e Bump h2 from 0.3.13 to 0.3.18 in /src-tauri
Bumps [h2](https://github.com/hyperium/h2) from 0.3.13 to 0.3.18.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.13...v0.3.18)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-10 21:41:28 -07:00
dependabot[bot]
554bda4643 Bump openssl from 0.10.41 to 0.10.52 in /src-tauri
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.41 to 0.10.52.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.41...openssl-v0.10.52)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-10 21:41:20 -07:00
SpikeHD
d1018c249e Merge pull request #165 from Grasscutters/dependabot/cargo/src-tauri/tauri-1.0.9
Bump tauri from 1.0.8 to 1.0.9 in /src-tauri
2023-05-10 19:47:29 -07:00
dependabot[bot]
0df78f35bd Bump tauri from 1.0.8 to 1.0.9 in /src-tauri
Bumps [tauri](https://github.com/tauri-apps/tauri) from 1.0.8 to 1.0.9.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/tauri-v1.0.8...tauri-v1.0.9)

---
updated-dependencies:
- dependency-name: tauri
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-11 01:19:36 +00:00
SpikeHD
fb60889857 Merge pull request #137 from Grasscutters/dependabot/npm_and_yarn/webpack-5.76.1
Bump webpack from 5.73.0 to 5.76.1
2023-05-10 18:19:28 -07:00
SpikeHD
9516c78871 Merge pull request #126 from Grasscutters/dependabot/cargo/src-tauri/bumpalo-3.12.0
Bump bumpalo from 3.10.0 to 3.12.0 in /src-tauri
2023-05-10 18:19:14 -07:00
SpikeHD
2a45f35062 Merge pull request #125 from Grasscutters/dependabot/cargo/src-tauri/bzip2-0.4.4
Bump bzip2 from 0.4.3 to 0.4.4 in /src-tauri
2023-05-10 18:19:06 -07:00
SpikeHD
ba12ab6586 Merge pull request #124 from Grasscutters/dependabot/npm_and_yarn/json5-1.0.2
Bump json5 from 1.0.1 to 1.0.2
2023-05-10 18:18:51 -07:00
SpikeHD
0c37493d2a Merge pull request #120 from Grasscutters/dependabot/npm_and_yarn/decode-uri-component-0.2.2
Bump decode-uri-component from 0.2.0 to 0.2.2
2023-05-10 18:18:24 -07:00
SpikeHD
c8a368235c Merge pull request #158 from wehigami/main
CSS Tweaks
2023-05-10 18:02:22 -07:00
SpikeHD
c2587cc923 Merge branch 'main' into main 2023-05-10 18:02:02 -07:00
Wehi
00929a3efe backdrop blur full functioning 2023-05-11 02:56:20 +02:00
Wehi
ce78bf69aa added back backdrop blur, fixed button size issue 2023-05-11 02:46:30 +02:00
SpikeHD
732e020eb3 Merge pull request #162 from NotThorny/Fix-Overlap
Fix overlap on resize
2023-05-10 14:15:26 -07:00
Thoronium
114a1d2023 Merge branch 'main' into Fix-Overlap 2023-05-10 13:38:41 -06:00
Thoronium
3ed197b4b4 Prettier 2023-05-10 13:34:57 -06:00
SpikeHD
eed59e7883 Merge pull request #161 from NotThorny/Fix-PortHelp
Fix port help box
2023-05-10 12:04:08 -07:00
Thoronium
5b9af3fcce Fix bar overlap on resize 2023-05-10 13:03:13 -06:00
Thoronium
b9b8632992 Fix port help box 2023-05-10 12:59:23 -06:00
Wehi
878dfed932 slight changes to Big Button css and Launch button font-weight 2023-05-10 16:13:55 +02:00
Wehi
15e6958527 Added transition to socials images 2023-05-10 15:06:04 +02:00
Wehi
36b3c2f841 Taken spikes feedback into account. Removed backdrop blur anyway due to my friends feedback, added shadow gradient for better button visibility. Lmk whether or not to still keep the backdrop blur. 2023-05-10 15:03:29 +02:00
Wehi
c6abf53880 BottomBar elements now align to right 2023-05-10 03:15:48 +02:00
Wehi
9dcaea7e5b Deleted the welcome message cause my friends said it sucks 2023-05-10 02:31:42 +02:00
Wehi
f4b8cdf732 Launch button stylized to look clearer. WIP on moving all the launch elements to the right for better readability. 2023-05-10 02:19:44 +02:00
Wehi
ed743b2ff9 added background to make the welcome text more visible 2023-05-10 02:02:44 +02:00
Wehi
776aee0265 Added a welcome message to the rightbar in order to make it look more comfy 2023-05-10 01:57:36 +02:00
Wehi
f508b3f0cf RightBar resembles the official release 2023-05-10 01:45:31 +02:00
Moistcrafter
5bad4d05ee Update README.md 2023-05-04 18:42:20 -07:00
SpikeHD
f53d903a8b Update README.md 2023-04-30 15:24:10 -07:00
SpikeHD
47b15fc2ff Merge pull request #156 from NotThorny/Linting
Lints
2023-04-28 13:07:30 -07:00
Thoronium
bdb0fd3eb7 Small lints 2023-04-28 13:52:24 -06:00
Thoronium
4631a6d38d Formatting 2023-04-28 13:11:06 -06:00
SpikeHD
b34f71a301 Merge pull request #155 from NotThorny/UpdateDeps
Update deps
2023-04-28 11:59:29 -07:00
Thoronium
dea373a0d5 Update deps 2023-04-26 22:46:21 -06:00
Thoronium
cab19e64c4 Update dependency 2023-04-26 22:46:21 -06:00
dependabot[bot]
420e437788 Bump webpack from 5.73.0 to 5.76.1
Bumps [webpack](https://github.com/webpack/webpack) from 5.73.0 to 5.76.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.73.0...v5.76.1)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-15 03:14:14 +00:00
dependabot[bot]
6f1f55663b Bump bumpalo from 3.10.0 to 3.12.0 in /src-tauri
Bumps [bumpalo](https://github.com/fitzgen/bumpalo) from 3.10.0 to 3.12.0.
- [Release notes](https://github.com/fitzgen/bumpalo/releases)
- [Changelog](https://github.com/fitzgen/bumpalo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fitzgen/bumpalo/compare/3.10.0...3.12.0)

---
updated-dependencies:
- dependency-name: bumpalo
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-20 22:13:35 +00:00
dependabot[bot]
f3f5dc95ae Bump bzip2 from 0.4.3 to 0.4.4 in /src-tauri
Bumps [bzip2](https://github.com/alexcrichton/bzip2-rs) from 0.4.3 to 0.4.4.
- [Release notes](https://github.com/alexcrichton/bzip2-rs/releases)
- [Commits](https://github.com/alexcrichton/bzip2-rs/commits/0.4.4)

---
updated-dependencies:
- dependency-name: bzip2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-10 22:30:14 +00:00
dependabot[bot]
470ddb0598 Bump json5 from 1.0.1 to 1.0.2
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-08 23:21:55 +00:00
dependabot[bot]
cf267657dd Bump decode-uri-component from 0.2.0 to 0.2.2
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-09 07:05:22 +00:00
49 changed files with 2201 additions and 619 deletions

View File

@@ -1,3 +1,3 @@
{
"rust-analyzer.linkedProjects": [".\\src-tauri\\Cargo.toml"]
"rust-analyzer.linkedProjects": ["src-tauri/Cargo.toml"]
}

View File

@@ -29,7 +29,7 @@ For game versions 3.1 and above, Cultivation automatically makes a small patch t
Download and open the MSI, and once installed, run Cultivation as administrator. Refer below for more [detailed setup instructions](#setup).
**Windows 7 Users:** You will need to download [WebView](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section) manually, and download the `.zip` instead of the `.msi`.
**Windows 7 Users:** You will need to download [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section) manually, and download the `.zip` instead of the `.msi`.
# Setup
@@ -37,7 +37,7 @@ Download and open the MSI, and once installed, run Cultivation as administrator.
- Download Cultivation
- If you are on Windows 10 or 11, use the MSI
- If you are on Windows 7, or the MSI doesn't work, use the zip and download [WebView](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)
- If you are on Windows 7, or the MSI doesn't work, use the zip and download [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)
- If you are on GNU/Linux or MacOS, [help us port Windows-specific system calls to GNU/Linux and MacOS!](https://github.com/Grasscutters/Cultivation/issues/7)
- Install or extract Cultivation
- Open Cultivation **_as administrator_**
@@ -79,7 +79,7 @@ Please allow the Cultivation window to pop back up once you have quit out of the
- Install [yarn](https://classic.yarnpkg.com/lang/en/docs/install) (cry about it `npm` lovers)
- Install [Rust](https://www.rust-lang.org/tools/install)
- `yarn install`
- `yarn start:dev`
- `yarn tauri dev`
### Building

View File

@@ -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 |

645
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "cultivation"
version = "0.1.0"
version = "1.2.0"
description = "A custom launcher for anime game."
authors = ["KingRainbow44", "SpikeHD"]
license = ""
@@ -22,16 +22,22 @@ 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.7", features = ["api-all"] }
tauri = { version = "1.0.9", features = ["api-all"] }
# Arg parsing
args = "2.0"
getopts = "0.2"
# Access system process info.
sysinfo = "0.24.6"
sysinfo = "0.28.4"
# ZIP-archive library.
zip-extract = "0.1.1"
@@ -44,7 +50,6 @@ once_cell = "1.13.0"
# Program opener.
open = "3.0.2"
duct = "0.13.5"
# Services
windows-service = "0.6.0"
@@ -54,11 +59,11 @@ 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"
tokio = { version = "1.18.2", features = ["signal"] }
tokio = { version = "1.20.4", features = ["signal"] }
rustls-pemfile = "1.0.0"
reqwest = { version = "0.11.3", features = ["stream"] }
futures-util = "0.3.14"
@@ -72,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

View File

@@ -8,7 +8,8 @@
"ip_placeholder": "IP 地址...",
"port_placeholder": "端口...",
"files_downloading": "文件下载中:",
"files_extracting": "文件解压中:"
"files_extracting": "文件解压中:",
"game_path_notify": "未找到游戏路径,请记得在设置中进行设置"
},
"options": {
"enabled": "已启用",
@@ -24,23 +25,26 @@
"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游戏"
},
"downloads": {
"grasscutter_fullbuild": "下载 Grasscutter 一体化",
"grasscutter_fullquest": "下载 Quest 一体化",
"grasscutter_stable_data": "下载 Grasscutter 稳定版数据",
"grasscutter_latest_data": "下载 Grasscutter 开发版数据",
"grasscutter_stable_data_update": "更新 Grasscutter 稳定版数据",
"grasscutter_latest_data_update": "更新 Grasscutter 开发版数据",
"grasscutter_stable": "下载 Grasscutter 稳定版",
"grasscutter_unstable": "下载 Grasscutter 稳定版",
"grasscutter_latest": "下载 Grasscutter 开发版",
"grasscutter_stable_update": "更新 Grasscutter 稳定版",
"grasscutter_unstable_update": "更新 Grasscutter 稳定版",
"grasscutter_latest_update": "更新 Grasscutter 开发版",
"resources": "下载 Grasscutter 资源",
"game": "下载游戏",

View File

@@ -8,7 +8,8 @@
"ip_placeholder": "IP地址...",
"port_placeholder": "通訊埠...",
"files_downloading": "檔案下載中:",
"files_extracting": "檔案解壓縮中:"
"files_extracting": "檔案解壓縮中:",
"game_path_notify": "找不到遊戲路徑,記得在設置裡設置!"
},
"options": {
"enabled": "已啟用",
@@ -24,23 +25,26 @@
"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 遊戲"
},
"downloads": {
"grasscutter_fullbuild": "下載Grasscutter多合一下載",
"grasscutter_fullquest": "下载 Quest 一体化",
"grasscutter_stable_data": "下載Grasscutter穩定版數據Data",
"grasscutter_latest_data": "下載Grasscutter開發板數據Data",
"grasscutter_stable_data_update": "更新Grasscutter穩定版數據Data",
"grasscutter_latest_data_update": "更新Grasscutter開發板數據Data",
"grasscutter_stable": "下載Grasscutter穩定版",
"grasscutter_unstable": "下載Grasscutter穩定版",
"grasscutter_latest": "下載Grasscutter開發板",
"grasscutter_stable_update": "更新Grasscutter穩定版",
"grasscutter_unstable_update": "更新Grasscutter穩定版",
"grasscutter_latest_update": "更新Grasscutter開發板",
"resources": "下載Grasscutter資源Resources",
"game": "下載遊戲",

View File

@@ -8,7 +8,8 @@
"ip_placeholder": "Server Adresse...",
"port_placeholder": "Port...",
"files_downloading": "Herunterladen von Dateien: ",
"files_extracting": "Extrahieren von Dateien: "
"files_extracting": "Extrahieren von Dateien: ",
"game_path_notify": "Spielpfad nicht gefunden, denken Sie daran, ihn in den Einstellungen festzulegen!"
},
"options": {
"enabled": "Aktiviert",
@@ -23,23 +24,26 @@
"grasscutter_with_game": "Grasscutter automatisch mit dem Spiel starten",
"language": "Sprache auswählen",
"background": "Benutzerdefinierten Hintergrund festlegen (link oder bild)",
"use_theme_background": "Verwenden Sie den vom ausgewählten Thema bereitgestellten Hintergrund",
"theme": "Theme auswählen",
"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)"
"un_elevated": "Führen Sie das Spiel nicht erhöht aus (kein Admin)",
"redirect_more": "Leiten Sie auch andere MHY-Spiele um"
},
"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_stable": "Stabile Grasscutter Version herunterladen",
"grasscutter_unstable": "Stabile Grasscutter Version herunterladen",
"grasscutter_latest": "Aktuellste Grasscutter Version herunterladen",
"grasscutter_stable_update": "Stabile Grasscutter Version aktualisieren",
"grasscutter_unstable_update": "Stabile Grasscutter Version aktualisieren",
"grasscutter_latest_update": "Aktuellste Grasscutter Version aktualisieren",
"resources": "Grasscutter Ressourcen herunterladen",
"game": "Spiel herunterladen",

View File

@@ -8,7 +8,8 @@
"ip_placeholder": "Server Address...",
"port_placeholder": "Port...",
"files_downloading": "Files Downloading: ",
"files_extracting": "Files Extracting: "
"files_extracting": "Files Extracting: ",
"game_path_notify": "Game path not found, remember to set it in settings!"
},
"options": {
"enabled": "Enabled",
@@ -24,23 +25,28 @@
"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"
},
"downloads": {
"grasscutter_fullbuild": "Download Grasscutter All-in-One",
"grasscutter_fullquest": "Download Questing 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",
"grasscutter_latest_data_update": "Update Grasscutter Latest Data",
"grasscutter_stable": "Download Grasscutter Stable",
"grasscutter_unstable": "Download Grasscutter Questing",
"grasscutter_latest": "Download Grasscutter Latest",
"grasscutter_stable_update": "Update Grasscutter Stable",
"grasscutter_unstable_update": "Update Grasscutter Questing",
"grasscutter_latest_update": "Update Grasscutter Latest",
"resources": "Download Grasscutter Resources",
"game": "Download Game",
@@ -81,7 +87,8 @@
"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",

View File

@@ -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,30 +20,33 @@
"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"
},
"downloads": {
"grasscutter_fullbuild": "Descargar Datos todo en uno de Grasscutter",
"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_stable": "Descargar Grasscutter Estable",
"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_latest": "Descargar Grasscutter más reciente",
"grasscutter_stable_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:",
@@ -57,24 +61,24 @@
"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"
},
"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"

View File

@@ -8,74 +8,88 @@
"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": "active",
"disabled": "desactiver",
"enabled": "Activé",
"disabled": "Désractivé",
"game_path": "Définir le chemin d'installation du jeu",
"game_command": "Commande de lancement du jeu",
"game_executable": "definir l'executable du jeu",
"game_executable": "finir l'executable du jeu",
"recover_rsa": "Récupération d'urgence des RSA",
"grasscutter_jar": "definir le Jar Grasscutter",
"toggle_encryption": "activer l'encryption",
"grasscutter_jar": "finir le Jar Grasscutter",
"toggle_encryption": "Activer l'encryption",
"install_certificate": "Installer le certificat du proxy",
"java_path": "definir un chemin java personnalise",
"java_path": "finir un chemin java personnalise",
"grasscutter_with_game": "Lancer Grasscutter automatiquement avec le jeu",
"language": "Choisir la langue",
"background": "definir un arriere plan personnalise (lien ou fichier image)",
"theme": "definir un theme",
"patch_rsa": "Corriger automatiquement les RSA",
"use_proxy": "Utiliser un proxy interne",
"background": "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 excitation",
"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"
},
"downloads": {
"grasscutter_fullbuild": "Telecharger Grasscutter tout-en-un",
"grasscutter_stable_data": "Telecharger les donnees de Grasscutter (version stable)",
"grasscutter_latest_data": "Telecharger les donnees de Grasscutter (derniere version)",
"grasscutter_stable_data_update": "Mettre a jour les donnees de Grasscutter (version stable)",
"grasscutter_latest_data_update": "Mettre a jour les donnees de Grasscutter (derniere version)",
"grasscutter_stable": "Telecharger Grasscutter (version stable)",
"grasscutter_latest": "Telecharger Grasscutter (derniere version)",
"grasscutter_stable_update": "Mettre a jour Grasscutter (version stable)",
"grasscutter_latest_update": "Mettre a jour Grasscutter (derniere version)",
"resources": "Telecharger les ressources logicielles de Grasscutter",
"grasscutter_fullquest": "Télécharger les Quêtes 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)",
"grasscutter_latest_data_update": "Mettre à jour les données de Grasscutter (derniere version)",
"grasscutter_unstable": "Télécharger Grasscutter (version stable)",
"grasscutter_latest": "Télécharger Grasscutter (derniere version)",
"grasscutter_unstable_update": "Mettre à jour Grasscutter (version stable)",
"grasscutter_latest_update": "Mettre à jour Grasscutter (derniere version)",
"resources": "Telecharger les ressources de Grasscutter",
"aio_header": "Telechargements tout-en-un:",
"individual_header": "Telechargements de pièces individuelles:",
"individual_header": "Telechargements individuels:",
"mods_header": "Mods:",
"migoto": "Telecharger GIMI 3dmigoto"
},
"download_status": {
"downloading": "Telechargement",
"downloading": "Téléchargement",
"extracting": "Extraction",
"error": "Erreur",
"finished": "Termine",
"stopped": "Arrete"
"finished": "Terminé",
"stopped": "Arrêté"
},
"components": {
"select_file": "choisir fichier ou dossier...",
"select_folder": "choisir dossier...",
"download": "Telecharger",
"select_file": "Choisir un fichier ou un dossier...",
"select_folder": "Choisir un dossier...",
"download": "Télécharger",
"delete": "Supprimer",
"install": "Installer"
},
"news": {
"latest_commits": "Recents Commits",
"latest_version": "Derniere version"
"latest_commits": "Commits récents",
"latest_version": "Dernière version"
},
"help": {
"port_help_text": "Assurez-vous que c'est le port serveur Dispatch, et non le port du serveur de jeu. C'est presque toujours '433'.",
"game_help_text": "Vous n'avez pas besoin d'une copie differente du jeu pour jouer avec Grasscutter. Cela est ou pour retrograder en 2.6 ou si vous n'avez pas le jeu d'installe",
"gc_stable_jar": "Telecharger le dernier build stable de Grasscutter, ce qui inclut le fichier jar et les fichiers de donnees",
"gc_fullbuild": "Téléchargez un build complet de Grasscutter, incluant le repo, le jar et les ressources. Il est entièrement configuré et ne nécessite aucun autre téléchargement à partir de ce menu.",
"gc_dev_jar": "Telecharger le dernier build en development de Grasscutter, ce qui inclut le fichier jar et les fichiers de donnees",
"gc_stable_data": "Telecharger le dernier build stable de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
"gc_dev_data": "Telecharger le dernier build en development de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
"port_help_text": "Assurez-vous que c'est le port du serveur de Dispatch, et non le port du serveur de jeu. C'est presque toujours '433'.",
"game_help_text": "Il n'y a pas besoin d'une copie differente du jeu pour jouer avec Grasscutter. C'est utile pour downgrade en 2.6 ou si vous n'avez pas le jeu d'installe",
"gc_stable_jar": "Télécharge le dernier build stable de Grasscutter, ce qui inclut le fichier jar et les fichiers de données",
"gc_fullbuild": "Télécharge un build complet de Grasscutter, incluant le repo, le jar et les ressources. Il est entièrement configuré et ne nécessite aucun autre téléchargement à partir de ce menu.",
"gc_dev_jar": "Télécharge le dernier build de development de Grasscutter, ce qui inclut le fichier jar et les fichiers de données",
"gc_stable_data": "Télécharge le dernier build stable de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
"gc_dev_data": "Télécharge le dernier build de development de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
"resources": "Les ressources sont aussi necessaires pour lancer un serveur Grasscutter. Ce bouton deviendra gris si vous avez deja un fichier ressources avec les donnees dedans.",
"add_delay": "Définir un délai dans le chargeur de 3dmigoto ! \nCela devrait résoudre les problèmes de chargement, mais ajoutera un petit délai au chargement de 3dmigoto lors du lancement du jeu. \nVous pouvez maintenant lancer le jeu avec 3dmigoto.",
"add_delay": "Définit le délai du chargement de 3dmigoto ! \nCela devrait résoudre les problèmes de chargement, mais ajoutera un petit délai au chargement de 3dmigoto lors du lancement du jeu. \nVous pouvez maintenant lancer le jeu avec 3dmigoto.",
"use_proxy": "Active le proxy interne de Cultivation. Il faut activer cette option si un logiciel tel que Fiddler n'est pas installé.",
"patch_rsa": "Patch et dépatche les clés RSA du jeu automatiquement. A moins de jouer avec d'anciennes versons ou des versions non officielles (3.0 ou plus ancien), cette option doit être activée.",
"migoto": "Pour importer des modèles depuis GameBanana"
},
"swag": {
"akebi_name": "Akebi",
"migoto_name": "Migoto",
"reshade_name": "Reshade",
"akebi": "Définir l'exécutable d'Akebid'aAcrepi",
"migoto": "Définir l'exécutable de 3DMigoto",
"reshade": "Définir l'injecteur de Reshade"
}
}

View File

@@ -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,23 +24,26 @@
"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"
},
"downloads": {
"grasscutter_fullbuild": "Sedang Mendownload Grasscutter Semua Dalam Satu",
"grasscutter_fullquest": "Unduh pencarian 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",
"grasscutter_latest_data_update": "Memperbaharui Grasscutter Data Terbaru",
"grasscutter_stable": "Download Grasscutter Stabil Version ",
"grasscutter_unstable": "Download Grasscutter Stabil Version ",
"grasscutter_latest": "Download Grasscutter Terbaru Version",
"grasscutter_stable_update": "Sedang MengUpdate Grasscutter Stabil",
"grasscutter_unstable_update": "Sedang MengUpdate Grasscutter Stabil",
"grasscutter_latest_update": "Sedang MengUpdate Grasscutter Terbaru",
"resources": "Mendownload Grasscutter Resources",
"aio_header": "Unduhan Semua Dalam Satu:",

98
src-tauri/lang/it.json Normal file
View File

@@ -0,0 +1,98 @@
{
"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"
},
"downloads": {
"grasscutter_fullbuild": "Scarica Grasscutter Tutto-in-Uno",
"grasscutter_fullquest": "Scarica Questing 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"
},
"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"
}
}

View File

@@ -8,7 +8,8 @@
"ip_placeholder": "서버 주소",
"port_placeholder": "포트",
"files_downloading": "파일 다운로드 중: ",
"files_extracting": "파일 추출 중: "
"files_extracting": "파일 추출 중: ",
"game_path_notify": "게임 경로를 찾을 수 없습니다. 설정에서 설정하는 것을 잊지 마세요!"
},
"options": {
"enabled": "활성",
@@ -24,23 +25,26 @@
"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 게임도 리디렉션"
},
"downloads": {
"grasscutter_fullbuild": "올인원 Grasscutter 다운로드",
"grasscutter_fullquest": "퀘스트 올인원 다운로드",
"grasscutter_stable_data": "안정적인 데이터 다운로드",
"grasscutter_latest_data": "최신 데이터 다운로드",
"grasscutter_stable_data_update": "안정적 데이터 업데이트",
"grasscutter_latest_data_update": "최신 데이터 업데이트",
"grasscutter_stable": "안정 다운로드",
"grasscutter_unstable": "안정 다운로드",
"grasscutter_latest": "최신 다운로드",
"grasscutter_stable_update": "안정 업데이트",
"grasscutter_unstable_update": "안정 업데이트",
"grasscutter_latest_update": "최신 업데이트",
"resources": "리소스 다운로드",
"game": "게임 다운로드",

View File

@@ -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,23 +23,26 @@
"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"
},
"downloads": {
"grasscutter_fullbuild": "Lejupielādējiet Grasscutter viss vienā",
"grasscutter_fullquest": "Lejupielādēt questing 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",
"grasscutter_latest_data_update": "Atjauniniet Grasscutter jaunākos datus",
"grasscutter_stable": "Lejupielādēt Grasscutter stabilo",
"grasscutter_unstable": "Lejupielādēt Grasscutter stabilo",
"grasscutter_latest": "Lejupielādēt Grasscutter jaunāko",
"grasscutter_stable_update": "Atjauniet Grasscutter stabilo",
"grasscutter_unstable_update": "Atjauniet Grasscutter stabilo",
"grasscutter_latest_update": "Atjauniet Grasscutter jaunāko",
"resources": "Lejupielādējiet Grasscutter resursi",
"aio_header": "Lejupielādes viss vienā",

View File

@@ -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,23 +24,26 @@
"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"
},
"downloads": {
"grasscutter_fullbuild": "Grasscutter Alles-in-één Downloaden",
"grasscutter_fullquest": "Alles-in-één zoeken 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",
"grasscutter_latest_data_update": "Nieuwste gegevens Van Grasscutter bijwerken",
"grasscutter_stable": "Download Stabiele Versie Van Grasscutter",
"grasscutter_unstable": "Download Stabiele Versie Van Grasscutter",
"grasscutter_latest": "Download De Nieuwste Versie Van Grasscutter",
"grasscutter_stable_update": "Update Grasscutter Naar De Stabiele Versie",
"grasscutter_unstable_update": "Update Grasscutter Naar De Stabiele Versie",
"grasscutter_latest_update": "Update Grasscutter Naar De Nieuwste Versie",
"resources": "Download Grasscutter bronnen",
"game": "Download Spel",

101
src-tauri/lang/pl.json Normal file
View File

@@ -0,0 +1,101 @@
{
"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"
},
"downloads": {
"grasscutter_fullbuild": "Pobierz Grasscutter (wszystko w jednym)",
"grasscutter_fullquest": "Pobierz Questing (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"
},
"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"
}
}

View File

@@ -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,23 +25,26 @@
"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"
},
"downloads": {
"grasscutter_fullbuild": "Baixar o Grasscutter Tudo-em-Um",
"grasscutter_fullquest": "Baixar de missões 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",
"grasscutter_latest_data_update": "Atualizar os Dados do Grasscutter Mais Recente",
"grasscutter_stable": "Baixar o Grasscutter Estável",
"grasscutter_unstable": "Baixar o Grasscutter Estável",
"grasscutter_latest": "Baixar o Grasscutter Mais Recente",
"grasscutter_stable_update": "Atualizar o Grasscutter Estável",
"grasscutter_unstable_update": "Atualizar o Grasscutter Estável",
"grasscutter_latest_update": "Atualizar o Grasscutter Mais Recente",
"resources": "Baixar os Recursos do Grasscutter ",
"game": "Baixar o Jogo",

View File

@@ -8,7 +8,8 @@
"ip_placeholder": "Айпи адрес...",
"port_placeholder": "Порт...",
"files_downloading": "Файлов скачано: ",
"files_extracting": "Извлечено файлов: "
"files_extracting": "Извлечено файлов: ",
"game_path_notify": "Путь к игре не найден, не забудьте установить его в настройках!"
},
"options": {
"enabled": "Включено",
@@ -23,23 +24,26 @@
"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"
},
"downloads": {
"grasscutter_fullbuild": "Скачать все в одном Grasscutter",
"grasscutter_fullquest": "Скачать квесты все в одном",
"grasscutter_stable_data": "Скачать стабильные данные Grasscutter",
"grasscutter_latest_data": "Скачать последние данные Grasscutter",
"grasscutter_stable_data_update": "Обновить стабильные данные Grasscutter",
"grasscutter_latest_data_update": "Обновить последние данные Grasscutter",
"grasscutter_stable": "Скачать стабильную версию Grasscutter",
"grasscutter_unstable": "Скачать стабильную версию Grasscutter",
"grasscutter_latest": "Скачать последнюю версию Grasscutter",
"grasscutter_stable_update": "Обновить стабильную версию Grasscutter",
"grasscutter_unstable_update": "Обновить стабильную версию Grasscutter",
"grasscutter_latest_update": "Обновить последнюю версию Grasscutter",
"resources": "Скачать ресурсы Grasscutter",
"game": "Скачать Игру",

View File

@@ -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,23 +25,26 @@
"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"
},
"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_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",
"grasscutter_latest_data_update": "Cập nhật dữ liệu Grasscutter bản mới nhất",
"grasscutter_stable": "Tải Grasscutter bản ổn định",
"grasscutter_unstable": "Tải Grasscutter bản ổn định",
"grasscutter_latest": "Tải Grasscutter bản mới nhất",
"grasscutter_stable_update": "Cập nhật Grasscutter bản ổn định",
"grasscutter_unstable_update": "Cập nhật Grasscutter bản ổn định",
"grasscutter_latest_update": "Cập nhật Grasscutter bản mới nhất",
"resources": "Tải tài nguyên Grasscutter",
"game": "Tải game",

View File

@@ -18,5 +18,5 @@ pub fn reopen_as_admin() {
exit(0);
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
pub fn reopen_as_admin() {}

View File

@@ -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>,
@@ -15,7 +15,8 @@ pub struct Configuration {
pub last_ip: Option<String>,
pub last_port: Option<String>,
pub language: Option<String>,
pub customBackground: 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,7 @@ pub struct Configuration {
pub horny_mode: Option<bool>,
pub auto_mongodb: Option<bool>,
pub un_elevated: Option<bool>,
pub redirect_more: Option<bool>,
}
pub fn config_path() -> PathBuf {
@@ -39,7 +41,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
}

View File

@@ -131,11 +131,10 @@ pub fn read_file(path: String) -> String {
let mut file = match fs::File::open(path_buf) {
Ok(file) => file,
Err(e) => {
println!("Failed to open file {}: {}", &path, 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
}

View File

@@ -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",
@@ -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();
}
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,6 +214,7 @@ 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,
@@ -205,8 +223,13 @@ fn main() -> Result<(), ArgsError> {
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,
proxy::set_redirect_more,
release::get_latest_release,
unzip::unzip,
file_helpers::rename,
@@ -230,6 +253,12 @@ fn main() -> Result<(), ArgsError> {
gamebanana::list_submissions,
gamebanana::list_mods
])
.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");
} else {
@@ -255,6 +284,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;
@@ -300,6 +330,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(60);
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
@@ -341,7 +406,7 @@ fn restart_grasscutter(window: tauri::Window) -> bool {
#[cfg(unix)]
#[tauri::command]
fn restart_grasscutter(window: tauri::Window) {
fn restart_grasscutter(_window: tauri::Window) {
// Placeholder text for imports
let s = System::new();
if let Some(process) = s.process(Pid::from(1337)) {
@@ -349,7 +414,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();
@@ -410,12 +474,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);
}
#[tauri::command]
async fn connect(port: u16, certificate_path: String) {
// Log message to console.

View File

@@ -3,6 +3,53 @@ use crate::file_helpers;
use crate::system_helpers;
use std::path::PathBuf;
#[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() -> bool {
let patch_path = PathBuf::from(system_helpers::install_location()).join("patch/version.dll");
@@ -37,6 +84,82 @@ pub async fn patch_game() -> bool {
true
}
#[cfg(target_os = "linux")]
#[tauri::command]
pub async fn patch_game() -> 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(
@@ -50,6 +173,51 @@ pub async fn unpatch_game() -> bool {
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();

View File

@@ -3,8 +3,7 @@
* https://github.com/omjadas/hudsucker/blob/main/examples/log.rs
*/
#[cfg(target_os = "linux")]
use crate::system_helpers::run_command;
use crate::config::get_config;
use once_cell::sync::Lazy;
use std::{path::PathBuf, str::FromStr, sync::Mutex};
@@ -27,6 +26,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,6 +41,7 @@ async fn shutdown_signal() {
// Global ver for getting server address.
static SERVER: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new("http://localhost:443".to_string()));
static REDIRECT_MORE: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
#[derive(Clone)]
struct ProxyHandler;
@@ -51,6 +58,11 @@ pub fn set_proxy_addr(addr: String) {
println!("Set server to {}", SERVER.lock().unwrap());
}
#[tauri::command]
pub fn set_redirect_more() {
*REDIRECT_MORE.lock().unwrap() = true;
}
#[async_trait]
impl HttpHandler for ProxyHandler {
async fn handle_request(
@@ -60,24 +72,93 @@ impl HttpHandler for ProxyHandler {
) -> RequestOrResponse {
let uri = req.uri().to_string();
if uri.contains("hoyoverse.com") || uri.contains("mihoyo.com") || uri.contains("yuanshen.com") {
// Handle CONNECTs
if req.method().as_str() == "CONNECT" {
let builder = Response::builder()
.header("DecryptEndpoint", "Created")
.status(StatusCode::OK);
let res = builder.body(()).unwrap();
let mut more = get_config().redirect_more;
// Respond to CONNECT
*res.body()
} else {
let uri_path_and_query = req.uri().path_and_query().unwrap().as_str();
// Create new URI.
let new_uri =
Uri::from_str(format!("{}{}", SERVER.lock().unwrap(), uri_path_and_query).as_str())
.unwrap();
// Set request URI to the new one.
*req.uri_mut() = new_uri;
if *REDIRECT_MORE.lock().unwrap() {
more = Some(true);
}
match more {
Some(true) => {
if 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")
{
// Handle CONNECTs
if req.method().as_str() == "CONNECT" {
let builder = Response::builder()
.header("DecryptEndpoint", "Created")
.status(StatusCode::OK);
let res = builder.body(()).unwrap();
// Respond to CONNECT
*res.body()
} else {
let uri_path_and_query = req.uri().path_and_query().unwrap().as_str();
// Create new URI.
let new_uri =
Uri::from_str(format!("{}{}", SERVER.lock().unwrap(), uri_path_and_query).as_str())
.unwrap();
// Set request URI to the new one.
*req.uri_mut() = new_uri;
}
}
}
Some(false) => {
if uri.contains("hoyoverse.com")
|| uri.contains("mihoyo.com")
|| uri.contains("yuanshen.com")
{
// Handle CONNECTs
if req.method().as_str() == "CONNECT" {
let builder = Response::builder()
.header("DecryptEndpoint", "Created")
.status(StatusCode::OK);
let res = builder.body(()).unwrap();
// Respond to CONNECT
*res.body()
} else {
let uri_path_and_query = req.uri().path_and_query().unwrap().as_str();
// Create new URI.
let new_uri =
Uri::from_str(format!("{}{}", SERVER.lock().unwrap(), uri_path_and_query).as_str())
.unwrap();
// Set request URI to the new one.
*req.uri_mut() = new_uri;
}
}
}
// Use default as fallback
None => {
if uri.contains("hoyoverse.com")
|| uri.contains("mihoyo.com")
|| uri.contains("yuanshen.com")
{
// Handle CONNECTs
if req.method().as_str() == "CONNECT" {
let builder = Response::builder()
.header("DecryptEndpoint", "Created")
.status(StatusCode::OK);
let res = builder.body(()).unwrap();
// Respond to CONNECT
*res.body()
} else {
let uri_path_and_query = req.uri().path_and_query().unwrap().as_str();
// Create new URI.
let new_uri =
Uri::from_str(format!("{}{}", SERVER.lock().unwrap(), uri_path_and_query).as_str())
.unwrap();
// Set request URI to the new one.
*req.uri_mut() = new_uri;
}
}
}
}
@@ -95,7 +176,26 @@ 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")
let more = get_config().redirect_more;
match more {
Some(true) => {
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")
}
Some(false) => {
uri.contains("hoyoverse.com") || uri.contains("mihoyo.com") || uri.contains("yuanshen.com")
}
None => {
uri.contains("hoyoverse.com") || uri.contains("mihoyo.com") || uri.contains("yuanshen.com")
}
}
}
}
@@ -188,24 +288,23 @@ 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")]
@@ -234,21 +333,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 +446,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.");
}

View File

@@ -1,8 +1,9 @@
use duct::cmd;
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,101 @@ 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")]
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")]
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 +118,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 +138,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();
@@ -60,7 +164,10 @@ pub fn run_command(program: &str, args: Vec<&str>, relative: Option<bool>) {
std::env::set_current_dir(&path_buf).unwrap();
}
cmd(prog, args).run().unwrap();
// Run the command
let mut command = Command::new(&prog);
command.args(&args);
command.spawn().unwrap();
// Restore the original working directory
std::env::set_current_dir(cwd).unwrap();
@@ -78,6 +185,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",
@@ -85,8 +193,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.
@@ -103,6 +261,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.
@@ -116,10 +366,28 @@ 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();
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()
}
}
#[tauri::command]
@@ -245,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]
@@ -268,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)]
@@ -293,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",
&regpath,
"/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) {}
@@ -317,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()
}

View File

@@ -107,6 +107,12 @@ pub fn unzip(
.unwrap();
}
if zipfile.contains("GrasscutterQuests") {
window
.emit("jar_extracted", destpath.to_string() + "grasscutter.jar")
.unwrap();
}
if zipfile.contains("GIMI") {
window
.emit(

View File

@@ -1,5 +1,5 @@
{
"$schema": "..\\node_modules/@tauri-apps/cli\\schema.json",
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": {
"beforeDevCommand": "yarn start",
"devPath": "http://localhost:3000",
@@ -7,17 +7,17 @@
},
"package": {
"productName": "Cultivation",
"version": "1.0.27"
"version": "1.2.0"
},
"tauri": {
"allowlist": {
"fs": {
"scope": ["$DATA", "$DATA/cultivation", "$DATA/cultivation/*"]
"scope": ["$DATA", "$DATA/cultivation", "$DATA/cultivation/**"]
},
"protocol": {
"all": true,
"asset": true,
"assetScope": ["$DATA", "$DATA/cultivation", "$DATA/cultivation/*"]
"assetScope": ["$DATA", "$DATA/cultivation", "$DATA/cultivation/**"]
},
"all": true
},
@@ -53,7 +53,7 @@
}
},
"security": {
"csp": "default-src 'self' https://asset.localhost; img-src 'self'; img-src 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,

View File

@@ -107,11 +107,11 @@ select:focus {
width: 100%;
height: 160px;
backdrop-filter: blur(10px);
box-shadow: inset 0px 5px 12px -3px rgb(50 50 50 / 75%);
margin: 0;
padding: 0;
backdrop-filter: blur(10px);
box-shadow: inset 0px 5px 12px -3px rgb(0, 0, 0, 0.43);
}
@media (max-height: 580px) {

View File

@@ -38,7 +38,7 @@ class App extends React.Component<Readonly<unknown>, IState> {
}
// Get custom bg AFTER theme is loaded !! important !!
const custom_bg = await getConfigOption('customBackground')
const custom_bg = await getConfigOption('custom_background')
if (custom_bg) {
const isUrl = /^http(s)?:\/\//gm.test(custom_bg)

View File

@@ -15,7 +15,7 @@ async function setProxyAddress(address: string) {
}
async function startProxy() {
await invoke('connect', { port: 2222, certificatePath: (await dataDir()) + '\\cultivation\\ca' })
await invoke('connect', { port: 2222, certificatePath: (await dataDir()) + 'cultivation/ca' })
await invoke('open_in_browser', { url: 'https://hoyoverse.com' })
}
@@ -24,12 +24,12 @@ async function stopProxy() {
}
async function generateCertificates() {
await invoke('generate_ca_files', { path: (await dataDir()) + '\\cultivation' })
await invoke('generate_ca_files', { path: (await dataDir()) + 'cultivation' })
}
async function generateInfo() {
console.log({
certificatePath: (await dataDir()) + '\\cultivation\\ca',
certificatePath: (await dataDir()) + 'cultivation/ca',
isAdmin: await invoke('is_elevated'),
connectingTo: proxyAddress,
})

View File

@@ -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'
@@ -13,8 +13,9 @@ import Game from './components/menu/Game'
import RightBar from './components/RightBar'
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'
@@ -42,6 +43,8 @@ interface IState {
migotoSet: boolean
playGame: (exe?: string, proc_name?: string) => void
notification: React.ReactElement | null
isGamePathSet: boolean
game_install_path: string
}
export class Main extends React.Component<IProps, IState> {
@@ -59,6 +62,8 @@ export class Main extends React.Component<IProps, IState> {
alert('Error launching game')
},
notification: null,
isGamePathSet: true,
game_install_path: '',
}
listen('lang_error', (payload) => {
@@ -71,10 +76,6 @@ export class Main extends React.Component<IProps, IState> {
listen('migoto_extracted', ({ payload }: { payload: string }) => {
setConfigOption('migoto_path', payload)
invoke('set_migoto_target', {
migotoPath: payload,
})
})
// Emitted for rsa replacing-purposes
@@ -101,10 +102,28 @@ export class Main extends React.Component<IProps, IState> {
// 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
@@ -126,8 +145,13 @@ export class Main extends React.Component<IProps, IState> {
}
async componentDidMount() {
const game_path = await getConfigOption('game_install_path')
const cert_generated = await getConfigOption('cert_generated')
this.setState({
game_install_path: game_path,
})
this.setState({
migotoSet: !!(await getConfigOption('migoto_path')),
})
@@ -189,6 +213,31 @@ export class Main extends React.Component<IProps, IState> {
})
}
async componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>) {
const game_path = await getConfigOption('game_install_path')
// Check if game exists at set location
const game_exists: boolean = (await invoke('dir_exists', {
path: game_path,
})) as boolean
// Set no game path so the user understands it doesn't exist there
if (!game_exists) {
setConfigOption('game_install_path', '')
}
//if previous state is not equal the current one - update the game_install_path to be the current game path
if (prevState.game_install_path != game_path) {
this.setState({
game_install_path: game_path,
})
this.state.game_install_path === ''
? this.setState({ isGamePathSet: false })
: this.setState({ isGamePathSet: true })
}
}
render() {
return (
<>
@@ -227,6 +276,8 @@ export class Main extends React.Component<IProps, IState> {
<Notification show={!!this.state.notification}>{this.state.notification}</Notification>
{this.state.isGamePathSet ? <></> : <GamePathNotify />}
<RightBar />
<NewsSection />

View File

@@ -8,17 +8,12 @@
justify-content: flex-start;
height: 100vh;
width: 80px;
width: 70px;
right: 0%;
z-index: 99;
background-color: rgba(77, 77, 77, 0.6);
z-index: 999;
}
.BarImg:hover {
cursor: pointer;
background-color: rgba(0, 0, 0, 0.25);
}
.RightBarInner > div {
@@ -26,16 +21,11 @@
}
.RightBar img {
height: 40px;
height: 30px;
filter: invert(100%) sepia(0%) saturate(11%) hue-rotate(227deg) brightness(103%) contrast(105%);
transition: filter 0.2s ease-in-out;
}
.RightBar img:hover {
filter: invert(75%) sepia(0%) saturate(100%) hue-rotate(0deg) brightness(100%) contrast(100%);
}
@media (max-height: 580px) {
.RightBar {
height: calc(100vh - 180px);
@@ -47,3 +37,25 @@
height: calc(100vh - 170px);
}
}
.BarImg {
transition: 0.2s;
border-radius: 50%;
width: 40px;
height: 40px;
background-color: rgba(0, 0, 0, 0.685);
display: flex;
justify-content: center;
align-items: center;
border: 2px solid transparent;
}
.BarImg:hover {
cursor: pointer;
border: 2px solid #ffc920;
}
.BarImg:hover img {
transition: 0.2s;
filter: invert(72%) sepia(68%) saturate(777%) hue-rotate(341deg) brightness(113%) contrast(101%);
}

View File

@@ -20,6 +20,8 @@
#playButton .BigButton {
height: 100%;
box-shadow: 0 0 5px 3px rgba(0, 0, 0, 0.2);
font-size: 24px;
font-weight: 500;
}
#serverControls {

View File

@@ -12,6 +12,7 @@ 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'
@@ -31,8 +32,6 @@ interface IState {
ipPlaceholder: string
portPlaceholder: string
portHelpText: string
httpsLabel: string
httpsEnabled: boolean
@@ -55,7 +54,6 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
port: '',
ipPlaceholder: '',
portPlaceholder: '',
portHelpText: '',
httpsLabel: '',
httpsEnabled: false,
launchServer: () => {
@@ -90,7 +88,6 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
port: config.last_port || '',
ipPlaceholder: await translate('main.ip_placeholder'),
portPlaceholder: await translate('help.port_placeholder'),
portHelpText: await translate('help.port_help_text'),
httpsLabel: await translate('main.https_enable'),
httpsEnabled: config.https_enabled || false,
swag: config.swag_mode || false,
@@ -123,7 +120,11 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
// Connect to proxy
if (config.toggle_grasscutter) {
if (config.patch_rsa) {
const game_exe = await getGameExecutable()
const patchable = game_exe?.toLowerCase().includes('genshin' || 'yuanshen')
if (config.patch_rsa && patchable) {
const gameVersion = await getGameVersion()
console.log(gameVersion)
@@ -152,8 +153,6 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
}
}
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)
@@ -168,7 +167,7 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
addr: (this.state.httpsEnabled ? 'https' : 'http') + '://' + this.state.ip + ':' + this.state.port,
})
// Connect to proxy
await invoke('connect', { port: 8365, certificatePath: (await dataDir()) + '\\cultivation\\ca' })
await invoke('connect', { port: 8365, certificatePath: (await dataDir()) + 'cultivation/ca' })
}
// Open server as well if the options are set
@@ -212,13 +211,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
@@ -229,8 +229,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 || '',
@@ -294,7 +317,7 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
onChange={this.setPort}
initalValue={this.state.port}
/>
<HelpButton contents={this.state.portHelpText} />
<HelpButton contents={'help.port_help_text'} />
<Checkbox
id="httpsEnable"
label={this.state.httpsLabel}

View File

@@ -7,7 +7,7 @@
padding: 0 30px;
border-radius: 5px;
border: none;
background: linear-gradient(#ffd326, #ffc61e);
background: linear-gradient(#ffcf0d, #fec004);
color: #704a1d;
font-weight: bold;
@@ -16,7 +16,7 @@
.BigButton:hover {
cursor: pointer;
background: linear-gradient(#ffc61e, #ffd326);
background: linear-gradient(#fdd841, #ffc517);
}
.BigButton.disabled {

View File

@@ -17,7 +17,7 @@
.CheckboxDisplay img {
height: 100%;
filter: invert(99%) sepia(0%) saturate(1188%) hue-rotate(186deg) brightness(97%) contrast(67%);
filter: invert(60%);
}
.Checkbox label {

View File

@@ -13,14 +13,14 @@ import { invoke } from '@tauri-apps/api'
import { listen } from '@tauri-apps/api/event'
import HelpButton from '../common/HelpButton'
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_BUILD_DOWNLOAD = 'https://github.com/NotThorny/Grasscutter/releases/download/culti-aio/GrasscutterCulti.zip'
const FULL_QUEST_DOWNLOAD = 'https://github.com/NotThorny/Grasscutter/releases/download/culti-aio/GrasscutterQuests.zip'
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 STABLE_DOWNLOAD = 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/stable/Grasscutter.zip'
const DEV_DOWNLOAD = 'https://nightly.link/Grasscutters/Grasscutter/workflows/build/development/Grasscutter.zip'
const RESOURCES_DOWNLOAD = 'https://gitlab.com/YuukiPS/GC-Resources/-/archive/3.5/GC-Resources-3.5.zip' // Use Yuuki res as grasscutter crepe res are broken
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/V6.0/3dmigoto-GIMI-for-playing-mods.zip'
'https://github.com/SilentNightSound/GI-Model-Importer/releases/download/V7.0/3dmigoto-GIMI-for-playing-mods.zip'
interface IProps {
closeFn: () => void
@@ -55,9 +55,9 @@ 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.downloadGrasscutterStableRepo = this.downloadGrasscutterStableRepo.bind(this)
this.downloadGrasscutterDevRepo = this.downloadGrasscutterDevRepo.bind(this)
this.downloadGrasscutterStable = this.downloadGrasscutterStable.bind(this)
this.downloadGrasscutterLatest = this.downloadGrasscutterLatest.bind(this)
this.downloadResources = this.downloadResources.bind(this)
this.downloadMigoto = this.downloadMigoto.bind(this)
@@ -85,15 +85,15 @@ export default class Downloads extends React.Component<IProps, IState> {
return
}
const path = gc_path.substring(0, gc_path.lastIndexOf('\\'))
const path = gc_path.substring(0, gc_path.lastIndexOf('/'))
if (gc_path) {
const resources_exist: boolean =
((await invoke('dir_exists', {
path: path + '\\resources',
path: path + '/resources',
})) as boolean) &&
(!(await invoke('dir_is_empty', {
path: path + '\\resources',
path: path + '/resources',
})) as boolean)
this.setState({
@@ -110,7 +110,7 @@ export default class Downloads extends React.Component<IProps, IState> {
// Set to default if not set
if (!path || path === '') {
const appdata = await dataDir()
folderPath = appdata + 'cultivation\\grasscutter'
folderPath = appdata + 'cultivation/grasscutter'
// Early return since its formatted properly
return folderPath
@@ -133,8 +133,18 @@ export default class Downloads extends React.Component<IProps, IState> {
async downloadGrasscutterFullBuild() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(FULL_BUILD_DOWNLOAD, folder + '\\GrasscutterCulti.zip', async () => {
await unzip(folder + '\\GrasscutterCulti.zip', folder + '\\', true)
this.props.downloadManager.addDownload(FULL_BUILD_DOWNLOAD, folder + '/GrasscutterCulti.zip', async () => {
await unzip(folder + '/GrasscutterCulti.zip', folder + '/', true)
this.toggleButtons()
})
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()
})
@@ -143,8 +153,8 @@ export default class Downloads extends React.Component<IProps, IState> {
async downloadGrasscutterStableRepo() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(STABLE_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', async () => {
await unzip(folder + '\\grasscutter_repo.zip', folder + '\\', true)
this.props.downloadManager.addDownload(STABLE_REPO_DOWNLOAD, folder + '/grasscutter_repo.zip', async () => {
await unzip(folder + '/grasscutter_repo.zip', folder + '/', true)
this.toggleButtons()
})
@@ -153,31 +163,18 @@ export default class Downloads extends React.Component<IProps, IState> {
async downloadGrasscutterDevRepo() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(DEV_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', async () => {
await unzip(folder + '\\grasscutter_repo.zip', folder + '\\', true)
this.props.downloadManager.addDownload(DEV_REPO_DOWNLOAD, folder + '/grasscutter_repo.zip', async () => {
await unzip(folder + '/grasscutter_repo.zip', folder + '/', true)
this.toggleButtons()
})
this.toggleButtons()
}
async downloadGrasscutterStable() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(STABLE_DOWNLOAD, folder + '\\grasscutter.zip', async () => {
await unzip(folder + '\\grasscutter.zip', folder + '\\', true)
this.toggleButtons
})
// Also add repo download
this.downloadGrasscutterStableRepo()
this.toggleButtons()
}
async downloadGrasscutterLatest() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(DEV_DOWNLOAD, folder + '\\grasscutter.zip', async () => {
await unzip(folder + '\\grasscutter.zip', folder + '\\', true)
this.props.downloadManager.addDownload(DEV_DOWNLOAD, folder + '/grasscutter.zip', async () => {
await unzip(folder + '/grasscutter.zip', folder + '/', true)
this.toggleButtons()
})
@@ -188,28 +185,27 @@ export default class Downloads extends React.Component<IProps, IState> {
}
async downloadResources() {
// 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.'
)
this.props.downloadManager.addDownload(RESOURCES_DOWNLOAD, folder + '/resources.zip', async () => {
// Delete the existing folder if it exists
if (
await invoke('dir_exists', {
path: folder + '\\resources',
path: folder + '/resources',
})
) {
await invoke('dir_delete', {
path: folder + '\\resources',
path: folder + '/resources',
})
}
await unzip(folder + '\\resources.zip', folder + '\\', true)
await unzip(folder + '/resources.zip', folder + '/', true)
// Rename folder to resources
invoke('rename', {
path: folder + '\\Resources',
path: folder + '/Resources',
newName: 'resources',
})
@@ -220,13 +216,13 @@ export default class Downloads extends React.Component<IProps, IState> {
}
async downloadMigoto() {
const folder = (await this.getCultivationFolder()) + '\\3dmigoto'
const folder = (await this.getCultivationFolder()) + '/3dmigoto'
await invoke('dir_create', {
path: folder,
})
this.props.downloadManager.addDownload(MIGOTO_DOWNLOAD, folder + '\\GIMI-3dmigoto.zip', async () => {
await unzip(folder + '\\GIMI-3dmigoto.zip', folder + '\\', true)
this.props.downloadManager.addDownload(MIGOTO_DOWNLOAD, folder + '/GIMI-3dmigoto.zip', async () => {
await unzip(folder + '/GIMI-3dmigoto.zip', folder + '/', true)
this.toggleButtons()
})
@@ -260,6 +256,7 @@ export default class Downloads extends React.Component<IProps, IState> {
<Tr text={'downloads.grasscutter_fullbuild'} />
<HelpButton contents="help.gc_fullbuild" />
</div>
<div className="DownloadValue" id="downloadMenuButtonGCFullBuild">
<BigButton
disabled={this.state.grasscutter_downloading}
@@ -271,25 +268,23 @@ export default class Downloads extends React.Component<IProps, IState> {
</div>
</div>
<Divider />
{/* <div className="DownloadMenuSection" id="downloadMenuContainerGCStable">
<div className="DownloadLabel" id="downloadMenuLabelGCStable">
<Tr
text={this.state.grasscutter_set ? 'downloads.grasscutter_stable' : 'downloads.grasscutter_stable_update'}
/>
<HelpButton contents="help.gc_stable_jar" />
<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="downloadMenuButtonGCStable">
<div className="DownloadValue" id="downloadMenuButtonGCFullQuest">
<BigButton
disabled={this.state.grasscutter_downloading}
onClick={this.downloadGrasscutterStable}
id="grasscutterStableBtn"
onClick={this.downloadGrasscutterFullQuest}
id="grasscutterFullBuildBtn"
>
<Tr text="components.download" />
</BigButton>
</div>
</div> */}
</div>
<Divider />
<div className="HeaderText" id="downloadMenuIndividualHeader">
<Tr text="downloads.individual_header" />
</div>
@@ -311,27 +306,6 @@ export default class Downloads extends React.Component<IProps, IState> {
</div>
</div>
{/* <div className="DownloadMenuSection" id="downloadMenuContainerGCStableData">
<div className="DownloadLabel" id="downloadMenuLabelGCStableData">
<Tr
text={
this.state.grasscutter_set
? 'downloads.grasscutter_stable_data'
: 'downloads.grasscutter_stable_data_update'
}
/>
<HelpButton contents="help.gc_stable_data" />
</div>
<div className="DownloadValue" id="downloadMenuButtonGCStableData">
<BigButton
disabled={this.state.repo_downloading}
onClick={this.downloadGrasscutterStableRepo}
id="grasscutterStableRepo"
>
<Tr text="components.download" />
</BigButton>
</div>
</div> */}
<div className="DownloadMenuSection" id="downloadMenuContainerGCDevData">
<div className="DownloadLabel" id="downloadMenuLabelGCDevData">
<Tr

View File

@@ -45,8 +45,8 @@ export default class Downloads extends React.Component<IProps, IState> {
async downloadGame() {
const folder = this.state.gameDownloadFolder
this.props.downloadManager.addDownload(GAME_DOWNLOAD, folder + '\\game.zip', async () => {
await unzip(folder + '\\game.zip', folder + '\\', true)
this.props.downloadManager.addDownload(GAME_DOWNLOAD, folder + '/game.zip', async () => {
await unzip(folder + '/game.zip', folder + '/', true)
this.setState({
gameDownloading: false,
})

View File

@@ -0,0 +1,15 @@
.GameInstallNotify {
display: flex;
justify-content: center;
background-color: rgb(39, 39, 39);
color: white;
}
.GameInstallNotify span {
padding: 10px 0;
}
#pointer {
position: absolute;
right: 85px;
}

View File

@@ -0,0 +1,15 @@
import React from 'react'
import './GamePathNotify.css'
import Tr from '../../../utils/language'
export default class GamePathNotify extends React.Component {
render() {
return (
<div className="GameInstallNotify">
<span>
<Tr text={'main.game_path_notify'} />
</span>
</div>
)
}
}

View File

@@ -15,9 +15,14 @@ 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'
export enum GrasscutterElevation {
None = 'None',
Capability = 'Capability',
Root = 'Root',
}
interface IProps {
closeFn: () => void
downloadManager: DownloadHandler
@@ -33,6 +38,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 +48,10 @@ interface IState {
swag: boolean
platform: string
un_elevated: boolean
redirect_more: boolean
// Linux stuff
grasscutter_elevation: string
// Swag stuff
akebi_path: string
@@ -63,6 +73,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 +83,10 @@ export default class Options extends React.Component<IProps, IState> {
auto_mongodb: false,
platform: '',
un_elevated: false,
redirect_more: false,
// Linux stuff
grasscutter_elevation: GrasscutterElevation.None,
// Swag stuff
akebi_path: '',
@@ -97,10 +112,13 @@ export default class Options extends React.Component<IProps, IState> {
const languages = await getLanguages()
const platform: string = await invoke('get_platform')
// Remove jar from path
const path = config.grasscutter_path.replace(/\\/g, '/')
const folderPath = path.substring(0, path.lastIndexOf('/'))
const encEnabled = await server.encryptionEnabled(folderPath + '/config.json')
let encEnabled
if (config.grasscutter_path) {
// Remove jar from path
const path = config.grasscutter_path.replace(/\\/g, '/')
const folderPath = path.substring(0, path.lastIndexOf('/'))
encEnabled = await server.encryptionEnabled(folderPath + '/config.json')
}
console.log(platform)
@@ -111,9 +129,10 @@ export default class Options extends React.Component<IProps, IState> {
grasscutter_with_game: config.grasscutter_with_game || false,
language_options: languages,
current_language: config.language || 'en',
bg_url_or_path: config.customBackground || '',
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 +142,10 @@ 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,
// Linux stuff
grasscutter_elevation: config.grasscutter_elevation || GrasscutterElevation.None,
// Swag stuff
akebi_path: config.akebi_path || '',
@@ -147,6 +170,13 @@ export default class Options extends React.Component<IProps, IState> {
)
}
// If setting any other game, automatically set to redirect more
if (!value.toLowerCase().includes('genshin' || 'yuanshen')) {
if (!this.state.redirect_more) {
this.toggleOption('redirect_more')
}
}
this.setState({
game_install_path: value,
})
@@ -194,11 +224,6 @@ export default class Options extends React.Component<IProps, IState> {
this.setState({
migoto_path: value,
})
// Set game exe in Migoto ini
invoke('set_migoto_target', {
migotoPath: value,
})
}
setReshade(value: string) {
@@ -231,13 +256,13 @@ export default class Options extends React.Component<IProps, IState> {
async setCustomBackground(value: string) {
const isUrl = /^(?:http(s)?:\/\/)/gm.test(value)
if (!value) return await setConfigOption('customBackground', '')
if (!value) return await setConfigOption('custom_background', '')
if (!isUrl) {
const filename = value.replace(/\\/g, '/').split('/').pop()
const localBgPath = ((await dataDir()) as string).replace(/\\/g, '/')
const localBgPath = (await dataDir()).replace(/\\/g, '/')
await setConfigOption('customBackground', `${localBgPath}/cultivation/bg/${filename}`)
await setConfigOption('custom_background', `${localBgPath}/cultivation/bg/${filename}`)
// Copy the file over to the local directory
await invoke('copy_file', {
@@ -247,7 +272,7 @@ export default class Options extends React.Component<IProps, IState> {
window.location.reload()
} else {
await setConfigOption('customBackground', value)
await setConfigOption('custom_background', value)
window.location.reload()
}
}
@@ -287,6 +312,14 @@ 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()
}
@@ -317,25 +350,14 @@ export default class Options extends React.Component<IProps, IState> {
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" />
@@ -393,6 +415,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 />
@@ -423,6 +457,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 />
@@ -468,18 +531,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">
@@ -518,6 +583,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">
@@ -541,7 +619,7 @@ export default class Options extends React.Component<IProps, IState> {
readonly={false}
clearable={true}
customClearBehaviour={async () => {
await setConfigOption('customBackground', '')
await setConfigOption('custom_background', '')
window.location.reload()
}}
/>

View File

@@ -124,7 +124,7 @@ export default class NewsSection extends React.Component<IProps, IState> {
case 'latest_version':
news = (
<tr>
<td>Latest version: Grasscutter 1.4.8 - Cultivation 1.0.27</td>
<td>Latest version: Grasscutter 1.7.0 - Cultivation 1.2.0</td>
</tr>
)
break

View File

@@ -15,7 +15,8 @@ let defaultConfig: Configuration
last_ip: 'localhost',
last_port: '443',
language: 'en',
customBackground: '',
custom_background: '',
use_theme_background: false,
cert_generated: false,
theme: 'default',
https_enabled: false,
@@ -26,6 +27,10 @@ let defaultConfig: Configuration
horny_mode: false,
auto_mongodb: false,
un_elevated: false,
redirect_more: false,
// Linux stuff
grasscutter_elevation: 'None',
}
})()
@@ -43,7 +48,8 @@ export interface Configuration {
last_ip: string
last_port: string
language: string
customBackground: string
custom_background: string
use_theme_background: boolean
cert_generated: boolean
theme: string
https_enabled: boolean
@@ -55,6 +61,10 @@ export interface Configuration {
swag_mode?: boolean
auto_mongodb: boolean
un_elevated: boolean
redirect_more: boolean
// Linux stuff
grasscutter_elevation: string
// Swag stuff
akebi_path?: string
@@ -116,7 +126,7 @@ async function readConfigFile() {
await fs.createDir(local + 'cultivation').catch((e) => console.log(e))
}
const innerDirs = await fs.readDir(local + '/cultivation')
const innerDirs = await fs.readDir(local + 'cultivation')
// Create grasscutter dir for potential installation
if (!innerDirs.find((fileOrDir) => fileOrDir?.name === 'grasscutter')) {

View File

@@ -45,7 +45,7 @@ export async function getGameDataFolder() {
return null
}
return (await getGameFolder()) + '\\' + gameExec.replace('.exe', '_Data')
return (await getGameFolder()) + '/' + gameExec.replace('.exe', '_Data')
}
export async function getGameVersion() {
@@ -57,7 +57,7 @@ export async function getGameVersion() {
const settings = JSON.parse(
await invoke('read_file', {
path: GameData + '\\StreamingAssets\\asb_settings.json',
path: GameData + '/StreamingAssets/asb_settings.json',
})
)

View File

@@ -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
return invoke('patch_game')
}
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')
}

View File

@@ -40,7 +40,7 @@ const defaultTheme = {
export async function getThemeList() {
// Do some invoke to backend to get the theme list
const themes = (await invoke('get_theme_list', {
dataDir: `${await dataDir()}/cultivation`,
dataDir: `${await dataDir()}cultivation`,
})) as BackendThemeList[]
const list: ThemeList[] = [
// ALWAYS include default theme
@@ -89,31 +89,35 @@ export async function loadTheme(theme: ThemeList, document: Document) {
const jsIncludes = theme.includes.js
// Load CSS files
cssIncludes.forEach((css) => {
if (!css) return
if (cssIncludes) {
cssIncludes?.forEach((css) => {
if (!css) return
const link = document.createElement('link')
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = convertFileSrc(theme.path + '/' + css)
head.appendChild(link)
})
link.rel = 'stylesheet'
link.href = convertFileSrc(theme.path + '/' + css)
head.appendChild(link)
})
}
// Load JS files
jsIncludes.forEach((js) => {
if (!js) return
if (jsIncludes) {
jsIncludes.forEach((js) => {
if (!js) return
const script = document.createElement('script')
const script = document.createElement('script')
script.src = convertFileSrc(theme.path + '/' + js)
head.appendChild(script)
})
script.src = convertFileSrc(theme.path + '/' + js)
head.appendChild(script)
})
}
// Set custom background
if (theme.customBackgroundURL) {
// If the custom bg is already set don't overwrite
if (config.customBackground === '') {
config.customBackground = theme.customBackgroundURL
// 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
}
}
@@ -129,14 +133,14 @@ export async function loadTheme(theme: ThemeList, document: Document) {
})
// Set the background
// If the custom bg is already set don't overwrite
if (config.customBackground === '') {
config.customBackground = bgPath + imageName
// 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
}
}
// Write config
await setConfigOption('customBackground', config.customBackground)
await setConfigOption('custom_background', config.custom_background)
return
}

View File

@@ -2385,7 +2385,7 @@ acorn@^7.0.0, acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1:
acorn@^8.2.4, acorn@^8.5.0, acorn@^8.7.1:
version "8.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
@@ -3570,9 +3570,9 @@ decimal.js@^10.2.1:
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==
version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
dedent@^0.7.0:
version "0.7.0"
@@ -3859,10 +3859,10 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
enhanced-resolve@^5.9.3:
version "5.10.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
enhanced-resolve@^5.10.0:
version "5.12.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634"
integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
@@ -5867,9 +5867,9 @@ json-stable-stringify-without-jsonify@^1.0.1:
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
version "1.0.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
dependencies:
minimist "^1.2.0"
@@ -6248,9 +6248,9 @@ minimatch@^5.0.1:
brace-expansion "^2.0.1"
minimist@^1.2.0, minimist@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
version "1.2.7"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
mkdirp@~0.5.1:
version "0.5.6"
@@ -7381,6 +7381,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 +7930,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 +8573,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 +8722,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 +8762,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"
@@ -8826,7 +8840,7 @@ walker@^1.0.7:
dependencies:
makeerror "1.0.12"
watchpack@^2.3.1:
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
@@ -8937,20 +8951,20 @@ webpack-sources@^3.2.3:
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@^5.64.4:
version "5.73.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.73.0.tgz#bbd17738f8a53ee5760ea2f59dce7f3431d35d38"
integrity sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==
version "5.76.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.1.tgz#7773de017e988bccb0f13c7d75ec245f377d295c"
integrity sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==
dependencies:
"@types/eslint-scope" "^3.7.3"
"@types/estree" "^0.0.51"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/wasm-edit" "1.11.1"
"@webassemblyjs/wasm-parser" "1.11.1"
acorn "^8.4.1"
acorn "^8.7.1"
acorn-import-assertions "^1.7.6"
browserslist "^4.14.5"
chrome-trace-event "^1.0.2"
enhanced-resolve "^5.9.3"
enhanced-resolve "^5.10.0"
es-module-lexer "^0.9.0"
eslint-scope "5.1.1"
events "^3.2.0"
@@ -8963,7 +8977,7 @@ webpack@^5.64.4:
schema-utils "^3.1.0"
tapable "^2.1.1"
terser-webpack-plugin "^5.1.3"
watchpack "^2.3.1"
watchpack "^2.4.0"
webpack-sources "^3.2.3"
websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
@@ -9041,9 +9055,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"