mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-14 16:14:48 +01:00
Compare commits
61 Commits
v1.0.22-al
...
more_cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c88e3ce3a7 | ||
|
|
e5d151f512 | ||
|
|
361737c00d | ||
|
|
0f08bb5fbf | ||
|
|
df674abd94 | ||
|
|
c21c5ac0b1 | ||
|
|
6ac0182784 | ||
|
|
2fa203163d | ||
|
|
75c6481778 | ||
|
|
12b60d3b2a | ||
|
|
88b5b40300 | ||
|
|
45ecfcbeb3 | ||
|
|
e6492825dc | ||
|
|
3141bcea41 | ||
|
|
64a04e927c | ||
|
|
4bcfd7ec09 | ||
|
|
a67eca49e5 | ||
|
|
48dff50a5d | ||
|
|
5480af7835 | ||
|
|
829b9822cb | ||
|
|
a6716e80f4 | ||
|
|
6962518ced | ||
|
|
09d0d8287f | ||
|
|
7bfa5e8e11 | ||
|
|
5de80f1655 | ||
|
|
33ce547bb2 | ||
|
|
864f9f199c | ||
|
|
5d8e4d7311 | ||
|
|
9f0567da6a | ||
|
|
56453ff55b | ||
|
|
61c5cc8d57 | ||
|
|
7bbc7e3c10 | ||
|
|
5b7c1307d9 | ||
|
|
096992572c | ||
|
|
68f0cce154 | ||
|
|
19db69646f | ||
|
|
82f40186fe | ||
|
|
d7b2aa25cc | ||
|
|
3356bddb42 | ||
|
|
db11cf7907 | ||
|
|
891dbb41aa | ||
|
|
cf6ec3da82 | ||
|
|
b2d6f390fb | ||
|
|
a920d70e53 | ||
|
|
d2e7759eec | ||
|
|
77380e357c | ||
|
|
33ddc36741 | ||
|
|
bbd18d33e9 | ||
|
|
b66f01232b | ||
|
|
b6a2e4dbc0 | ||
|
|
45ee8fbb23 | ||
|
|
78c2a8d0c8 | ||
|
|
fe420e9837 | ||
|
|
57576f399b | ||
|
|
8d45b3d11d | ||
|
|
1ff96f9c7e | ||
|
|
e834022ca7 | ||
|
|
c72e502603 | ||
|
|
5d6bd72083 | ||
|
|
ef3ba2a045 | ||
|
|
90b86b42d0 |
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"rust-analyzer.linkedProjects": [".\\src-tauri\\Cargo.toml"]
|
||||
}
|
||||
16
README.md
16
README.md
@@ -9,6 +9,7 @@ A game launcher designed to easily proxy traffic from anime game to private serv
|
||||
- [Client Patching Notice](#client-patching-notice)
|
||||
- [Download](#download)
|
||||
- [Setup](#setup)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Developer Quick-start](#developer-quickstart)
|
||||
- [Setup](#setup)
|
||||
- [Building](#building)
|
||||
@@ -37,7 +38,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 Linux or MacOS, [help us port Windows-specific system calls to Linux/MacOS!](https://github.com/Grasscutters/Cultivation/issues/7)
|
||||
- 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_**
|
||||
- Before clicking randomly on stuff, in options (top right cog icon), set your Game Install Path.
|
||||
@@ -57,6 +58,19 @@ Download and open the MSI, and once installed, run Cultivation as administrator.
|
||||
- Any specific Cultivation issues should go in [the issues section](/issues)
|
||||
- Any Grasscutter server related issues should go in [the Grasscutter issues section](https://github.com/Grasscutters/Grasscutter)
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
### White screen, insta-crash or something similar
|
||||
|
||||
- First try [running in Windows 8 compatibility mode](https://www.lifewire.com/run-older-programs-with-windows-10-compatibility-mode-4587064).
|
||||
- If that doesn't work, fully uninstall and reinstall [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section).
|
||||
- If you are having trouble uninstalling it, try deleting this registry folder and uninstalling again `Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}`
|
||||
- You can also try [uninstalling from the Command Prompt](https://superuser.com/a/1743626)
|
||||
|
||||
### Internet not working after use
|
||||
|
||||
Please allow the Cultivation window to pop back up once you have quit out of the game. This tells you that it knows you closed the game, and that it has reverted your proxy settings. If you have closed Cultivation before this happens, or have had some other issue with your internet, go to your [proxy settings in Windows](https://techviral.net/check-proxy-server-settings-in-windows/) and disable the "Manual proxy setup".
|
||||
|
||||
# Developer Quickstart
|
||||
|
||||
### Setup
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cultivation",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.26",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.0.0-rc.5",
|
||||
|
||||
331
src-tauri/Cargo.lock
generated
331
src-tauri/Cargo.lock
generated
@@ -76,6 +76,16 @@ version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
||||
|
||||
[[package]]
|
||||
name = "args"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4b7432c65177b8d5c032d56e020dd8d407e939468479fc8c300e2d93e6d970b"
|
||||
dependencies = [
|
||||
"getopts",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asn1-rs"
|
||||
version = "0.3.1"
|
||||
@@ -258,6 +268,21 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -270,6 +295,15 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.2"
|
||||
@@ -620,6 +654,21 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
@@ -741,11 +790,13 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
||||
name = "cultivation"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"args",
|
||||
"cc",
|
||||
"ctrlc",
|
||||
"duct",
|
||||
"file_diff",
|
||||
"futures-util",
|
||||
"getopts",
|
||||
"http",
|
||||
"hudsucker",
|
||||
"is_elevated",
|
||||
@@ -759,6 +810,7 @@ dependencies = [
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sevenz-rust",
|
||||
"sudo",
|
||||
"sysinfo",
|
||||
"tauri",
|
||||
@@ -768,6 +820,7 @@ dependencies = [
|
||||
"tokio-tungstenite 0.17.2",
|
||||
"tracing",
|
||||
"unrar",
|
||||
"windows-service",
|
||||
"zip 0.6.2",
|
||||
"zip-extract",
|
||||
]
|
||||
@@ -884,13 +937,22 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"block-buffer 0.10.2",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
@@ -1051,14 +1113,25 @@ checksum = "31a7a908b8f32538a2143e59a6e4e2508988832d5d4d6f7c156b3cbc762643a5"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.17"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
|
||||
checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime_creation"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d961767622336521cc48b3de810fce4edbf02d0c21079d78f3a6eeaf45b9450"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"filetime",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1326,6 +1399,15 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
@@ -1566,7 +1648,7 @@ version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1906,9 +1988,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.58"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
|
||||
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -2000,6 +2082,15 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lzma-rust"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808dc37ccba979c213304880eadaab444bb522a5fe79acca9e90ec62377125c2"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
version = "0.1.1"
|
||||
@@ -2111,7 +2202,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys",
|
||||
"windows-sys 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2465,7 +2556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f23a407004a1033f53e93f9b45580d14de23928faad187384f891507c9b0c045"
|
||||
dependencies = [
|
||||
"pathdiff",
|
||||
"windows-sys",
|
||||
"windows-sys 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2630,7 +2721,7 @@ dependencies = [
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
"windows-sys 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2662,10 +2753,10 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"digest 0.10.6",
|
||||
"hmac",
|
||||
"password-hash",
|
||||
"sha2",
|
||||
"sha2 0.10.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3406,7 +3497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys",
|
||||
"windows-sys 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3618,6 +3709,22 @@ dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sevenz-rust"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12eea80650ae08d8fe6f657d6249d757298bc7a241e00d190ac57cef0e74e02"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"byteorder",
|
||||
"crc",
|
||||
"filetime_creation",
|
||||
"js-sys",
|
||||
"lzma-rust",
|
||||
"sha2 0.9.9",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.10.1"
|
||||
@@ -3626,7 +3733,7 @@ checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3637,7 +3744,20 @@ checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3648,7 +3768,7 @@ checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4064,7 +4184,7 @@ dependencies = [
|
||||
"semver 1.0.12",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sha2 0.10.2",
|
||||
"tauri-utils",
|
||||
"thiserror",
|
||||
"time 0.3.11",
|
||||
@@ -4525,6 +4645,12 @@ version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.3"
|
||||
@@ -4702,9 +4828,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -4712,13 +4838,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -4739,9 +4865,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -4749,9 +4875,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4762,9 +4888,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
@@ -4888,6 +5014,12 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
|
||||
|
||||
[[package]]
|
||||
name = "wildmatch"
|
||||
version = "2.1.1"
|
||||
@@ -4990,6 +5122,17 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f33f2b90a6664e369c41ab5ff262d06f048fc9685d9bf8a0e99a47750bb0463"
|
||||
|
||||
[[package]]
|
||||
name = "windows-service"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd9db37ecb5b13762d95468a2fc6009d4b2c62801243223aabd44fca13ad13c8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"widestring",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
@@ -5003,12 +5146,72 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.0",
|
||||
"windows_aarch64_msvc 0.48.0",
|
||||
"windows_i686_gnu 0.48.0",
|
||||
"windows_i686_msvc 0.48.0",
|
||||
"windows_x86_64_gnu 0.48.0",
|
||||
"windows_x86_64_gnullvm 0.48.0",
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-tokens"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3263d25f1170419995b78ff10c06b949e8a986c35c208dc24333c64753a87169"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.32.0"
|
||||
@@ -5027,6 +5230,18 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.24.0"
|
||||
@@ -5051,6 +5266,18 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.24.0"
|
||||
@@ -5075,6 +5302,18 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.24.0"
|
||||
@@ -5099,6 +5338,30 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.24.0"
|
||||
@@ -5123,6 +5386,18 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
|
||||
@@ -26,6 +26,10 @@ sudo = "0.6.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.0.7", features = ["api-all"] }
|
||||
|
||||
# Arg parsing
|
||||
args = "2.0"
|
||||
getopts = "0.2"
|
||||
|
||||
# Access system process info.
|
||||
sysinfo = "0.24.6"
|
||||
|
||||
@@ -33,6 +37,7 @@ sysinfo = "0.24.6"
|
||||
zip-extract = "0.1.1"
|
||||
unrar = "0.4.4"
|
||||
zip = "0.6.2"
|
||||
sevenz-rust = "0.2.9"
|
||||
|
||||
# For creating a "global" downloads list.
|
||||
once_cell = "1.13.0"
|
||||
@@ -41,6 +46,9 @@ once_cell = "1.13.0"
|
||||
open = "3.0.2"
|
||||
duct = "0.13.5"
|
||||
|
||||
# Services
|
||||
windows-service = "0.6.0"
|
||||
|
||||
# Serialization.
|
||||
serde_json = "1"
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"patch_rsa": "自动修改RSA",
|
||||
"use_proxy": "使用内置代理",
|
||||
"wipe_login": "清除登录缓存",
|
||||
"horny_mode": "Horny 模式"
|
||||
"horny_mode": "Horny 模式",
|
||||
"auto_mongodb": "自动启动 MongoDB",
|
||||
"un_elevated": "非提升运行游戏(无管理员)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "下载 Grasscutter 一体化",
|
||||
@@ -43,7 +45,9 @@
|
||||
"resources": "下载 Grasscutter 资源",
|
||||
"game": "下载游戏",
|
||||
"aio_header": "多合一下载:",
|
||||
"individual_header": "个别部分下载:"
|
||||
"individual_header": "个别部分下载:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "下载 GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "下载中",
|
||||
@@ -75,7 +79,9 @@
|
||||
"resources": "资源文件在运行 Grasscutter 服务器时是必要的。此选项在已经存在资源文件时不可选。",
|
||||
"emergency_rsa": "在出现意外情况时自动将 RSA 恢复到原始版本",
|
||||
"use_proxy": "使用 Cultivation 的内置代理。除非你使用 Fiddler 等软件,否则应启用此项。",
|
||||
"patch_rsa": "自动修改和恢复 RSA 补丁。 除非您玩的是旧版/非官方版本,或者您手动修改了 RSA,否则应该启用此功能。"
|
||||
"patch_rsa": "自动修改和恢复 RSA 补丁。 除非您玩的是旧版/非官方版本,或者您手动修改了 RSA,否则应该启用此功能。",
|
||||
"add_delay": "在 3dmigoto 加载程序中设置延迟! \n这应该可以解决加载问题,但会在启动游戏时加载 3dmigoto 时增加一点延迟。 \n您现在可以再次使用 3dmigoto 启动。",
|
||||
"migoto": "用于从 GameBanana 导入模型"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"patch_rsa": "自動修補RSA",
|
||||
"use_proxy": "使用內建代理伺服器",
|
||||
"wipe_login": "擦除登錄緩存",
|
||||
"horny_mode": "Horny模式"
|
||||
"horny_mode": "Horny模式",
|
||||
"auto_mongodb": "自動啟動 MongoDB",
|
||||
"un_elevated": "在不升高的情况下运行游戏(没有管理员)。"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "下載Grasscutter多合一下載",
|
||||
@@ -43,7 +45,9 @@
|
||||
"resources": "下載Grasscutter資源(Resources)",
|
||||
"game": "下載遊戲",
|
||||
"aio_header": "多合一下載:",
|
||||
"individual_header": "個別部分下載:"
|
||||
"individual_header": "個別部分下載:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "下載GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "下載中",
|
||||
@@ -75,7 +79,9 @@
|
||||
"resources": "資源文件在架設一個Grasscutter伺服器時是必要的。 這個選項會在您已經有裡面有檔案的資源資料夾時不可選。",
|
||||
"emergency_rsa": "一旦有東西出了問題,此選項可以把您的rsa恢復成官方版本。",
|
||||
"use_proxy": "使用Cultivation內建的代理伺服器。此選項應該被啟用,除非你使用其他的代理伺服器。",
|
||||
"patch_rsa": "自動修補和恢復RSA。除非您的遊戲版本是舊的或者是非官方的,此選項應該被啟用。"
|
||||
"patch_rsa": "自動修補和恢復RSA。除非您的遊戲版本是舊的或者是非官方的,此選項應該被啟用。",
|
||||
"add_delay": "在 3dmigoto 加載程序中設置延遲! \n這應該可以解決加載問題,但會在啟動遊戲時加載 3dmigoto 時增加一點延遲。 \n您現在可以再次使用 3dmigoto 啟動。",
|
||||
"migoto": "用於從 GameBanana 導入模型"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
"patch_rsa": "RSA automatisch patchen",
|
||||
"use_proxy": "Gebruik interne proxy",
|
||||
"wipe_login": "Wis de inlogcache",
|
||||
"horny_mode": "Geile modus"
|
||||
"horny_mode": "Geile modus",
|
||||
"auto_mongodb": "Start automatisch MongoDB",
|
||||
"un_elevated": "Führen Sie das Spiel nicht erhöht aus (kein Admin)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Alles in Einem Grasscutter Daten herunterladen",
|
||||
@@ -42,7 +44,9 @@
|
||||
"resources": "Grasscutter Ressourcen herunterladen",
|
||||
"game": "Spiel herunterladen",
|
||||
"aio_header": "Alles in Einem herunterladen",
|
||||
"individual_header": "Einzelne Teile herunterladen:"
|
||||
"individual_header": "Einzelne Teile herunterladen:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "GIMI 3dmigoto herunterladen"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Lädt herunter",
|
||||
@@ -73,7 +77,9 @@
|
||||
"resources": "Diese werden auch benötigt, um einen Grasscutter-Server auszuführen. Diese Schaltfläche ist grau, wenn Sie einen bestehenden Ressourcenordner mit Inhalten haben",
|
||||
"emergency_rsa": "Im Fall, dass etwas schief laufen sollte, kannst du deine RSA auf die letzte offizielle Version zurücksetzen",
|
||||
"use_proxy": "Nutze den internen Proxy von Cultivation. Du solltest dies aktivieren, es sei denn du nutzt Programme wie Fiddler",
|
||||
"patch_rsa": "Patche und aktualisiere deine RSA automatisch. Solange du nicht mit einer alten/nicht offiziellen Version spielst oder deine RSA manuell gepatcht hast, sollte dies aktiviert sein."
|
||||
"patch_rsa": "Patche und aktualisiere deine RSA automatisch. Solange du nicht mit einer alten/nicht offiziellen Version spielst oder deine RSA manuell gepatcht hast, sollte dies aktiviert sein.",
|
||||
"add_delay": "Verzögerung im 3dmigoto-Lader einstellen! \nDies sollte die Ladeprobleme beheben, führt aber zu einer kleinen Verzögerung, wenn 3dmigoto beim Start des Spiels geladen wird. \nSie können nun wieder mit 3dmigoto starten.",
|
||||
"migoto": "Zum Importieren von Modellen von GameBanana"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"patch_rsa": "Automatically Patch RSA",
|
||||
"use_proxy": "Use Internal Proxy",
|
||||
"wipe_login": "Wipe Login Cache",
|
||||
"horny_mode": "Horny Mode"
|
||||
"horny_mode": "Horny Mode",
|
||||
"auto_mongodb": "Automatically Start MongoDB",
|
||||
"un_elevated": "Run the game non-elevated (no admin)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Download Grasscutter All-in-One",
|
||||
@@ -43,7 +45,9 @@
|
||||
"resources": "Download Grasscutter Resources",
|
||||
"game": "Download Game",
|
||||
"aio_header": "All-in-One Downloads:",
|
||||
"individual_header": "Individual downloads:"
|
||||
"individual_header": "Individual downloads:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Download GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Downloading",
|
||||
@@ -75,7 +79,9 @@
|
||||
"resources": "These are also required to run a Grasscutter server. This button will be grey if you have an existing resources folder with contents inside",
|
||||
"emergency_rsa": "In case something went wrong, force delete RSA patch.",
|
||||
"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."
|
||||
"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"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
@@ -26,9 +26,11 @@
|
||||
"background": "Establecer Fondo Personalizado (link o archivo de imagen)",
|
||||
"patch_rsa": "Parchear RSA automáticamente",
|
||||
"theme": "Establecer Tema",
|
||||
"use_proxy": "Use Internal Proxy",
|
||||
"wipe_login": "Wipe Login Cache",
|
||||
"horny_mode": "Horny Mode"
|
||||
"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)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Descargar Datos todo en uno de Grasscutter",
|
||||
@@ -43,7 +45,9 @@
|
||||
"resources": "Descargar Recursos de Grasscutter",
|
||||
"game": "Descarga el juego",
|
||||
"aio_header": "Descargas todo en uno:",
|
||||
"individual_header": "Descargas de piezas individuales:"
|
||||
"individual_header": "Descargas de piezas individuales:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Descargar GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Descargando",
|
||||
@@ -71,7 +75,9 @@
|
||||
"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."
|
||||
"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"
|
||||
},
|
||||
"swag": {
|
||||
"akebi": "Establecer el ejecutable de Akebi"
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"patch_rsa": "Corriger automatiquement les RSA",
|
||||
"use_proxy": "Utiliser un proxy interne",
|
||||
"wipe_login": "Effacer le cache de connexion",
|
||||
"horny_mode": "Mode excitation"
|
||||
"horny_mode": "Mode excitation",
|
||||
"auto_mongodb": "Démarrer automatiquement MongoDB",
|
||||
"un_elevated": "Exécuter le jeu sans élévation (pas d'administrateur)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Telecharger Grasscutter tout-en-un",
|
||||
@@ -42,7 +44,9 @@
|
||||
"grasscutter_latest_update": "Mettre a jour Grasscutter (derniere version)",
|
||||
"resources": "Telecharger les ressources logicielles de Grasscutter",
|
||||
"aio_header": "Telechargements tout-en-un:",
|
||||
"individual_header": "Telechargements de pièces individuelles:"
|
||||
"individual_header": "Telechargements de pièces individuelles:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Telecharger GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Telechargement",
|
||||
@@ -70,6 +74,8 @@
|
||||
"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",
|
||||
"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."
|
||||
"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.",
|
||||
"migoto": "Pour importer des modèles depuis GameBanana"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
"patch_rsa": "Automatically Patch RSA",
|
||||
"use_proxy": "Gunakan Proxy Internal",
|
||||
"wipe_login": "Menghapus Cache Login",
|
||||
"horny_mode": "Mode Terangsang"
|
||||
"horny_mode": "Mode Terangsang",
|
||||
"auto_mongodb": "Mulai MongoDB secara otomatis",
|
||||
"un_elevated": "Jalankan game yang tidak ditinggikan (tanpa admin)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Sedang Mendownload Grasscutter Semua Dalam Satu",
|
||||
@@ -41,7 +43,9 @@
|
||||
"grasscutter_latest_update": "Sedang MengUpdate Grasscutter Terbaru",
|
||||
"resources": "Mendownload Grasscutter Resources",
|
||||
"aio_header": "Unduhan Semua Dalam Satu:",
|
||||
"individual_header": "Unduhan Bagian Individual:"
|
||||
"individual_header": "Unduhan Bagian Individual:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Sedang Mendownload GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Sedang Mendownload",
|
||||
@@ -68,6 +72,8 @@
|
||||
"gc_dev_jar": "Unduh Build Development Grasscutter saat ini, Dimana Ada Jar File Dan Data File.",
|
||||
"gc_stable_data": "Unduh file data Grasscutter stabil saat ini, dimana Tidak Ada JAR file. Ini Berguna Untuk memperbarui.",
|
||||
"gc_dev_data": "Unduh file data Grasscutter Development saat ini, dimana Tidak Ada JAR file. Ini Berguna Untuk memperbarui.",
|
||||
"resources": "Ini juga diperlukan untuk menjalankan server Grasscutter. Tombol ini akan berwarna abu-abu jika Anda memiliki folder Resource yang ada dengan File di dalamnya"
|
||||
"resources": "Ini juga diperlukan untuk menjalankan server Grasscutter. Tombol ini akan berwarna abu-abu jika Anda memiliki folder Resource yang ada dengan File di dalamnya",
|
||||
"add_delay": "Atur penundaan di pemuat 3dmigoto! \nIni akan memperbaiki masalah pemuatan, tetapi akan menambah sedikit penundaan ketika 3dmigoto dimuat saat meluncurkan game. \nAnda sekarang dapat meluncurkan dengan 3dmigoto lagi.",
|
||||
"migoto": "Untuk mengimpor model dari GameBanana"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"patch_rsa": "RSA 패치 자동 적용",
|
||||
"use_proxy": "내부 프록시 사용",
|
||||
"wipe_login": "로그인 캐시 지우기",
|
||||
"horny_mode": "Horny 모드"
|
||||
"horny_mode": "Horny 모드",
|
||||
"auto_mongodb": "MongoDB 자동 시작",
|
||||
"un_elevated": "게임 비상승 실행(관리자 없음)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "올인원 Grasscutter 다운로드",
|
||||
@@ -43,7 +45,9 @@
|
||||
"resources": "리소스 다운로드",
|
||||
"game": "게임 다운로드",
|
||||
"aio_header": "올인원 다운로드",
|
||||
"individual_header": "개별 부품 다운로드:"
|
||||
"individual_header": "개별 부품 다운로드:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "GIMI 3dmigoto 다운로드"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "다운로드 중",
|
||||
@@ -75,7 +79,9 @@
|
||||
"resources": "또한 Grasscutter 서버를 실행하는 데도 필요합니다. 내용이 포함된 기존 리소스 폴더가 있는 경우 이 버튼은 회색으로 표시됩니다",
|
||||
"emergency_rsa": "문제가 있는 경우 RSA 패치를 제거하십시오.",
|
||||
"use_proxy": "Culturation 내부 프록시를 사용합니다. 피들러와 같은 것을 사용하지 않는 한 이 기능을 활성화해야 합니다",
|
||||
"patch_rsa": "게임 RSA를 자동으로 패치 및 패치 해제합니다. 이전/비공식 버전을 사용하거나 RSA를 수동으로 패치하지 않은 경우 이 기능을 활성화해야 합니다."
|
||||
"patch_rsa": "게임 RSA를 자동으로 패치 및 패치 해제합니다. 이전/비공식 버전을 사용하거나 RSA를 수동으로 패치하지 않은 경우 이 기능을 활성화해야 합니다.",
|
||||
"add_delay": "3dmigoto 로더에서 지연을 설정하세요! \n이렇게하면 로딩 문제가 해결되지만 게임을 시작할 때 3dmigoto가로드되는시기에 약간의 지연이 추가됩니다. \n이제 3dmigoto로 다시 시작할 수 있습니다.",
|
||||
"migoto": "GameBanana에서 모델 가져오기"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
"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"
|
||||
"horny_mode": "Uzbudināts režīms",
|
||||
"auto_mongodb": "Automātiski startējiet MongoDB",
|
||||
"un_elevated": "Palaist spēli bez paaugstinājuma (bez administratora)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Lejupielādējiet Grasscutter viss vienā",
|
||||
@@ -40,7 +42,9 @@
|
||||
"grasscutter_latest_update": "Atjauniet Grasscutter jaunāko",
|
||||
"resources": "Lejupielādējiet Grasscutter resursi",
|
||||
"aio_header": "Lejupielādes viss vienā",
|
||||
"individual_header": "Atsevišķu daļu lejupielādes:"
|
||||
"individual_header": "Atsevišķu daļu lejupielādes:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Lejupielādēt GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Notiek lejupielāde",
|
||||
@@ -67,6 +71,8 @@
|
||||
"gc_dev_jar": "Lejupielādējiet jaunāko izstrāde Grasscutter versiju, kuram ir jar failu un datu failus.",
|
||||
"gc_stable_data": "Lejupielādējiet pašreizējos stabilos Grasscutter datu failus, kuriem nav jar fails. Tas ir noderīgi atjaunināšanai.",
|
||||
"gc_dev_data": "Lejupielādējiet jaunāko izstrāde Grasscutter datu failus, kuriem nav pievienots jar fails. Tas ir noderīgi atjaunināšanai.",
|
||||
"resources": "Tie ir nepieciešami arī Grasscutter servera darbināšanai. Šī poga būs pelēka, ja jums ir resursu mape ar saturu."
|
||||
"resources": "Tie ir nepieciešami arī Grasscutter servera darbināšanai. Šī poga būs pelēka, ja jums ir resursu mape ar saturu.",
|
||||
"add_delay": "Iestatiet kavēšanos 3dmigoto iekrāvē! \nTam vajadzētu novērst ielādes problēmas, bet tas nedaudz aizkavēs 3dmigoto ielādēšanu, uzsākot spēli. \nTagad atkal varat sākt ar 3dmigoto.",
|
||||
"migoto": "Modeļu importēšanai no GameBanana"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
"patch_rsa": "RSA Automatisch Bijwerken",
|
||||
"use_proxy": "Gebruik Interne Proxy",
|
||||
"wipe_login": "Login cache wissen",
|
||||
"horny_mode": "Geile modus"
|
||||
"horny_mode": "Geile modus",
|
||||
"auto_mongodb": "Start automatisch MongoDB",
|
||||
"un_elevated": "Voer het spel uit zonder hoogtevrees (geen admin)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Grasscutter Alles-in-één Downloaden",
|
||||
@@ -42,7 +44,9 @@
|
||||
"resources": "Download Grasscutter bronnen",
|
||||
"game": "Download Spel",
|
||||
"aio_header": "Alles-in-één Downloads:",
|
||||
"individual_header": "Downloads van afzonderlijke onderdelen:"
|
||||
"individual_header": "Downloads van afzonderlijke onderdelen:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Download GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Aan Het Downloading",
|
||||
@@ -74,7 +78,9 @@
|
||||
"resources": "Deze zijn ook nodig om een Grasscutter server te draaien. Deze knop zal grijs zijn als u een bestaande resources map heeft met inhoud erin",
|
||||
"emergency_rsa": "Voor het geval er iets fout is gegaan, herstel uw rsa naar de laatste offici<63>le versies rsa.",
|
||||
"use_proxy": "Gebruik de Cultivation interne proxy. U zou dit ingeschakeld moeten hebben, tenzij u iets als Fiddler gebruikt",
|
||||
"patch_rsa": "Patch en unpatch je spel rsa automatisch. Tenzij je met oude/niet-offici<63>le versies speelt, of je hebt je rsa handmatig gepatcht, zou dit ingeschakeld moeten zijn."
|
||||
"patch_rsa": "Patch en unpatch je spel rsa automatisch. Tenzij je met oude/niet-offici<63>le versies speelt, of je hebt je rsa handmatig gepatcht, zou dit ingeschakeld moeten zijn.",
|
||||
"add_delay": "Vertraging instellen in 3dmigoto loader! \nDit zou laadproblemen moeten oplossen, maar zal een kleine vertraging toevoegen aan het laden van 3dmigoto bij het opstarten van het spel. \nJe kunt nu weer starten met 3dmigoto.",
|
||||
"migoto": "Voor het importeren van modellen uit GameBanana"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
94
src-tauri/lang/pt-br.json
Normal file
94
src-tauri/lang/pt-br.json
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"lang_name": "Português Brasileiro",
|
||||
"main": {
|
||||
"title": "Cultivation: Edição Thorny",
|
||||
"launch_button": "Iniciar",
|
||||
"gc_enable": "Conectar ao Grasscutter",
|
||||
"https_enable": "Usar HTTPS",
|
||||
"ip_placeholder": "Endereço do Servidor...",
|
||||
"port_placeholder": "Porta...",
|
||||
"files_downloading": "Baixando Arquivos: ",
|
||||
"files_extracting": "Extraindo Arquivos: "
|
||||
},
|
||||
"options": {
|
||||
"enabled": "Habilitado",
|
||||
"disabled": "Desabilitado",
|
||||
"game_path": "Definir o Local de Instalação do Jogo",
|
||||
"game_command": "Comando de Iniciação do Jogo",
|
||||
"game_executable": "Definir o Executavel do Jogo",
|
||||
"recover_rsa": "Exclusão de Emergencia de RSA",
|
||||
"grasscutter_jar": "Definir o arquivo JAR do Grasscutter",
|
||||
"toggle_encryption": "Ativar/Desativar Criptografia",
|
||||
"install_certificate": "Instalar o Certificado de Proxy",
|
||||
"java_path": "Definir um Local Customizado do Java",
|
||||
"grasscutter_with_game": "Iniciar automaticamente o Grasscutter com o Jogo",
|
||||
"language": "Selecionar Idioma",
|
||||
"background": "Definir Fundo Customizado (link ou arquivo de imagem)",
|
||||
"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)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Baixar o Grasscutter Tudo-em-Um",
|
||||
"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_latest": "Baixar o Grasscutter Mais Recente",
|
||||
"grasscutter_stable_update": "Atualizar o Grasscutter Estável",
|
||||
"grasscutter_latest_update": "Atualizar o Grasscutter Mais Recente",
|
||||
"resources": "Baixar os Recursos do Grasscutter ",
|
||||
"game": "Baixar o Jogo",
|
||||
"aio_header": "Downloads Tudo-em-Um:",
|
||||
"individual_header": "Downloads Individuais:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Baixar o GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Baixando",
|
||||
"extracting": "Extraindo",
|
||||
"error": "Erro",
|
||||
"finished": "Finalizado",
|
||||
"stopped": "Parado"
|
||||
},
|
||||
"components": {
|
||||
"select_file": "Selecione o arquivo ou pasta...",
|
||||
"select_folder": "Selecione a pasta...",
|
||||
"download": "Baixar",
|
||||
"delete": "Deletar",
|
||||
"install": "Instalar"
|
||||
},
|
||||
"news": {
|
||||
"latest_commits": "Commits Recentes",
|
||||
"latest_version": "Versão mais Recente"
|
||||
},
|
||||
"help": {
|
||||
"port_help_text": "Certifique-se de que esta é a porta do servidor dispatch, não a porta do jogo. Ela é quase sempre '443'.",
|
||||
"game_help_text": "Você não precisa de uma cópia do jogo separada para jogar com o Grasscutter. Isso é para, ou desatualizar para a 2.6, ou se você não tiver o jogo instalado.",
|
||||
"gc_stable_jar": "Baixar a versão atual do Grasscutter estável, que inclui o arquivo jar e os arquivos de dados.",
|
||||
"gc_fullbuild": "Baixar uma versão completa do Grasscutter, incluindo a repo, jar e recursos. Ela está totalmente configurada e não requer nenhum outro download deste menu.",
|
||||
"gc_dev_jar": "Baixar a versão de desenvolvimento mais recente do Grasscutter, que inclui o arquivo jar e os arquivos de dados.",
|
||||
"gc_stable_data": "Baixar os arquivos de dados da versão atual do Grasscutter estável, que não inclui o arquivo jar. Isso é útil para atualizações.",
|
||||
"gc_dev_data": "Baixar os arquivos de dados da versão de desenvolvimento mais recente do Grasscutter, que não vem com um arquivo jar. Isso é útil para atualizações.",
|
||||
"encryption": "Isso normalmente deve estar desativado.",
|
||||
"resources": "Esses também são necessários para usar o Grasscutter. Esse botão ficará cinza caso você já tenha uma pasta resources com coisas dentro.",
|
||||
"emergency_rsa": "Caso algo dê errado, força a exclusão da correção RSA.",
|
||||
"use_proxy": "Usa o proxy interno do Cultivation. Isso deveria estar habilitado a não ser que você utilize algo como o Fiddler.",
|
||||
"patch_rsa": "Corrigir e 'descorrigir' o RSA do seu jogo automaticamente. Isso deve estar habilitado a não ser que você esteja jogando com versões antigas (3.0 ou mais antigas) ou não oficiais.",
|
||||
"add_delay": "Atraso definido na carregadeira 3dmigoto! \nIsto deve resolver os problemas de carregamento, mas acrescentará um pequeno atraso quando o 3dmigoto for carregado no lançamento do jogo. \nAgora você pode lançar novamente com o 3dmigoto.",
|
||||
"migoto": "Para importação de modelos da GameBanana"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
"migoto_name": "Migoto",
|
||||
"reshade_name": "Reshade",
|
||||
"akebi": "Definir o Executavel do Akebi/Acrepi",
|
||||
"migoto": "Definir o Executavel do 3DMigoto",
|
||||
"reshade": "Definir o Executavel do Reshade Injector"
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,9 @@
|
||||
"patch_rsa": "Автоматическое исправление RSA",
|
||||
"use_proxy": "Использовать встроенный Прокси",
|
||||
"wipe_login": "Очистить кэш входа в систему",
|
||||
"horny_mode": "роговой режим"
|
||||
"horny_mode": "роговой режим",
|
||||
"auto_mongodb": "Автоматически запускать MongoDB",
|
||||
"un_elevated": "Запустите игру в неэлегантном режиме (без администратора)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Скачать все в одном Grasscutter",
|
||||
@@ -42,7 +44,9 @@
|
||||
"resources": "Скачать ресурсы Grasscutter",
|
||||
"game": "Скачать Игру",
|
||||
"aio_header": "Все в одной загрузке:",
|
||||
"individual_header": "загрузка отдельных частей:"
|
||||
"individual_header": "загрузка отдельных частей:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Скачать GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Скачивание",
|
||||
@@ -74,7 +78,9 @@
|
||||
"resources": "Это необходимо для запуска сервера Grasscutter. Эта кнопка будет серой, если у Вас уже есть не пустая папка с ресурсами.",
|
||||
"emergency_rsa": "Если что-то пошло не так, восстановит RSA до последней официальной версии.",
|
||||
"use_proxy": "Использовать встроенный Прокси. Отключите если используете Fiddler или подобную программу",
|
||||
"patch_rsa": "Патчит и восстанавливает RSA автоматически. Если вы не играете на старых/модифицированых версиях, или сами в ручную патчите Метаданные, эта опция должна быть включена."
|
||||
"patch_rsa": "Патчит и восстанавливает RSA автоматически. Если вы не играете на старых/модифицированых версиях, или сами в ручную патчите Метаданные, эта опция должна быть включена.",
|
||||
"add_delay": "Установите задержку в загрузчике 3dmigoto! \nЭто должно исправить проблемы с загрузкой, но добавит небольшую задержку в момент загрузки 3dmigoto при запуске игры. \nТеперь вы снова можете запускать игру с помощью 3dmigoto.",
|
||||
"migoto": "Для импорта моделей из GameBanana"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"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"
|
||||
"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)"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Tải Grasscutter tất cả trong một",
|
||||
@@ -43,7 +45,9 @@
|
||||
"resources": "Tải tài nguyên Grasscutter",
|
||||
"game": "Tải game",
|
||||
"aio_header": "Tải xuống tất cả trong một:",
|
||||
"individual_header": "Tải xuống từng phần:"
|
||||
"individual_header": "Tải xuống từng phần:",
|
||||
"mods_header": "Mods:",
|
||||
"migoto": "Tải GIMI 3dmigoto"
|
||||
},
|
||||
"download_status": {
|
||||
"downloading": "Đang tải",
|
||||
@@ -75,7 +79,9 @@
|
||||
"resources": "Tài nguyên được yêu cầu để chạy máy chủ Grasscutter. Nút này sẽ có màu xám nếu bạn đã có sẵn một thư mục tài nguyên (resources) có nội dung bên trong",
|
||||
"emergency_rsa": "Trong trường hợp gặp vấn đề, khôi phục lại RSA về phiên bản chính thức mới nhất.",
|
||||
"use_proxy": "Sử dụng proxy nội bộ của Cultivation. Nên bật tùy chọn này trừ khi bạn đang sử dụng một ứng dụng khác, như Fiddler",
|
||||
"patch_rsa": "Tự động vá và sửa lại RSA của game. Tùy chọn này nên được bật trừ khi bạn đang sử dụng phiên bản cũ, phiên bản không chính thức hoặc bạn đã tự vá rsa rồi."
|
||||
"patch_rsa": "Tự động vá và sửa lại RSA của game. Tùy chọn này nên được bật trừ khi bạn đang sử dụng phiên bản cũ, phiên bản không chính thức hoặc bạn đã tự vá rsa rồi.",
|
||||
"add_delay": "Đặt độ trễ trong trình tải 3dmigoto! \nĐiều này sẽ khắc phục sự cố tải, nhưng sẽ thêm một độ trễ nhỏ khi 3dmigoto được tải khi khởi chạy trò chơi. \nBây giờ bạn có thể khởi chạy lại với 3dmigoto.",
|
||||
"migoto": "Để nhập mô hình từ GameBanana"
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::process::exit;
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn reopen_as_admin() {
|
||||
use std::process::{exit, Command};
|
||||
|
||||
let install = std::env::current_exe().unwrap();
|
||||
|
||||
println!("Opening as admin: {}", install.to_str().unwrap());
|
||||
|
||||
44
src-tauri/src/config.rs
Normal file
44
src-tauri/src/config.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::string::String;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Configuration {
|
||||
pub toggle_grasscutter: bool,
|
||||
pub game_install_path: String,
|
||||
pub grasscutter_with_game: bool,
|
||||
pub grasscutter_path: String,
|
||||
pub java_path: String,
|
||||
pub close_action: u64,
|
||||
pub startup_launch: bool,
|
||||
pub last_ip: String,
|
||||
pub last_port: String,
|
||||
pub language: String,
|
||||
pub customBackground: String,
|
||||
pub cert_generated: bool,
|
||||
pub theme: String,
|
||||
pub https_enabled: bool,
|
||||
pub debug_enabled: bool,
|
||||
pub patch_rsa: bool,
|
||||
pub use_internal_proxy: bool,
|
||||
pub wipe_login: bool,
|
||||
pub horny_mode: bool,
|
||||
pub auto_mongodb: bool,
|
||||
pub un_elevated: bool,
|
||||
}
|
||||
|
||||
pub fn config_path() -> PathBuf {
|
||||
let mut path = tauri::api::path::data_dir().unwrap();
|
||||
path.push("cultivation");
|
||||
path.push("configuration.json");
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
pub fn get_config() -> Configuration {
|
||||
let path = config_path();
|
||||
let config = std::fs::read_to_string(path).unwrap();
|
||||
let config: Configuration = serde_json::from_str(&config).unwrap();
|
||||
|
||||
config
|
||||
}
|
||||
@@ -17,9 +17,9 @@ pub fn rename(path: String, new_name: String) {
|
||||
new_path = path.replace('\\', "/");
|
||||
}
|
||||
|
||||
let path_replaced = &path.replace(&new_path.split('/').last().unwrap(), &new_name);
|
||||
let path_replaced = &path.replace(new_path.split('/').last().unwrap(), &new_name);
|
||||
|
||||
match fs::rename(&path, &path_replaced) {
|
||||
match fs::rename(&path, path_replaced) {
|
||||
Ok(_) => {
|
||||
println!("Renamed {} to {}", &path, path_replaced);
|
||||
}
|
||||
@@ -68,7 +68,7 @@ pub fn copy_file(path: String, new_path: String) -> bool {
|
||||
}
|
||||
|
||||
// Copy old to new
|
||||
match std::fs::copy(&path_buf, format!("{}/{}", new_path, filename)) {
|
||||
match std::fs::copy(path_buf, format!("{}/{}", new_path, filename)) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
println!("Failed to copy file: {}", e);
|
||||
@@ -98,7 +98,7 @@ pub fn copy_file_with_new_name(path: String, new_path: String, new_name: String)
|
||||
new_path_buf.push(new_name);
|
||||
|
||||
// Copy old to new
|
||||
match std::fs::copy(&path_buf, &new_path_buf) {
|
||||
match std::fs::copy(path_buf, &new_path_buf) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
println!("Failed to copy file: {}", e);
|
||||
@@ -152,7 +152,7 @@ pub fn write_file(path: String, contents: String) {
|
||||
let path_buf = PathBuf::from(&path);
|
||||
|
||||
// Create file if it exists, otherwise just open and rewrite
|
||||
let mut file = match fs::File::create(&path_buf) {
|
||||
let mut file = match fs::File::create(path_buf) {
|
||||
Ok(file) => file,
|
||||
Err(e) => {
|
||||
println!("Failed to open file: {}", e);
|
||||
|
||||
@@ -9,7 +9,7 @@ pub async fn get_lang(window: tauri::Window, lang: String) -> String {
|
||||
let lang_path: PathBuf = [&install_location(), "lang", &format!("{}.json", lang)]
|
||||
.iter()
|
||||
.collect();
|
||||
match std::fs::read_to_string(&lang_path) {
|
||||
match std::fs::read_to_string(lang_path) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
emit_lang_err(window, format!("Failed to read language file: {}", e));
|
||||
@@ -28,7 +28,12 @@ pub async fn get_languages() -> std::collections::HashMap<String, String> {
|
||||
for entry in lang_files {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
let filename = path
|
||||
.file_name()
|
||||
.unwrap_or_else(|| panic!("Failed to get filename from path: {:?}", path))
|
||||
.to_str()
|
||||
.unwrap_or_else(|| panic!("Failed to convert filename to string: {:?}", path))
|
||||
.to_string();
|
||||
|
||||
let content = match std::fs::read_to_string(&path) {
|
||||
Ok(x) => x,
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
use args::{Args, ArgsError};
|
||||
use file_helpers::dir_exists;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use proxy::set_proxy_addr;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
@@ -13,44 +16,141 @@ use tauri::api::path::data_dir;
|
||||
use tauri::async_runtime::block_on;
|
||||
|
||||
use std::thread;
|
||||
use sysinfo::{System, SystemExt};
|
||||
use sysinfo::{Pid, ProcessExt, System, SystemExt};
|
||||
|
||||
use crate::admin::reopen_as_admin;
|
||||
|
||||
mod admin;
|
||||
mod config;
|
||||
mod downloader;
|
||||
mod file_helpers;
|
||||
mod gamebanana;
|
||||
mod lang;
|
||||
mod patch;
|
||||
mod proxy;
|
||||
mod release;
|
||||
mod system_helpers;
|
||||
mod unzip;
|
||||
mod web;
|
||||
|
||||
static WATCH_GAME_PROCESS: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new(String::new()));
|
||||
static WATCH_GRASSCUTTER_PROCESS: Lazy<Mutex<String>> = Lazy::new(|| Mutex::new(String::new()));
|
||||
static GC_PID: std::sync::Mutex<usize> = Mutex::new(696969);
|
||||
|
||||
fn try_flush() {
|
||||
std::io::stdout().flush().unwrap_or(())
|
||||
}
|
||||
|
||||
fn has_arg(args: &[String], arg: &str) -> bool {
|
||||
args.contains(&arg.to_string())
|
||||
}
|
||||
async fn parse_args(inp: &Vec<String>) -> Result<Args, ArgsError> {
|
||||
let mut args = Args::new(
|
||||
"Cultivation",
|
||||
"Private server helper program for an Anime Game",
|
||||
);
|
||||
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(
|
||||
"A",
|
||||
"no-admin",
|
||||
"Launch without requiring admin permissions",
|
||||
);
|
||||
args.flag(
|
||||
"g",
|
||||
"no-gui",
|
||||
"Run in CLI mode. Requires -A to be passed as well.",
|
||||
);
|
||||
args.flag("s", "server", "Launch the configured GC server");
|
||||
args.flag(
|
||||
"P",
|
||||
"patch",
|
||||
"Patch your game before launching, with whatever your game version needs",
|
||||
);
|
||||
args.flag(
|
||||
"N",
|
||||
"non-elevated-game",
|
||||
"Launch the game without admin permissions",
|
||||
);
|
||||
args.option(
|
||||
"H",
|
||||
"host",
|
||||
"Set host to connect to (eg. 'localhost:443' or 'my.awesomeserver.com:6969)",
|
||||
"SERVER_HOST",
|
||||
getopts::Occur::Optional,
|
||||
None,
|
||||
);
|
||||
args.option(
|
||||
"a",
|
||||
"game-args",
|
||||
"Arguments to pass to the game process, if launching it",
|
||||
r#""-opt-one -opt-two""#,
|
||||
getopts::Occur::Optional,
|
||||
None,
|
||||
);
|
||||
|
||||
async fn arg_handler(args: &[String]) {
|
||||
if has_arg(args, "--proxy") {
|
||||
args.parse(inp).unwrap();
|
||||
|
||||
let config = config::get_config();
|
||||
|
||||
if args.value_of("help")? {
|
||||
println!("{}", args.full_usage());
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
if args.value_of("launch-game")? {
|
||||
let game_path = config.game_install_path;
|
||||
let game_args: String = args.value_of("game-args").unwrap_or(String::new());
|
||||
|
||||
// Patch if needed
|
||||
if args.value_of("patch")? {
|
||||
patch::patch_game().await;
|
||||
}
|
||||
|
||||
if args.value_of("non-elevated-game")? {
|
||||
system_helpers::run_un_elevated(game_path.to_string(), Some(game_args))
|
||||
} else {
|
||||
system_helpers::run_program(game_path.to_string(), Some(game_args))
|
||||
}
|
||||
}
|
||||
|
||||
if args.value_of("server")? {
|
||||
let server_jar = config.grasscutter_path;
|
||||
let mut server_path = server_jar.clone();
|
||||
// Strip jar name from path
|
||||
if server_path.contains('/') {
|
||||
// Can never panic because of if
|
||||
let len = server_jar.rfind('/').unwrap();
|
||||
server_path.truncate(len);
|
||||
} else if server_path.contains('\\') {
|
||||
let len = server_jar.rfind('\\').unwrap();
|
||||
server_path.truncate(len);
|
||||
}
|
||||
let java_path = config.java_path;
|
||||
|
||||
system_helpers::run_jar(server_jar, server_path.to_string(), java_path);
|
||||
}
|
||||
|
||||
if args.value_of::<String>("host").is_ok() && !args.value_of::<String>("host")?.is_empty() {
|
||||
let host = args.value_of::<String>("host")?;
|
||||
set_proxy_addr(host);
|
||||
}
|
||||
|
||||
if args.value_of("proxy")? {
|
||||
println!("Starting proxy server...");
|
||||
let mut pathbuf = tauri::api::path::data_dir().unwrap();
|
||||
pathbuf.push("cultivation");
|
||||
pathbuf.push("ca");
|
||||
|
||||
connect(8035, pathbuf.to_str().unwrap().to_string()).await;
|
||||
}
|
||||
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), ArgsError> {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let parsed_args = block_on(parse_args(&args)).unwrap();
|
||||
|
||||
if !is_elevated() && !has_arg(&args, "--no-admin") {
|
||||
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.");
|
||||
println!("===============================================================================");
|
||||
@@ -60,7 +160,7 @@ fn main() {
|
||||
|
||||
// Setup datadir/cultivation just in case something went funky and it wasn't made
|
||||
if !dir_exists(data_dir().unwrap().join("cultivation").to_str().unwrap()) {
|
||||
fs::create_dir_all(&data_dir().unwrap().join("cultivation")).unwrap();
|
||||
fs::create_dir_all(data_dir().unwrap().join("cultivation")).unwrap();
|
||||
}
|
||||
|
||||
// Always set CWD to the location of the executable.
|
||||
@@ -68,36 +168,44 @@ fn main() {
|
||||
exe_path.pop();
|
||||
std::env::set_current_dir(&exe_path).unwrap();
|
||||
|
||||
block_on(arg_handler(&args));
|
||||
|
||||
// For disabled GUI
|
||||
ctrlc::set_handler(|| {
|
||||
disconnect();
|
||||
block_on(patch::unpatch_game());
|
||||
std::process::exit(0);
|
||||
})
|
||||
.unwrap_or(());
|
||||
|
||||
if !has_arg(&args, "--no-gui") {
|
||||
if !parsed_args.value_of("no-gui")? {
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
enable_process_watcher,
|
||||
enable_grasscutter_watcher,
|
||||
connect,
|
||||
disconnect,
|
||||
req_get,
|
||||
is_game_running,
|
||||
is_grasscutter_running,
|
||||
restart_grasscutter,
|
||||
get_theme_list,
|
||||
system_helpers::run_command,
|
||||
system_helpers::run_program,
|
||||
system_helpers::run_program_relative,
|
||||
system_helpers::start_service,
|
||||
system_helpers::service_status,
|
||||
system_helpers::stop_service,
|
||||
system_helpers::run_jar,
|
||||
system_helpers::open_in_browser,
|
||||
system_helpers::install_location,
|
||||
system_helpers::is_elevated,
|
||||
system_helpers::set_migoto_target,
|
||||
system_helpers::set_migoto_delay,
|
||||
system_helpers::wipe_registry,
|
||||
system_helpers::get_platform,
|
||||
system_helpers::run_un_elevated,
|
||||
proxy::set_proxy_addr,
|
||||
proxy::generate_ca_files,
|
||||
release::get_latest_release,
|
||||
unzip::unzip,
|
||||
file_helpers::rename,
|
||||
file_helpers::dir_create,
|
||||
@@ -130,6 +238,11 @@ fn main() {
|
||||
|
||||
// Always disconnect upon closing the program
|
||||
disconnect();
|
||||
|
||||
// Always unpatch game upon closing the program
|
||||
block_on(patch::unpatch_game());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -185,6 +298,104 @@ fn enable_process_watcher(window: tauri::Window, process: String) {
|
||||
});
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn is_grasscutter_running() -> bool {
|
||||
// Grab the grasscutter process name
|
||||
let proc = WATCH_GRASSCUTTER_PROCESS.lock().unwrap().to_string();
|
||||
|
||||
!proc.is_empty()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn restart_grasscutter(window: tauri::Window) -> bool {
|
||||
let pid: usize = *GC_PID.lock().unwrap();
|
||||
let system = System::new_all();
|
||||
// Get the process
|
||||
if let Some(process) = system.process(Pid::from(pid)) {
|
||||
// Kill it
|
||||
if process.kill() {
|
||||
// Also kill the cmd it was open in
|
||||
if let Some(parent) = system.process(process.parent().unwrap()) {
|
||||
parent.kill();
|
||||
}
|
||||
for process_gc in system.processes_by_name("java") {
|
||||
if process_gc.cmd().last().unwrap().contains("grasscutter") {
|
||||
process_gc.kill();
|
||||
}
|
||||
}
|
||||
window.emit("disable_grasscutter_watcher", &()).unwrap();
|
||||
thread::sleep(std::time::Duration::from_secs(2));
|
||||
// Start again
|
||||
window.emit("start_grasscutter", &()).unwrap();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn enable_grasscutter_watcher(window: tauri::Window, process: String) {
|
||||
let grasscutter_name = process.clone();
|
||||
let mut gc_pid = Pid::from(696969);
|
||||
|
||||
*WATCH_GRASSCUTTER_PROCESS.lock().unwrap() = process;
|
||||
|
||||
window.listen("disable_grasscutter_watcher", |_e| {
|
||||
*WATCH_GRASSCUTTER_PROCESS.lock().unwrap() = "".to_string();
|
||||
});
|
||||
|
||||
println!("Starting grasscutter watcher...");
|
||||
|
||||
thread::spawn(move || {
|
||||
// Initial sleep for 1 second while Grasscutter opens
|
||||
std::thread::sleep(std::time::Duration::from_secs(3));
|
||||
|
||||
let mut system = System::new_all();
|
||||
|
||||
for process_gc in system.processes_by_name("java") {
|
||||
if process_gc.cmd().last().unwrap().contains(&grasscutter_name) {
|
||||
gc_pid = process_gc.pid();
|
||||
*GC_PID.lock().unwrap() = gc_pid.into();
|
||||
window
|
||||
.emit("grasscutter_started", gc_pid.to_string())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
// Shorten loop timer to avoid user closing Cultivation before automatic stuff
|
||||
thread::sleep(std::time::Duration::from_secs(2));
|
||||
|
||||
// Refresh system info
|
||||
system.refresh_all();
|
||||
|
||||
// Grab the grasscutter process name
|
||||
let proc = WATCH_GRASSCUTTER_PROCESS.lock().unwrap().to_string();
|
||||
|
||||
if !proc.is_empty() {
|
||||
let mut exists = true;
|
||||
|
||||
if system.process(gc_pid).is_none() {
|
||||
exists = false;
|
||||
}
|
||||
|
||||
// If the grasscutter process closes.
|
||||
if !exists {
|
||||
println!("Grasscutter closed");
|
||||
|
||||
*WATCH_GRASSCUTTER_PROCESS.lock().unwrap() = "".to_string();
|
||||
|
||||
window.emit("grasscutter_closed", &()).unwrap();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn connect(port: u16, certificate_path: String) {
|
||||
// Log message to console.
|
||||
|
||||
59
src-tauri/src/patch.rs
Normal file
59
src-tauri/src/patch.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use crate::config;
|
||||
use crate::file_helpers;
|
||||
use crate::system_helpers;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub async fn patch_game() -> bool {
|
||||
let patch_path = PathBuf::from(system_helpers::install_location()).join("patch/version.dll");
|
||||
|
||||
// Are we already patched with mhypbase? If so, that's fine, just continue as normal
|
||||
let game_is_patched = file_helpers::are_files_identical(
|
||||
patch_path.clone().to_str().unwrap(),
|
||||
PathBuf::from(get_game_rsa_path().await.unwrap())
|
||||
.join("mhypbase.dll")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// Tell user they won't be unpatched with manual mhypbase patch
|
||||
if game_is_patched {
|
||||
println!(
|
||||
"You are already patched using mhypbase, so you will not be auto patched and unpatched!"
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy the patch to game files
|
||||
let replaced = file_helpers::copy_file_with_new_name(
|
||||
patch_path.clone().to_str().unwrap().to_string(),
|
||||
get_game_rsa_path().await.unwrap(),
|
||||
String::from("version.dll"),
|
||||
);
|
||||
|
||||
if !replaced {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub async fn unpatch_game() -> bool {
|
||||
// Just delete patch since it's not replacing any existing file
|
||||
let deleted = file_helpers::delete_file(
|
||||
PathBuf::from(get_game_rsa_path().await.unwrap())
|
||||
.join("version.dll")
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
deleted
|
||||
}
|
||||
|
||||
pub async fn get_game_rsa_path() -> Option<String> {
|
||||
let config = config::get_config();
|
||||
let mut game_folder = PathBuf::from(config.game_install_path);
|
||||
game_folder.pop();
|
||||
|
||||
Some(format!("{}/", game_folder.to_str().unwrap()).replace('\\', "/"))
|
||||
}
|
||||
@@ -41,7 +41,14 @@ struct ProxyHandler;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn set_proxy_addr(addr: String) {
|
||||
*SERVER.lock().unwrap() = addr;
|
||||
if addr.contains(' ') {
|
||||
let addr2 = addr.replace(' ', "");
|
||||
*SERVER.lock().unwrap() = addr2;
|
||||
} else {
|
||||
*SERVER.lock().unwrap() = addr;
|
||||
}
|
||||
|
||||
println!("Set server to {}", SERVER.lock().unwrap());
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -86,7 +93,9 @@ impl HttpHandler for ProxyHandler {
|
||||
}
|
||||
|
||||
async fn should_intercept(&mut self, _ctx: &HttpContext, _req: &Request<Body>) -> bool {
|
||||
true
|
||||
let uri = _req.uri().to_string();
|
||||
|
||||
uri.contains("hoyoverse.com") || uri.contains("mihoyo.com") || uri.contains("yuanshen.com")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +174,8 @@ pub fn connect_to_proxy(proxy_port: u16) {
|
||||
let settings = Hive::CurrentUser
|
||||
.open(
|
||||
r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
|
||||
Security::Write,
|
||||
// Only write should be needed but too many cases of Culti not being able to read/write proxy settings
|
||||
Security::AllAccess,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -212,7 +222,7 @@ pub fn disconnect_from_proxy() {
|
||||
let settings = Hive::CurrentUser
|
||||
.open(
|
||||
r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
|
||||
Security::Write,
|
||||
Security::AllAccess,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -353,7 +363,7 @@ pub fn install_ca_files(cert_path: &Path) {
|
||||
// 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");
|
||||
fs::copy(cert_path, usr_cert_path).expect("Unable to copy cert to local certificate directory");
|
||||
run_command("update-ca-certificates", vec![], None);
|
||||
|
||||
println!("Installed certificate.");
|
||||
|
||||
32
src-tauri/src/release.rs
Normal file
32
src-tauri/src/release.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Release {
|
||||
pub tag_name: String,
|
||||
pub link: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_latest_release() -> Release {
|
||||
let url = "https://api.github.com/repos/Grasscutters/Cultivation/releases/latest";
|
||||
let client = reqwest::Client::new();
|
||||
let response = client
|
||||
.get(url)
|
||||
.header("User-Agent", "Cultivation")
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
let text = response.text().await.unwrap();
|
||||
|
||||
println!("Response: {}", text);
|
||||
|
||||
// Parse "tag_name" from JSON
|
||||
let json: serde_json::Value = serde_json::from_str(&text).unwrap();
|
||||
let tag_name = json["tag_name"].as_str().unwrap();
|
||||
|
||||
// Parse "html_url"
|
||||
let link = json["html_url"].as_str().unwrap();
|
||||
|
||||
Release {
|
||||
tag_name: tag_name.to_string(),
|
||||
link: link.to_string(),
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
use duct::cmd;
|
||||
use ini::Ini;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
use windows_service::service::{ServiceAccess, ServiceState::Stopped};
|
||||
use windows_service::service_manager::{ServiceManager, ServiceManagerAccess};
|
||||
|
||||
#[cfg(windows)]
|
||||
use registry::{Data, Hive, Security};
|
||||
@@ -8,7 +11,13 @@ use registry::{Data, Hive, Security};
|
||||
#[tauri::command]
|
||||
pub fn run_program(path: String, args: Option<String>) {
|
||||
// Without unwrap_or, this can crash when UAC prompt is denied
|
||||
open::that(format!("{} {}", &path, &args.unwrap_or_else(|| "".into()))).unwrap_or(());
|
||||
match open::with(
|
||||
format!("{} {}", path, args.unwrap_or_else(|| "".into())),
|
||||
path.clone(),
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Failed to open program ({}): {}", &path, e),
|
||||
};
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -27,7 +36,7 @@ pub fn run_program_relative(path: String, args: Option<String>) {
|
||||
open::that(format!("{} {}", &path, args.unwrap_or_else(|| "".into()))).unwrap_or(());
|
||||
|
||||
// Restore the original working directory
|
||||
std::env::set_current_dir(&cwd).unwrap();
|
||||
std::env::set_current_dir(cwd).unwrap();
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -52,7 +61,7 @@ pub fn run_command(program: &str, args: Vec<&str>, relative: Option<bool>) {
|
||||
cmd(prog, args).run().unwrap();
|
||||
|
||||
// Restore the original working directory
|
||||
std::env::set_current_dir(&cwd).unwrap();
|
||||
std::env::set_current_dir(cwd).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -64,6 +73,8 @@ pub fn run_jar(path: String, execute_in: String, java_path: String) {
|
||||
format!("\"{}\" -jar \"{}\"", java_path, path)
|
||||
};
|
||||
|
||||
println!("Launching .jar with command: {}", &command);
|
||||
|
||||
// Open the program from the specified path.
|
||||
match open::with(
|
||||
format!("/k cd /D \"{}\" & {}", &execute_in, &command),
|
||||
@@ -74,6 +85,22 @@ pub fn run_jar(path: String, execute_in: String, java_path: String) {
|
||||
};
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn run_un_elevated(path: String, args: Option<String>) {
|
||||
// Open the program non-elevated.
|
||||
match open::with(
|
||||
format!(
|
||||
"cmd /min /C \"set __COMPAT_LAYER=RUNASINVOKER && start \"\" \"{}\"\" {}",
|
||||
path,
|
||||
args.unwrap_or_else(|| "".into())
|
||||
),
|
||||
"C:\\Windows\\System32\\cmd.exe",
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Failed to open program ({}): {}", &path, e),
|
||||
};
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_in_browser(url: String) {
|
||||
// Open the URL in the default browser.
|
||||
@@ -94,7 +121,45 @@ pub fn install_location() -> String {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn set_migoto_target(_path: String, migoto_path: String) -> bool {
|
||||
pub fn set_migoto_target(window: tauri::Window, migoto_path: String) -> bool {
|
||||
let mut migoto_pathbuf = PathBuf::from(migoto_path);
|
||||
|
||||
migoto_pathbuf.pop();
|
||||
migoto_pathbuf.push("d3dx.ini");
|
||||
|
||||
let mut conf = match Ini::load_from_file(&migoto_pathbuf) {
|
||||
Ok(c) => {
|
||||
println!("Loaded migoto ini");
|
||||
c
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error loading migoto config: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
window.emit("migoto_set", &()).unwrap();
|
||||
|
||||
// Set options
|
||||
conf
|
||||
.with_section(Some("Loader"))
|
||||
.set("target", "GenshinImpact.exe");
|
||||
|
||||
// Write file
|
||||
match conf.write_to_file(&migoto_pathbuf) {
|
||||
Ok(_) => {
|
||||
println!("Wrote config!");
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error writing config: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn set_migoto_delay(migoto_path: String) -> bool {
|
||||
let mut migoto_pathbuf = PathBuf::from(migoto_path);
|
||||
|
||||
migoto_pathbuf.pop();
|
||||
@@ -112,18 +177,16 @@ pub fn set_migoto_target(_path: String, migoto_path: String) -> bool {
|
||||
};
|
||||
|
||||
// Set options
|
||||
conf
|
||||
.with_section(Some("Loader"))
|
||||
.set("target", "GenshinImpact.exe");
|
||||
conf.with_section(Some("Loader")).set("delay", "20");
|
||||
|
||||
// Write file
|
||||
match conf.write_to_file(&migoto_pathbuf) {
|
||||
Ok(_) => {
|
||||
println!("Wrote config!");
|
||||
println!("Wrote delay!");
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error writing config: {}", e);
|
||||
println!("Error writing delay: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -152,6 +215,72 @@ pub fn wipe_registry(exec_name: String) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
pub fn service_status(service: String) -> bool {
|
||||
let manager = match ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT) {
|
||||
Ok(manager) => manager,
|
||||
Err(_e) => return false,
|
||||
};
|
||||
let my_service = match manager.open_service(service.clone(), ServiceAccess::QUERY_STATUS) {
|
||||
Ok(my_service) => my_service,
|
||||
Err(_e) => {
|
||||
println!("{} service not found! Not installed?", service);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let status_result = my_service.query_status();
|
||||
if status_result.is_ok() {
|
||||
let status = status_result.unwrap();
|
||||
println!("{} service status: {:?}", service, status.current_state);
|
||||
if status.current_state == Stopped {
|
||||
// Start the service if it is stopped
|
||||
start_service(service);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
pub fn start_service(service: String) -> bool {
|
||||
println!("Starting service: {}", service);
|
||||
let manager = match ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT) {
|
||||
Ok(manager) => manager,
|
||||
Err(_e) => return false,
|
||||
};
|
||||
let my_service = match manager.open_service(service, ServiceAccess::START) {
|
||||
Ok(my_service) => my_service,
|
||||
Err(_e) => return false,
|
||||
};
|
||||
match my_service.start(&[OsStr::new("Started service!")]) {
|
||||
Ok(_s) => true,
|
||||
Err(_e) => return false,
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
pub fn stop_service(service: String) -> bool {
|
||||
println!("Stopping service: {}", service);
|
||||
let manager = match ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT) {
|
||||
Ok(manager) => manager,
|
||||
Err(_e) => return false,
|
||||
};
|
||||
let my_service = match manager.open_service(service, ServiceAccess::STOP) {
|
||||
Ok(my_service) => my_service,
|
||||
Err(_e) => return false,
|
||||
};
|
||||
match my_service.stop() {
|
||||
Ok(_s) => true,
|
||||
Err(_e) => return false,
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tauri::command]
|
||||
pub fn wipe_registry(_exec_name: String) {}
|
||||
|
||||
@@ -72,6 +72,10 @@ pub fn unzip(
|
||||
|
||||
let archive = Archive::new(zipfile.clone());
|
||||
name = archive.list().unwrap().next().unwrap().unwrap().filename;
|
||||
} else if zipfile.ends_with(".7z") {
|
||||
success = extract_7z(&zipfile, &f, &full_path, top_level.unwrap_or(true));
|
||||
|
||||
name = String::from("banana");
|
||||
} else {
|
||||
success = extract_zip(&zipfile, &f, &full_path, top_level.unwrap_or(true));
|
||||
|
||||
@@ -97,12 +101,21 @@ pub fn unzip(
|
||||
}
|
||||
|
||||
// If downloading full build, emit that the jar was extracted with it
|
||||
if zipfile.ends_with("Culti3.4.zip") {
|
||||
if zipfile.contains("GrasscutterCulti") {
|
||||
window
|
||||
.emit("jar_extracted", destpath.to_string() + "grasscutter.jar")
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if zipfile.contains("GIMI") {
|
||||
window
|
||||
.emit(
|
||||
"migoto_extracted",
|
||||
destpath.to_string() + "3DMigoto Loader.exe",
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Delete zip file
|
||||
match std::fs::remove_file(&zipfile) {
|
||||
Ok(_) => {
|
||||
@@ -169,3 +182,20 @@ fn extract_zip(_zipfile: &str, f: &File, full_path: &path::Path, top_level: bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_7z(sevenzfile: &str, _f: &File, full_path: &path::Path, _top_level: bool) -> bool {
|
||||
match sevenz_rust::decompress_file(sevenzfile, full_path) {
|
||||
Ok(_) => {
|
||||
println!(
|
||||
"Extracted 7zip file to: {}",
|
||||
full_path.to_str().unwrap_or("Error")
|
||||
);
|
||||
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to extract 7zip file: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ pub(crate) async fn query(site: &str) -> String {
|
||||
.ok();
|
||||
|
||||
if response.is_some() {
|
||||
return response.unwrap().text().await.unwrap();
|
||||
response.unwrap().text().await.unwrap()
|
||||
} else {
|
||||
false.to_string()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "Cultivation",
|
||||
"version": "1.0.10"
|
||||
"version": "1.0.26"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
||||
@@ -11,9 +11,12 @@ import Downloads from './components/menu/Downloads'
|
||||
import NewsSection from './components/news/NewsSection'
|
||||
import Game from './components/menu/Game'
|
||||
import RightBar from './components/RightBar'
|
||||
import { ExtrasMenu } from './components/menu/ExtrasMenu'
|
||||
import Notification from './components/common/Notification'
|
||||
|
||||
import { 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'
|
||||
import { dataDir } from '@tauri-apps/api/path'
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
@@ -24,7 +27,6 @@ import DownloadHandler from '../utils/download'
|
||||
import cogBtn from '../resources/icons/cog.svg'
|
||||
import downBtn from '../resources/icons/download.svg'
|
||||
import wrenchBtn from '../resources/icons/wrench.svg'
|
||||
import { ExtrasMenu } from './components/menu/ExtrasMenu'
|
||||
|
||||
interface IProps {
|
||||
downloadHandler: DownloadHandler
|
||||
@@ -39,6 +41,7 @@ interface IState {
|
||||
extrasOpen: boolean
|
||||
migotoSet: boolean
|
||||
playGame: (exe?: string, proc_name?: string) => void
|
||||
notification: React.ReactElement | null
|
||||
}
|
||||
|
||||
export class Main extends React.Component<IProps, IState> {
|
||||
@@ -55,6 +58,7 @@ export class Main extends React.Component<IProps, IState> {
|
||||
playGame: () => {
|
||||
alert('Error launching game')
|
||||
},
|
||||
notification: null,
|
||||
}
|
||||
|
||||
listen('lang_error', (payload) => {
|
||||
@@ -65,6 +69,14 @@ export class Main extends React.Component<IProps, IState> {
|
||||
setConfigOption('grasscutter_path', payload)
|
||||
})
|
||||
|
||||
listen('migoto_extracted', ({ payload }: { payload: string }) => {
|
||||
setConfigOption('migoto_path', payload)
|
||||
|
||||
invoke('set_migoto_target', {
|
||||
migotoPath: payload,
|
||||
})
|
||||
})
|
||||
|
||||
// Emitted for rsa replacing-purposes
|
||||
listen('game_closed', async () => {
|
||||
const wasPatched = await getConfigOption('patch_rsa')
|
||||
@@ -78,6 +90,23 @@ export class Main extends React.Component<IProps, IState> {
|
||||
}
|
||||
})
|
||||
|
||||
listen('migoto_set', async () => {
|
||||
this.setState({
|
||||
migotoSet: !!(await getConfigOption('migoto_path')),
|
||||
})
|
||||
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
// Emitted for automatic processes
|
||||
listen('grasscutter_closed', async () => {
|
||||
const autoService = await getConfigOption('auto_mongodb')
|
||||
|
||||
if (autoService) {
|
||||
await invoke('stop_service', { service: 'MongoDB' })
|
||||
}
|
||||
})
|
||||
|
||||
let min = false
|
||||
|
||||
// periodically check if we need to min/max based on whether the game is open
|
||||
@@ -116,6 +145,35 @@ export class Main extends React.Component<IProps, IState> {
|
||||
const updatedConfig = await getConfigOption('patch_rsa')
|
||||
await setConfigOption('patch_rsa', updatedConfig)
|
||||
|
||||
// Get latest version and compare to this version
|
||||
const latestVersion: {
|
||||
tag_name: string
|
||||
link: string
|
||||
} = await invoke('get_latest_release')
|
||||
const tagName = latestVersion?.tag_name.replace(/[^\d.]/g, '')
|
||||
|
||||
// Check if tagName is different than current version
|
||||
if (tagName && tagName !== (await getVersion())) {
|
||||
// Display notification of new release
|
||||
this.setState({
|
||||
notification: (
|
||||
<>
|
||||
Cultivation{' '}
|
||||
<a href="#" onClick={() => invoke('open_in_browser', { url: latestVersion.link })}>
|
||||
{latestVersion?.tag_name}
|
||||
</a>{' '}
|
||||
is now available!
|
||||
</>
|
||||
),
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
notification: null,
|
||||
})
|
||||
}, 6000)
|
||||
}
|
||||
|
||||
// Period check to only show progress bar when downloading files
|
||||
setInterval(() => {
|
||||
this.setState({
|
||||
@@ -167,6 +225,8 @@ export class Main extends React.Component<IProps, IState> {
|
||||
</div> */}
|
||||
</TopBar>
|
||||
|
||||
<Notification show={!!this.state.notification}>{this.state.notification}</Notification>
|
||||
|
||||
<RightBar />
|
||||
|
||||
<NewsSection />
|
||||
|
||||
@@ -12,8 +12,9 @@ import Plus from '../../resources/icons/plus.svg'
|
||||
|
||||
import './ServerLaunchSection.css'
|
||||
import { dataDir } from '@tauri-apps/api/path'
|
||||
import { getGameExecutable, getGameVersion } from '../../utils/game'
|
||||
import { getGameExecutable, getGameVersion, getGrasscutterJar } from '../../utils/game'
|
||||
import { patchGame, unpatchGame } from '../../utils/rsa'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
|
||||
interface IProps {
|
||||
openExtras: (playGame: () => void) => void
|
||||
@@ -25,6 +26,7 @@ interface IState {
|
||||
checkboxLabel: string
|
||||
ip: string
|
||||
port: string
|
||||
launchServer: (proc_name?: string) => void
|
||||
|
||||
ipPlaceholder: string
|
||||
portPlaceholder: string
|
||||
@@ -37,6 +39,8 @@ interface IState {
|
||||
swag: boolean
|
||||
akebiSet: boolean
|
||||
migotoSet: boolean
|
||||
|
||||
unElevated: boolean
|
||||
}
|
||||
|
||||
export default class ServerLaunchSection extends React.Component<IProps, IState> {
|
||||
@@ -54,9 +58,13 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
portHelpText: '',
|
||||
httpsLabel: '',
|
||||
httpsEnabled: false,
|
||||
launchServer: () => {
|
||||
alert('Error launching grasscutter')
|
||||
},
|
||||
swag: false,
|
||||
akebiSet: false,
|
||||
migotoSet: false,
|
||||
unElevated: false,
|
||||
}
|
||||
|
||||
this.toggleGrasscutter = this.toggleGrasscutter.bind(this)
|
||||
@@ -64,6 +72,11 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
this.setIp = this.setIp.bind(this)
|
||||
this.setPort = this.setPort.bind(this)
|
||||
this.toggleHttps = this.toggleHttps.bind(this)
|
||||
this.launchServer = this.launchServer.bind(this)
|
||||
|
||||
listen('start_grasscutter', async () => {
|
||||
this.launchServer()
|
||||
})
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@@ -83,6 +96,7 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
swag: config.swag_mode || false,
|
||||
akebiSet: config.akebi_path !== '',
|
||||
migotoSet: config.migoto_path !== '',
|
||||
unElevated: config.un_elevated || false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -159,16 +173,7 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
|
||||
// Open server as well if the options are set
|
||||
if (config.grasscutter_with_game) {
|
||||
const jarFolderArr = config.grasscutter_path.replace(/\\/g, '/').split('/')
|
||||
jarFolderArr.pop()
|
||||
|
||||
const jarFolder = jarFolderArr.join('/')
|
||||
|
||||
await invoke('run_jar', {
|
||||
path: config.grasscutter_path,
|
||||
executeIn: jarFolder,
|
||||
javaPath: config.java_path || '',
|
||||
})
|
||||
this.launchServer()
|
||||
}
|
||||
} else {
|
||||
await unpatchGame()
|
||||
@@ -187,15 +192,35 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
path: exe || config.game_install_path,
|
||||
})
|
||||
|
||||
if (gameExists) await invoke('run_program_relative', { path: exe || config.game_install_path })
|
||||
if (gameExists)
|
||||
if (config.un_elevated) {
|
||||
await invoke('run_un_elevated', {
|
||||
path: config.game_install_path,
|
||||
})
|
||||
} else {
|
||||
await invoke('run_program_relative', { path: exe || config.game_install_path })
|
||||
}
|
||||
else alert('Game not found! At: ' + (exe || config.game_install_path))
|
||||
}
|
||||
|
||||
async launchServer() {
|
||||
async launchServer(proc_name?: string) {
|
||||
if (await invoke('is_grasscutter_running')) {
|
||||
alert('Grasscutter already running!')
|
||||
return
|
||||
}
|
||||
const config = await getConfig()
|
||||
|
||||
if (!config.grasscutter_path) return alert('Grasscutter not installed or set!')
|
||||
|
||||
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' })
|
||||
}
|
||||
|
||||
let jarFolder = config.grasscutter_path
|
||||
|
||||
if (jarFolder.includes('/')) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.DirInput {
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
24
src/ui/components/common/Notification.css
Normal file
24
src/ui/components/common/Notification.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.Notification {
|
||||
position: absolute;
|
||||
|
||||
/* Default styles, changed when showing notif */
|
||||
top: -100%;
|
||||
right: 10%;
|
||||
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ffc61e;
|
||||
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.NotifShow {
|
||||
top: 10%;
|
||||
}
|
||||
22
src/ui/components/common/Notification.tsx
Normal file
22
src/ui/components/common/Notification.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from 'react'
|
||||
|
||||
import './Notification.css'
|
||||
|
||||
interface IProps {
|
||||
children: React.ReactNode | null
|
||||
show: boolean
|
||||
}
|
||||
|
||||
export default class Notification extends React.Component<IProps> {
|
||||
constructor(props: IProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={'Notification ' + (this.props.show ? 'NotifShow' : '')}>
|
||||
<div className="NotificationMessage">{this.props.children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
32
src/ui/components/common/SmallButton.css
Normal file
32
src/ui/components/common/SmallButton.css
Normal file
@@ -0,0 +1,32 @@
|
||||
.SmallButtonSection {
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.SmallButtonButton {
|
||||
height: 20px;
|
||||
filter: drop-shadow(0px 0px 5px rgb(0 0 0 / 20%));
|
||||
}
|
||||
|
||||
.SmallButtonButton:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.SmallButtonButton img {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.SmallButtonContents {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.SmallButtonContents .MiniDialog {
|
||||
position: absolute;
|
||||
|
||||
bottom: 40px;
|
||||
right: -450%;
|
||||
width: 200px;
|
||||
height: 120px;
|
||||
}
|
||||
39
src/ui/components/common/SmallButton.tsx
Normal file
39
src/ui/components/common/SmallButton.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
|
||||
import './SmallButton.css'
|
||||
import Wrench from '../../../resources/icons/wrench.svg'
|
||||
import { translate } from '../../../utils/language'
|
||||
|
||||
interface IProps {
|
||||
children?: React.ReactNode[] | React.ReactNode
|
||||
onClick: () => unknown
|
||||
id?: string
|
||||
contents?: string
|
||||
}
|
||||
|
||||
export default class SmallButton extends React.Component<IProps> {
|
||||
constructor(props: IProps) {
|
||||
super(props)
|
||||
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
}
|
||||
|
||||
async showAlert() {
|
||||
if (this.props.contents) alert(await translate(this.props.contents))
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
this.props.onClick()
|
||||
this.showAlert()
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="SmallButtonSection">
|
||||
<div className="SmallButtonButton" onClick={this.handleClick}>
|
||||
<img src={Wrench} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -13,12 +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://cdn.discordapp.com/attachments/615655311960965130/1079203157294460958/GrasscutterCulti3.4.zip'
|
||||
const FULL_BUILD_DOWNLOAD = 'https://github.com/NotThorny/Grasscutter/releases/download/culti-aio/GrasscutterCulti.zip' // Change to link that can be updated without modifying here
|
||||
const 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.4/GC-Resources-3.4.zip' // Use Yuuki res as grasscutter crepe res are broken
|
||||
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 MIGOTO_DOWNLOAD =
|
||||
'https://github.com/SilentNightSound/GI-Model-Importer/releases/download/V6.0/3dmigoto-GIMI-for-playing-mods.zip'
|
||||
|
||||
interface IProps {
|
||||
closeFn: () => void
|
||||
@@ -30,8 +32,10 @@ interface IState {
|
||||
grasscutter_downloading: boolean
|
||||
resources_downloading: boolean
|
||||
repo_downloading: boolean
|
||||
migoto_downloading: boolean
|
||||
grasscutter_set: boolean
|
||||
resources_exist: boolean
|
||||
swag: boolean
|
||||
}
|
||||
|
||||
export default class Downloads extends React.Component<IProps, IState> {
|
||||
@@ -43,8 +47,10 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
grasscutter_downloading: this.props.downloadManager.downloadingJar(),
|
||||
resources_downloading: this.props.downloadManager.downloadingResources(),
|
||||
repo_downloading: this.props.downloadManager.downloadingRepo(),
|
||||
migoto_downloading: this.props.downloadManager.downloadingMigoto(),
|
||||
grasscutter_set: false,
|
||||
resources_exist: false,
|
||||
swag: false,
|
||||
}
|
||||
|
||||
this.getGrasscutterFolder = this.getGrasscutterFolder.bind(this)
|
||||
@@ -54,11 +60,17 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
this.downloadGrasscutterStable = this.downloadGrasscutterStable.bind(this)
|
||||
this.downloadGrasscutterLatest = this.downloadGrasscutterLatest.bind(this)
|
||||
this.downloadResources = this.downloadResources.bind(this)
|
||||
this.downloadMigoto = this.downloadMigoto.bind(this)
|
||||
this.toggleButtons = this.toggleButtons.bind(this)
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const gc_path = await getConfigOption('grasscutter_path')
|
||||
const swag = await getConfigOption('swag_mode')
|
||||
|
||||
this.setState({
|
||||
swag: swag || false,
|
||||
})
|
||||
|
||||
listen('jar_extracted', () => {
|
||||
this.setState({ grasscutter_set: true }, this.forceUpdate)
|
||||
@@ -113,10 +125,16 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
return folderPath
|
||||
}
|
||||
|
||||
async getCultivationFolder() {
|
||||
const folderPath = (await dataDir()) + 'cultivation'
|
||||
|
||||
return folderPath
|
||||
}
|
||||
|
||||
async downloadGrasscutterFullBuild() {
|
||||
const folder = await this.getGrasscutterFolder()
|
||||
this.props.downloadManager.addDownload(FULL_BUILD_DOWNLOAD, folder + '\\GrasscutterCulti3.4.zip', async () => {
|
||||
await unzip(folder + '\\GrasscutterCulti3.4.zip', folder + '\\', true)
|
||||
this.props.downloadManager.addDownload(FULL_BUILD_DOWNLOAD, folder + '\\GrasscutterCulti.zip', async () => {
|
||||
await unzip(folder + '\\GrasscutterCulti.zip', folder + '\\', true)
|
||||
this.toggleButtons()
|
||||
})
|
||||
|
||||
@@ -172,7 +190,6 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
async downloadResources() {
|
||||
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.'
|
||||
@@ -202,6 +219,20 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
this.toggleButtons()
|
||||
}
|
||||
|
||||
async downloadMigoto() {
|
||||
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.toggleButtons()
|
||||
})
|
||||
|
||||
this.toggleButtons()
|
||||
}
|
||||
|
||||
async toggleButtons() {
|
||||
const gc_path = await getConfigOption('grasscutter_path')
|
||||
|
||||
@@ -211,6 +242,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
grasscutter_downloading: this.props.downloadManager.downloadingJar(),
|
||||
resources_downloading: this.props.downloadManager.downloadingResources(),
|
||||
repo_downloading: this.props.downloadManager.downloadingRepo(),
|
||||
migoto_downloading: this.props.downloadManager.downloadingMigoto(),
|
||||
grasscutter_set: gc_path !== '',
|
||||
})
|
||||
}
|
||||
@@ -218,7 +250,6 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
render() {
|
||||
return (
|
||||
<Menu closeFn={this.props.closeFn} className="Downloads" heading="Downloads">
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="HeaderText" id="downloadMenuAIOHeader">
|
||||
@@ -226,9 +257,7 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
</div>
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerGCFullBuild">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelGCFullBuild">
|
||||
<Tr
|
||||
text={'downloads.grasscutter_fullbuild'}
|
||||
/>
|
||||
<Tr text={'downloads.grasscutter_fullbuild'} />
|
||||
<HelpButton contents="help.gc_fullbuild" />
|
||||
</div>
|
||||
<div className="DownloadValue" id="downloadMenuButtonGCFullBuild">
|
||||
@@ -340,6 +369,26 @@ export default class Downloads extends React.Component<IProps, IState> {
|
||||
</BigButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.swag && (
|
||||
<>
|
||||
<Divider />
|
||||
<div className="HeaderText" id="downloadMenuModsHeader">
|
||||
<Tr text="downloads.mods_header" />
|
||||
</div>
|
||||
<div className="DownloadMenuSection" id="downloadMenuContainerMigoto">
|
||||
<div className="DownloadLabel" id="downloadMenuLabelMigoto">
|
||||
<Tr text={'downloads.migoto'} />
|
||||
<HelpButton contents="help.migoto" />
|
||||
</div>
|
||||
<div className="DownloadValue" id="downloadMenuButtonMigoto">
|
||||
<BigButton disabled={this.state.migoto_downloading} onClick={this.downloadMigoto} id="migotoBtn">
|
||||
<Tr text="components.download" />
|
||||
</BigButton>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { invoke } from '@tauri-apps/api'
|
||||
import { dataDir } from '@tauri-apps/api/path'
|
||||
import DirInput from '../common/DirInput'
|
||||
import Menu from './Menu'
|
||||
import Tr, { getLanguages, translate } from '../../../utils/language'
|
||||
import Tr, { getLanguages } from '../../../utils/language'
|
||||
import { setConfigOption, getConfig, getConfigOption, Configuration } from '../../../utils/configuration'
|
||||
import Checkbox from '../common/Checkbox'
|
||||
import Divider from './Divider'
|
||||
@@ -16,6 +16,7 @@ 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'
|
||||
|
||||
interface IProps {
|
||||
closeFn: () => void
|
||||
@@ -37,8 +38,10 @@ interface IState {
|
||||
use_internal_proxy: boolean
|
||||
wipe_login: boolean
|
||||
horny_mode: boolean
|
||||
auto_mongodb: boolean
|
||||
swag: boolean
|
||||
platform: string
|
||||
un_elevated: boolean
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: string
|
||||
@@ -66,7 +69,9 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
wipe_login: false,
|
||||
horny_mode: false,
|
||||
swag: false,
|
||||
auto_mongodb: false,
|
||||
platform: '',
|
||||
un_elevated: false,
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: '',
|
||||
@@ -83,6 +88,8 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
this.setCustomBackground = this.setCustomBackground.bind(this)
|
||||
this.toggleEncryption = this.toggleEncryption.bind(this)
|
||||
this.removeRSA = this.removeRSA.bind(this)
|
||||
this.addMigotoDelay = this.addMigotoDelay.bind(this)
|
||||
this.toggleUnElevatedGame = this.toggleUnElevatedGame.bind(this)
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@@ -107,13 +114,15 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
bg_url_or_path: config.customBackground || '',
|
||||
themes: (await getThemeList()).map((t) => t.name),
|
||||
theme: config.theme || 'default',
|
||||
encryption: await translate(encEnabled ? 'options.enabled' : 'options.disabled'),
|
||||
encryption: encEnabled || false,
|
||||
patch_rsa: config.patch_rsa || false,
|
||||
use_internal_proxy: config.use_internal_proxy || false,
|
||||
wipe_login: config.wipe_login || false,
|
||||
horny_mode: config.horny_mode || false,
|
||||
swag: config.swag_mode || false,
|
||||
auto_mongodb: config.auto_mongodb || false,
|
||||
platform,
|
||||
un_elevated: config.un_elevated || false,
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: config.akebi_path || '',
|
||||
@@ -157,7 +166,7 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
|
||||
// Update encryption button when setting new jar
|
||||
this.setState({
|
||||
encryption: await translate(encEnabled ? 'options.enabled' : 'options.disabled'),
|
||||
encryption: encEnabled,
|
||||
})
|
||||
|
||||
window.location.reload()
|
||||
@@ -188,7 +197,6 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
|
||||
// Set game exe in Migoto ini
|
||||
invoke('set_migoto_target', {
|
||||
path: this.state.game_install_path,
|
||||
migotoPath: value,
|
||||
})
|
||||
}
|
||||
@@ -260,18 +268,35 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
await server.toggleEncryption(folderPath + '/config.json')
|
||||
|
||||
this.setState({
|
||||
encryption: await translate(
|
||||
(await server.encryptionEnabled(folderPath + '/config.json')) ? 'options.enabled' : 'options.disabled'
|
||||
),
|
||||
encryption: await server.encryptionEnabled(folderPath + '/config.json'),
|
||||
})
|
||||
|
||||
alert('Restart Grasscutter to apply encryption settings! If it is already closed, just start as normal.')
|
||||
// Check if Grasscutter is running, and restart if so to apply changes
|
||||
if (await invoke('is_grasscutter_running')) {
|
||||
alert('Automatically restarting Grasscutter to apply encryption changes!')
|
||||
await invoke('restart_grasscutter')
|
||||
}
|
||||
}
|
||||
|
||||
async toggleUnElevatedGame() {
|
||||
const changedVal = !(await getConfigOption('un_elevated'))
|
||||
setConfigOption('un_elevated', changedVal)
|
||||
|
||||
this.setState({
|
||||
un_elevated: changedVal,
|
||||
})
|
||||
}
|
||||
|
||||
async removeRSA() {
|
||||
await meta.unpatchGame()
|
||||
}
|
||||
|
||||
async addMigotoDelay() {
|
||||
invoke('set_migoto_delay', {
|
||||
migotoPath: this.state.migoto_path,
|
||||
})
|
||||
}
|
||||
|
||||
async installCert() {
|
||||
await invoke('generate_ca_files', {
|
||||
path: (await dataDir()) + 'cultivation',
|
||||
@@ -356,6 +381,18 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainerAutoMongodb">
|
||||
<div className="OptionLabel" id="menuOptionsLabelAutoMongodb">
|
||||
<Tr text="options.auto_mongodb" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsCheckboxAutoMongodb">
|
||||
<Checkbox
|
||||
onChange={() => this.toggleOption('auto_mongodb')}
|
||||
checked={this.state?.auto_mongodb}
|
||||
id="autoMongodb"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
@@ -373,9 +410,7 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
<HelpButton contents="help.encryption" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsButtonToggleEnc">
|
||||
<BigButton onClick={this.toggleEncryption} id="toggleEnc">
|
||||
{this.state.encryption}
|
||||
</BigButton>
|
||||
<Checkbox onChange={() => this.toggleEncryption()} checked={this.state.encryption} id="toggleEnc" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainerInstallCert">
|
||||
@@ -404,6 +439,7 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
<Tr text="swag.migoto" />
|
||||
</div>
|
||||
<div className="OptionValue" id="menuOptionsDirMigoto">
|
||||
<SmallButton onClick={this.addMigotoDelay} id="migotoDelay" contents="help.add_delay"></SmallButton>
|
||||
<DirInput onChange={this.setMigoto} value={this.state?.migoto_path} extensions={['exe']} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -432,6 +468,18 @@ 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" />
|
||||
</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">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import { ModData, PartialModData } from '../../../utils/gamebanana'
|
||||
import { getConfigOption } from '../../../utils/configuration'
|
||||
|
||||
import './ModTile.css'
|
||||
import Like from '../../../resources/icons/like.svg'
|
||||
@@ -18,6 +19,7 @@ interface IProps {
|
||||
}
|
||||
|
||||
interface IState {
|
||||
horny: boolean
|
||||
hover: boolean
|
||||
modEnabled: boolean
|
||||
}
|
||||
@@ -27,6 +29,7 @@ export class ModTile extends React.Component<IProps, IState> {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
horny: false,
|
||||
hover: false,
|
||||
modEnabled: false,
|
||||
}
|
||||
@@ -44,10 +47,13 @@ export class ModTile extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const horny = await getConfigOption('horny_mode')
|
||||
|
||||
if (!('id' in this.props.mod)) {
|
||||
// Partial mod
|
||||
this.setState({
|
||||
modEnabled: await modIsEnabled(this.props.mod.name),
|
||||
horny,
|
||||
})
|
||||
|
||||
return
|
||||
@@ -55,6 +61,7 @@ export class ModTile extends React.Component<IProps, IState> {
|
||||
|
||||
this.setState({
|
||||
modEnabled: await modIsEnabled(String(this.props.mod.id)),
|
||||
horny,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -66,6 +73,7 @@ export class ModTile extends React.Component<IProps, IState> {
|
||||
this.setState(
|
||||
{
|
||||
modEnabled: !this.state.modEnabled,
|
||||
horny: !this.state.horny,
|
||||
},
|
||||
() => {
|
||||
if (this.state.modEnabled) {
|
||||
@@ -108,7 +116,7 @@ export class ModTile extends React.Component<IProps, IState> {
|
||||
))}
|
||||
<img
|
||||
src={mod.images[0]}
|
||||
className={`ModImageInner ${'id' in mod && !this.props.horny && mod.nsfw ? 'nsfw' : ''} ${
|
||||
className={`ModImageInner ${'id' in mod && !this.state.horny && mod.nsfw ? 'nsfw' : ''} ${
|
||||
this.state.hover ? 'blur' : ''
|
||||
}`}
|
||||
/>
|
||||
|
||||
@@ -60,51 +60,51 @@ export default class NewsSection extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
async showLatestCommits() {
|
||||
// Just use official API
|
||||
// Just use official API
|
||||
const response: string = await invoke('req_get', {
|
||||
url: 'https://api.github.com/repos/Grasscutters/Grasscutter/commits',
|
||||
})
|
||||
let grasscutterApiResponse: GrasscutterAPIResponse | null = null
|
||||
|
||||
try {
|
||||
grasscutterApiResponse = JSON.parse(response)
|
||||
} catch (e) {
|
||||
grasscutterApiResponse = null
|
||||
}
|
||||
|
||||
let commits: CommitResponse[]
|
||||
if (grasscutterApiResponse?.commits == null) {
|
||||
// If it didn't work, try again anyways
|
||||
const response: string = await invoke('req_get', {
|
||||
url: 'https://api.github.com/repos/Grasscutters/Grasscutter/commits',
|
||||
})
|
||||
let grasscutterApiResponse: GrasscutterAPIResponse | null = null
|
||||
commits = JSON.parse(response)
|
||||
} else {
|
||||
commits = grasscutterApiResponse.commits.gc_stable
|
||||
}
|
||||
|
||||
try {
|
||||
grasscutterApiResponse = JSON.parse(response)
|
||||
} catch (e) {
|
||||
grasscutterApiResponse = null
|
||||
}
|
||||
// Probably rate-limited
|
||||
if (!Array.isArray(commits)) return
|
||||
|
||||
let commits: CommitResponse[]
|
||||
if (grasscutterApiResponse?.commits == null) {
|
||||
// If it didn't work, try again anyways
|
||||
const response: string = await invoke('req_get', {
|
||||
url: 'https://api.github.com/repos/Grasscutters/Grasscutter/commits',
|
||||
})
|
||||
commits = JSON.parse(response)
|
||||
} else {
|
||||
commits = grasscutterApiResponse.commits.gc_stable
|
||||
}
|
||||
// Get only first 5
|
||||
const commitsList = commits.slice(0, 10)
|
||||
const commitsListHtml = commitsList.map((commitResponse: CommitResponse) => {
|
||||
return (
|
||||
<tr className="Commit" id="newsCommitsTable" key={commitResponse.sha}>
|
||||
<td className="CommitAuthor">
|
||||
<span>{commitResponse.commit.author.name}</span>
|
||||
</td>
|
||||
<td className="CommitMessage">
|
||||
<span>{commitResponse.commit.message}</span>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
|
||||
// Probably rate-limited
|
||||
if (!Array.isArray(commits)) return
|
||||
|
||||
// Get only first 5
|
||||
const commitsList = commits.slice(0, 10)
|
||||
const commitsListHtml = commitsList.map((commitResponse: CommitResponse) => {
|
||||
return (
|
||||
<tr className="Commit" id="newsCommitsTable" key={commitResponse.sha}>
|
||||
<td className="CommitAuthor">
|
||||
<span>{commitResponse.commit.author.name}</span>
|
||||
</td>
|
||||
<td className="CommitMessage">
|
||||
<span>{commitResponse.commit.message}</span>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
|
||||
this.setState({
|
||||
commitList: commitsListHtml,
|
||||
news: <>{commitsListHtml}</>,
|
||||
})
|
||||
this.setState({
|
||||
commitList: commitsListHtml,
|
||||
news: <>{commitsListHtml}</>,
|
||||
})
|
||||
|
||||
return this.state.commitList
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ let defaultConfig: Configuration
|
||||
use_internal_proxy: true,
|
||||
wipe_login: false,
|
||||
horny_mode: false,
|
||||
auto_mongodb: false,
|
||||
un_elevated: false,
|
||||
}
|
||||
})()
|
||||
|
||||
@@ -51,6 +53,8 @@ export interface Configuration {
|
||||
wipe_login: boolean
|
||||
horny_mode: boolean
|
||||
swag_mode?: boolean
|
||||
auto_mongodb: boolean
|
||||
un_elevated: boolean
|
||||
|
||||
// Swag stuff
|
||||
akebi_path?: string
|
||||
|
||||
@@ -90,7 +90,7 @@ export default class DownloadHandler {
|
||||
} = payload
|
||||
|
||||
// Find the download that is not extracting and set it's status as such
|
||||
const index = this.downloads.findIndex((download) => download.path === obj.file || obj.new_folder)
|
||||
const index = this.downloads.findIndex((download) => download.path === obj.file)
|
||||
this.downloads[index].status = 'finished'
|
||||
})
|
||||
}
|
||||
@@ -101,21 +101,25 @@ export default class DownloadHandler {
|
||||
|
||||
downloadingJar() {
|
||||
// Kinda hacky but it works
|
||||
return this.downloads.some((d) => d.path.includes('grasscutter.zip'))
|
||||
return this.downloads.some((d) => d.path.includes('grasscutter.zip') && d.status != ('finished' || 'error'))
|
||||
}
|
||||
|
||||
downloadingFullBuild() {
|
||||
// Kinda hacky but it works
|
||||
return this.downloads.some((d) => d.path.includes('GrasscutterCulti3.4.zip'))
|
||||
return this.downloads.some((d) => d.path.includes('GrasscutterCulti') && d.status != ('finished' || 'error'))
|
||||
}
|
||||
|
||||
downloadingResources() {
|
||||
// Kinda hacky but it works
|
||||
return this.downloads.some((d) => d.path.includes('resources'))
|
||||
return this.downloads.some((d) => d.path.includes('resources') && d.status != ('finished' || 'error'))
|
||||
}
|
||||
|
||||
downloadingRepo() {
|
||||
return this.downloads.some((d) => d.path.includes('grasscutter_repo.zip'))
|
||||
return this.downloads.some((d) => d.path.includes('grasscutter_repo.zip') && d.status != ('finished' || 'error'))
|
||||
}
|
||||
|
||||
downloadingMigoto() {
|
||||
return this.downloads.some((d) => d.path.includes('3dmigoto') && d.status != ('finished' || 'error'))
|
||||
}
|
||||
|
||||
addDownload(url: string, path: string, onFinish?: () => void) {
|
||||
|
||||
@@ -12,6 +12,17 @@ export async function getGameExecutable() {
|
||||
return pathArr[pathArr.length - 1]
|
||||
}
|
||||
|
||||
export async function getGrasscutterJar() {
|
||||
const config = await getConfig()
|
||||
|
||||
if (!config.grasscutter_path) {
|
||||
return null
|
||||
}
|
||||
|
||||
const pathArr = config.grasscutter_path.replace(/\\/g, '/').split('/')
|
||||
return pathArr[pathArr.length - 1]
|
||||
}
|
||||
|
||||
export async function getGameFolder() {
|
||||
const config = await getConfig()
|
||||
|
||||
|
||||
@@ -1,25 +1,12 @@
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { dataDir } from '@tauri-apps/api/path'
|
||||
import { getGameFolder } from './game'
|
||||
// Patch file from: https://github.com/34736384/RSAPatch/
|
||||
|
||||
export async function patchGame() {
|
||||
// Do we have a patch already?
|
||||
const patchedExists = await invoke('dir_exists', {
|
||||
path: (await getBackupRSAPath()) + '\\version.dll',
|
||||
})
|
||||
|
||||
if (!patchedExists) {
|
||||
// No patch found? Patching creates one
|
||||
const patched = await downloadRSA()
|
||||
|
||||
if (!patched) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
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: (await getBackupRSAPath()) + '\\version.dll',
|
||||
path1: patchPath,
|
||||
path2: (await getGameRSAPath()) + '\\mhypbase.dll',
|
||||
})
|
||||
|
||||
@@ -31,7 +18,7 @@ export async function patchGame() {
|
||||
|
||||
// Copy the patch to game files
|
||||
const replaced = await invoke('copy_file_with_new_name', {
|
||||
path: (await getBackupRSAPath()) + '\\version.dll',
|
||||
path: patchPath,
|
||||
newPath: await getGameRSAPath(),
|
||||
newName: 'version.dll',
|
||||
})
|
||||
@@ -61,25 +48,3 @@ export async function getGameRSAPath() {
|
||||
|
||||
return (gameData + '\\').replace(/\\/g, '/')
|
||||
}
|
||||
|
||||
export async function getBackupRSAPath() {
|
||||
return (await dataDir()) + 'cultivation\\rsa'
|
||||
}
|
||||
|
||||
export async function downloadRSA() {
|
||||
// Patch file from: https://github.com/34736384/RSAPatch/
|
||||
|
||||
// Should make sure rsa path exists
|
||||
await invoke('dir_create', {
|
||||
path: await getBackupRSAPath(),
|
||||
})
|
||||
|
||||
// Copy patch from local for offline compatibility
|
||||
await invoke('copy_file_with_new_name', {
|
||||
path: (await invoke('install_location')) + '\\patch\\version.dll',
|
||||
newPath: await getBackupRSAPath(),
|
||||
newName: 'version.dll',
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user