Compare commits
1 Commits
rewrite
...
custom-opt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1a41bec65 |
@@ -2,9 +2,20 @@ root = true
|
|||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = crlf
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
insert_final_newline = false
|
||||||
max_line_length = 120
|
max_line_length = 120
|
||||||
tab_width = 2
|
tab_width = 2
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.rs]
|
||||||
|
max_line_length = 100
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[{*.ats,*.cts,*.mts,*.ts}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.json]
|
||||||
|
indent_size = 2
|
||||||
@@ -1,40 +1,39 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es2021": true,
|
"es2021": true,
|
||||||
"node": true
|
"node": true
|
||||||
},
|
|
||||||
"extends": ["eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": true
|
|
||||||
},
|
},
|
||||||
"ecmaVersion": "latest",
|
"extends": [
|
||||||
"sourceType": "module"
|
"eslint:recommended",
|
||||||
},
|
"plugin:react/recommended",
|
||||||
"plugins": ["react", "@typescript-eslint"],
|
"plugin:@typescript-eslint/recommended"
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/ban-types": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"extendDefaults": true,
|
|
||||||
"types": {
|
|
||||||
"{}": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"@typescript-eslint/no-unused-vars": [
|
"parser": "@typescript-eslint/parser",
|
||||||
"warn",
|
"parserOptions": {
|
||||||
{
|
"ecmaFeatures": {
|
||||||
"argsIgnorePattern": "^_",
|
"jsx": true
|
||||||
"varsIgnorePattern": "^_"
|
},
|
||||||
}
|
"ecmaVersion": "latest",
|
||||||
]
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"settings": {
|
"plugins": [
|
||||||
"react": {
|
"react",
|
||||||
"version": "detect"
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"semi": [
|
||||||
|
"error",
|
||||||
|
"never"
|
||||||
|
],
|
||||||
|
"no-explicit-any": "off"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
3
.gitattributes
vendored
@@ -1,3 +0,0 @@
|
|||||||
* text=auto eol=lf
|
|
||||||
|
|
||||||
src-tauri/keys/* binary
|
|
||||||
61
.github/workflows/backend-checks.yml
vendored
@@ -1,61 +0,0 @@
|
|||||||
name: Check backend
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- '.github/workflows/backend-checks.yml'
|
|
||||||
- 'src-tauri/**'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- '.github/workflows/backend-checks.yml'
|
|
||||||
- 'src-tauri/**'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.ref }}-${{ github.workflow }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
rustfmt:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --manifest-path ./src-tauri/Cargo.toml --all -- --check
|
|
||||||
|
|
||||||
clippy:
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [windows-latest, ubuntu-latest, macos-latest]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Install Linux dependencies
|
|
||||||
if: matrix.platform == 'ubuntu-latest'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libwebkit2gtk-4.0-dev \
|
|
||||||
build-essential \
|
|
||||||
curl \
|
|
||||||
wget \
|
|
||||||
libssl-dev \
|
|
||||||
libgtk-3-dev \
|
|
||||||
libayatana-appindicator3-dev \
|
|
||||||
librsvg2-dev
|
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
with:
|
|
||||||
working-directory: src-tauri
|
|
||||||
|
|
||||||
- uses: actions-rs/clippy-check@v1
|
|
||||||
with:
|
|
||||||
name: clippy (${{ runner.os }})
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
args: --manifest-path ./src-tauri/Cargo.toml --no-default-features -- -D warnings
|
|
||||||
85
.github/workflows/build.yml
vendored
@@ -1,85 +0,0 @@
|
|||||||
name: Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- '.github/workflows/build.yml'
|
|
||||||
- 'src-tauri/**/*'
|
|
||||||
- 'src/**/*'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- '.github/workflows/build.yml'
|
|
||||||
- 'src-tauri/**/*'
|
|
||||||
- 'src/**/*'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.ref }}-${{ github.workflow }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-win:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: setup node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Install Rust
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
|
|
||||||
- name: Install deps and build
|
|
||||||
run: yarn && yarn build --debug
|
|
||||||
|
|
||||||
- name: Compress build
|
|
||||||
uses: vimtor/action-zip@v1
|
|
||||||
with:
|
|
||||||
files: src-tauri/target/debug/lang/ src-tauri/target/debug/keys/ src-tauri/target/debug/patch/ src-tauri/target/debug/Cultivation.exe src-tauri/target/debug/bundle/msi/
|
|
||||||
recursive: true
|
|
||||||
dest: Cultivation.zip
|
|
||||||
|
|
||||||
- name: Upload build
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: CultivationWin
|
|
||||||
path: Cultivation.zip
|
|
||||||
|
|
||||||
build-ubuntu:
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: setup node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Install Rust
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
|
|
||||||
- name: Install libraries
|
|
||||||
run: sudo apt install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
|
|
||||||
|
|
||||||
- name: Install deps and build
|
|
||||||
run: yarn && yarn build --debug
|
|
||||||
|
|
||||||
- name: Compress build
|
|
||||||
uses: vimtor/action-zip@v1
|
|
||||||
with:
|
|
||||||
files: src-tauri/target/debug/lang/ src-tauri/target/debug/keys/ src-tauri/target/debug/patch/ src-tauri/target/debug/cultivation
|
|
||||||
recursive: true
|
|
||||||
dest: Cultivation.zip
|
|
||||||
|
|
||||||
- name: Upload build
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: CultivationLinux
|
|
||||||
path: Cultivation.zip
|
|
||||||
32
.github/workflows/frontend-checks.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: Check frontend
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths-ignore:
|
|
||||||
- '**.lock'
|
|
||||||
- '**.rs'
|
|
||||||
- '**.toml'
|
|
||||||
pull_request:
|
|
||||||
paths-ignore:
|
|
||||||
- '**.lock'
|
|
||||||
- '**.rs'
|
|
||||||
- '**.toml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.ref }}-${{ github.workflow }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
prettier-tsc-eslint-checks:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Install modules
|
|
||||||
run: yarn
|
|
||||||
- name: Run prettier
|
|
||||||
run: yarn prettier --check .
|
|
||||||
- name: Run tsc
|
|
||||||
run: yarn tsc --noEmit
|
|
||||||
- name: Run ESLint
|
|
||||||
run: yarn eslint src
|
|
||||||
4
.gitignore
vendored
@@ -17,12 +17,10 @@
|
|||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
.vs
|
|
||||||
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
# moved lang files
|
# moved lang files
|
||||||
/lang
|
/lang
|
||||||
package-lock.json
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
. "$(dirname -- "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
yarn lint-staged --allow-empty
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"src-tauri/**/*.rs": "rustfmt --edition 2021",
|
|
||||||
"*": "yarn prettier --write --ignore-unknown"
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
src-tauri/resources/
|
|
||||||
src-tauri/target/
|
|
||||||
src-tauri/WixTools/
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true
|
|
||||||
}
|
|
||||||
3
.vscode/settings.json
vendored
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"rust-analyzer.linkedProjects": ["src-tauri/Cargo.toml"]
|
|
||||||
}
|
|
||||||
141
README.md
@@ -1,126 +1,67 @@
|
|||||||
EN | [简中](README_zh-CN.md) | [繁中](README_zh-TW.md) |
|
# NOTICE
|
||||||
|
Yes! The Cultivation repository is **open**. This does **not** mean it has released.\
|
||||||
|
Cultivation will be releasing at some point after opening this repo.
|
||||||
|
|
||||||
|
**This also means you will not be provided explicit support for Cultivation.**\
|
||||||
|
Consider Cultivation to be the bleeding-edge version of GrassClipper.
|
||||||
|
|
||||||
|
During this open-beta testing period, **helpful issues are appreciated**, while unhelpful ones will be closed.
|
||||||
|
|
||||||
|
## Fair Warning
|
||||||
|
Cultivation is **VERY MUCH IN BETA** and a majority of features do not work.\
|
||||||
|
There are **no official releases of Cultivation**. You are **required** to build the application from **scratch**.\
|
||||||
|
Please do **NOT install, download, or use pre-compiled versions of Cultivation**. Only use releases from this GitHub repository.
|
||||||
|
|
||||||
# Cultivation
|
# Cultivation
|
||||||
|
|
||||||
A game launcher designed to easily proxy traffic from anime game to private servers.
|
A game launcher designed to easily proxy traffic from anime game to private servers.
|
||||||
|
|
||||||
# Table Of Contents
|
# Table Of Contents
|
||||||
|
* [Download](#download)
|
||||||
- [Client Patching Notice](#client-patching-notice)
|
* [Developer Quick-start](#developer-quickstart)
|
||||||
- [Download](#download)
|
* [Setup](#setup)
|
||||||
- [Setup](#setup)
|
* [Building](#building)
|
||||||
- [Troubleshooting](#troubleshooting)
|
* [Troubleshooting](#troubleshooting)
|
||||||
- [Developer Quick-start](#developer-quickstart)
|
* [Theming](#theming)
|
||||||
- [Setup](#setup)
|
|
||||||
- [Building](#building)
|
|
||||||
- [Code Formatting and Linting](#code-formatting-and-linting)
|
|
||||||
- [Generating Update Artifacts](#generating-update-artifacts)
|
|
||||||
- [Theming](#theming)
|
|
||||||
- [Screenshots](#screenshots)
|
|
||||||
- [Credits](#credits)
|
|
||||||
|
|
||||||
# Client Patching Notice - RSA
|
|
||||||
|
|
||||||
For game versions 3.1 and above, Cultivation automatically makes a small patch to your game client when launching using Grasscutter, and restores it upon closing the game. In theory, you should still be totally safe, however it would be dishonest to not explicitly state that **modifying the game client could, theoretically, lead to a ban if you connect to official servers with it**. It is extremely unlikely AND there are no instances known of it happening, but the possibility exists.
|
|
||||||
|
|
||||||
# Download
|
# Download
|
||||||
|
|
||||||
[Find release builds here!](https://github.com/Grasscutters/Cultivation/releases)
|
[Find release builds here!](https://github.com/Grasscutters/Cultivation/releases)
|
||||||
|
|
||||||
Download and open the MSI, and once installed, run Cultivation as administrator. Refer below for more [detailed setup instructions](#setup).
|
Once downloaded, extract somewhere and open as administrator.
|
||||||
|
|
||||||
**Windows 7 Users:** You will need to download [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section) manually, and download the `.zip` instead of the `.msi`.
|
|
||||||
|
|
||||||
# Setup
|
|
||||||
|
|
||||||
5-minute video for those who don't like to/cannot read: https://youtu.be/e0irOYbQe7I
|
|
||||||
|
|
||||||
- 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 [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)
|
|
||||||
- If you are on GNU/Linux or MacOS, [help us port Windows-specific system calls to GNU/Linux and MacOS!](https://github.com/Grasscutters/Cultivation/issues/7)
|
|
||||||
- Install or extract Cultivation
|
|
||||||
- Open Cultivation **_as administrator_**
|
|
||||||
- Before clicking randomly on stuff, in options (top right cog icon), set your Game Install Path.
|
|
||||||
- If you are using an existing server installation from somewhere else, you can set the `.jar` file in settings as well. All downloads made through Culti will automatically use that path, no additional config needed.
|
|
||||||
- If you use multiple Java versions, you can set the Java path to your Java 17 installation (only required if you are running your own server)
|
|
||||||
- Decide if you want to download your own server, or just join a public one
|
|
||||||
- If joining a public one, you're done. Just click "Connect with Grasscutter" and input the address and port. You do not have to continue these instructions.
|
|
||||||
- If you are getting System Error, or 4214, ask the [Discord support channels](https://discord.gg/grasscutter)
|
|
||||||
- Open the "Downloads" menu (top right)
|
|
||||||
- Download "Grasscutter All-in-One" (top of the list)
|
|
||||||
- Once that is done, click the icon next to "Launch"
|
|
||||||
- To play on your new server:
|
|
||||||
- Click "Connect with Grasscutter"
|
|
||||||
- Input `localhost` as the address, and `443` as the port
|
|
||||||
- Ensure HTTPS is disabled
|
|
||||||
- Any generic "I am getting XYZ error!" should go in the [Discord support channels](https://discord.gg/grasscutter)
|
|
||||||
- Any 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
|
# Developer Quickstart
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
* Install [NodeJS >12](https://nodejs.org/en/)
|
||||||
- Install [NodeJS >18](https://nodejs.org/en/)
|
* Install [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) & [Rust compiler](https://www.rust-lang.org/tools/install)
|
||||||
- Install [pnpm](https://pnpm.io/installation) (cry about it `yarn` lovers)
|
* `npm install` or `yarn install`
|
||||||
- Install [Rust](https://www.rust-lang.org/tools/install)
|
* `npm run start:dev` or `yarn start:dev`
|
||||||
- `pnpm install`
|
|
||||||
- `pnpm tauri dev`
|
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
`npm run build` or `yarn build`
|
||||||
|
|
||||||
For a release build,
|
Add `--release` or `--debug` depending on what release you are creating. This defaults to `--release`
|
||||||
|
|
||||||
- `pnpm build`
|
### Updating
|
||||||
|
* Add the `TAURI_PRIVATE_KEY` as an environment variable with a path to your private key.
|
||||||
|
* Add the `TAURI_KEY_PASSWORD` as an environment variable with the password for your private key.
|
||||||
|
* Run `npm run update` or `yarn build`
|
||||||
|
* The update will be in `src-tauri/target/(release|debug)/msi/Cultivation_X.X.X_x64_xx-XX.msi.zip`
|
||||||
|
|
||||||
For a debug build,
|
# Troubleshooting
|
||||||
|
TODO. Collect common issues before updating.
|
||||||
- `pnpm build --debug`
|
|
||||||
|
|
||||||
### Code Formatting and Linting
|
|
||||||
|
|
||||||
Formatting:
|
|
||||||
|
|
||||||
- `pnpm format`
|
|
||||||
|
|
||||||
Check Lints, fix (some) lints:
|
|
||||||
|
|
||||||
- `pnpm lint`, `pnpm lint:fix`
|
|
||||||
|
|
||||||
### Generating Update Artifacts
|
|
||||||
|
|
||||||
- Add the `TAURI_PRIVATE_KEY` as an environment variable with a path to your private key.
|
|
||||||
- Add the `TAURI_KEY_PASSWORD` as an environment variable with the password for your private key.
|
|
||||||
- `pnpm build`
|
|
||||||
|
|
||||||
The update will be at `src-tauri/target/(release|debug)/msi/Cultivation_X.X.X_x64_xx-XX.msi.zip`
|
|
||||||
|
|
||||||
# Theming
|
# Theming
|
||||||
|
|
||||||
A full theming reference can be found [here!](/THEMES.md)
|
A full theming reference can be found [here!](/THEMES.md)
|
||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
|

|
||||||
TODO
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
* [SpikeHD](https://github.com/SpikeHD): For originally creating **GrassClipper** and creating the amazing UI of Cultivation.
|
||||||
- [SpikeHD](https://github.com/SpikeHD): For originally creating **GrassClipper** and creating the amazing UI of Cultivation.
|
* [KingRainbow44](https://github.com/KingRainbow44): For building a proxy daemon from scratch and integrating it with Cultivation.
|
||||||
- [KingRainbow44](https://github.com/KingRainbow44): For building a proxy daemon from scratch and integrating it with Cultivation.
|
* [Tauri](https://tauri.app): For providing an amazing, efficient, and simple desktop application framework/library.
|
||||||
- [Benj](https://github.com/4Benj): For assistance in client patching.
|
|
||||||
- [lilmayofuksu](https://github.com/lilmayofuksu): For assistance in client patching.
|
|
||||||
- [Tauri](https://tauri.app): For providing an amazing, efficient, and simple desktop application framework/library.
|
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
[EN](README.md) | 简中 | [繁中](README_zh-TW.md)
|
|
||||||
|
|
||||||
# Cultivation
|
|
||||||
|
|
||||||
一个游戏启动器,旨在轻松将某动漫游戏的流量代理到私人服务器。
|
|
||||||
|
|
||||||
虽然此存储库是**开放的**。 但这**并不**意味着它已经发布。
|
|
||||||
请不要**安装、下载或使用在其他地方找到的预编译版本的 Cultivation**。 仅使用此 GitHub 存储库中的版本。
|
|
||||||
|
|
||||||
# 目录
|
|
||||||
|
|
||||||
- [下载](#下载)
|
|
||||||
- [开发人员快速入门](#开发人员快速入门)
|
|
||||||
- [安装](#安装)
|
|
||||||
- [编译](#编译)
|
|
||||||
- [代码格式化与纠错](#代码格式化与纠错)
|
|
||||||
- [生成更新项目](#生成更新项目)
|
|
||||||
- [启动器主题](#启动器主题)
|
|
||||||
- [画面](#画面)
|
|
||||||
- [成员](#成员)
|
|
||||||
|
|
||||||
# 客户端修补通知
|
|
||||||
|
|
||||||
对于游戏版本为 3.1 及以上时,使用 Grasscutter 启动时,Cultivation 会自动为您的游戏客户端制作一个小补丁,并在关闭游戏时恢复它。 从理论上讲,你应该是完全安全的,但是不明确**如果您使用它连接到官方服务器,修改游戏客户端可能会导致封号**,但可能性是非常小的,并且从未接到发生过此类情况的问题,但存在这种可能性!
|
|
||||||
|
|
||||||
# 下载
|
|
||||||
|
|
||||||
[在此处查找发布版本!](https://github.com/Grasscutters/Cultivation/releases)
|
|
||||||
|
|
||||||
下载后,从某个位置解压缩并以管理员身份打开。
|
|
||||||
|
|
||||||
# 开发人员快速入门
|
|
||||||
|
|
||||||
### 安装
|
|
||||||
|
|
||||||
- 安装 [NodeJS >12](https://nodejs.org/en/)
|
|
||||||
- 安装 [yarn](https://classic.yarnpkg.com/lang/en/docs/install)
|
|
||||||
- 安装 [Rust](https://www.rust-lang.org/tools/install)
|
|
||||||
- `yarn install`
|
|
||||||
- `yarn start:dev`
|
|
||||||
|
|
||||||
### 编译
|
|
||||||
|
|
||||||
发布版本,
|
|
||||||
|
|
||||||
- `yarn build`
|
|
||||||
|
|
||||||
调试版本,
|
|
||||||
|
|
||||||
- `yarn build --debug`
|
|
||||||
|
|
||||||
### 代码格式化与纠错
|
|
||||||
|
|
||||||
格式化:
|
|
||||||
|
|
||||||
- `yarn format`
|
|
||||||
|
|
||||||
纠错, 修复(一些)错误:
|
|
||||||
|
|
||||||
- `yarn lint`, `yarn lint:fix`
|
|
||||||
|
|
||||||
### 生成更新项目
|
|
||||||
|
|
||||||
- 将 `TAURI_PRIVATE_KEY` 添加到环境变量,其中包含私钥的路径。
|
|
||||||
- 将 `TAURI_KEY_PASSWORD` 添加到环境变量,其中包含私钥的密码。
|
|
||||||
- `yarn build`
|
|
||||||
|
|
||||||
更新将生成在 `src-tauri/target/(release|debug)/msi/Cultivation_X.X.X_x64_xx-XX.msi.zip`
|
|
||||||
|
|
||||||
# 启动器主题
|
|
||||||
|
|
||||||
完整的主题参考可以[在这里找到!](/THEMES.md)
|
|
||||||
|
|
||||||
# 画面
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
## 成员
|
|
||||||
|
|
||||||
- [SpikeHD](https://github.com/SpikeHD): For originally creating **GrassClipper** and creating the amazing UI of Cultivation.
|
|
||||||
- [KingRainbow44](https://github.com/KingRainbow44): For building a proxy daemon from scratch and integrating it with Cultivation.
|
|
||||||
- [Benj](https://github.com/4Benj): For assistance in client patching.
|
|
||||||
- [lilmayofuksu](https://github.com/lilmayofuksu): For assistance in client patching.
|
|
||||||
- [Tauri](https://tauri.app): For providing an amazing, efficient, and simple desktop application framework/library.
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
[EN](README.md) | [简中](README_zh-CN.md) | 繁中
|
|
||||||
|
|
||||||
# 客戶端修補通知
|
|
||||||
|
|
||||||
對於遊戲版本為 3.1 及以上時,使用 Grasscutter 啟動時,Cultivation 會自動為您的遊戲客戶端製作一個小修補,並在關閉遊戲時恢復它。 從理論上講,你應該是完全安全的,但是不明確**如果您使用它連接到官方伺服器,修改遊戲客戶端可能會導致封號**,但可能性是非常小的,並且從未接到發生過此類情況的問題,但存在這種可能性!
|
|
||||||
|
|
||||||
# Cultivation
|
|
||||||
|
|
||||||
一個遊戲啟動器,旨在輕松將某動漫遊戲的流量代理到私人伺服器。
|
|
||||||
|
|
||||||
雖然此存儲庫是**開放的**。 但這**並不**意味著它已經發布。
|
|
||||||
請不要**安裝、下載或使用在其他地方找到的預編譯版本的 Cultivation**。 僅使用此 GitHub 存儲庫中的版本。
|
|
||||||
|
|
||||||
# 目錄
|
|
||||||
|
|
||||||
- [下載](#下載)
|
|
||||||
- [開發人員快速入門](#開發人員快速入門)
|
|
||||||
- [安裝](#安裝)
|
|
||||||
- [編譯](#編譯)
|
|
||||||
- [代碼格式化與糾錯](#代碼格式化與糾錯)
|
|
||||||
- [生成更新項目](#生成更新項目)
|
|
||||||
- [啟動器主題](#啟動器主題)
|
|
||||||
- [畫面](#畫面)
|
|
||||||
- [成員](#成員)
|
|
||||||
|
|
||||||
# 下載
|
|
||||||
|
|
||||||
[在此處查找發布版本!](https://github.com/Grasscutters/Cultivation/releases)
|
|
||||||
|
|
||||||
下載後,從某個位置解壓縮並以管理員身份打開。
|
|
||||||
|
|
||||||
# 開發人員快速入門
|
|
||||||
|
|
||||||
### 安裝
|
|
||||||
|
|
||||||
- 安裝 [NodeJS >12](https://nodejs.org/en/)
|
|
||||||
- 安裝 [yarn](https://classic.yarnpkg.com/lang/en/docs/install) (`npm`愛好者去哭吧!(滑稽))
|
|
||||||
- 安裝 [Rust](https://www.rust-lang.org/tools/install)
|
|
||||||
- `yarn install`
|
|
||||||
- `yarn start:dev`
|
|
||||||
|
|
||||||
### 編譯
|
|
||||||
|
|
||||||
發布版本,
|
|
||||||
|
|
||||||
- `yarn build`
|
|
||||||
|
|
||||||
調試版本,
|
|
||||||
|
|
||||||
- `yarn build --debug`
|
|
||||||
|
|
||||||
### 代碼格式化與糾錯
|
|
||||||
|
|
||||||
格式化:
|
|
||||||
|
|
||||||
- `yarn format`
|
|
||||||
|
|
||||||
糾錯, 修復(一些)錯誤:
|
|
||||||
|
|
||||||
- `yarn lint`, `yarn lint:fix`
|
|
||||||
|
|
||||||
### 生成更新項目
|
|
||||||
|
|
||||||
- 將 `TAURI_PRIVATE_KEY` 添加到環境變數,其中包含私鑰的路徑。
|
|
||||||
- 將 `TAURI_KEY_PASSWORD` 添加到環境變數,其中包含私鑰的密碼。
|
|
||||||
- `yarn build`
|
|
||||||
|
|
||||||
更新將生成在 `src-tauri/target/(release|debug)/msi/Cultivation_X.X.X_x64_xx-XX.msi.zip`
|
|
||||||
|
|
||||||
# 啟動器主題
|
|
||||||
|
|
||||||
完整的主題參考可以[在這裏找到!](/THEMES.md)
|
|
||||||
|
|
||||||
# 畫面
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
## 成員
|
|
||||||
|
|
||||||
- [SpikeHD](https://github.com/SpikeHD): For originally creating **GrassClipper** and creating the amazing UI of Cultivation.
|
|
||||||
- [KingRainbow44](https://github.com/KingRainbow44): For building a proxy daemon from scratch and integrating it with Cultivation.
|
|
||||||
- [Benj](https://github.com/4Benj): For assistance in client patching.
|
|
||||||
- [lilmayofuksu](https://github.com/lilmayofuksu): For assistance in client patching.
|
|
||||||
- [Tauri](https://tauri.app): For providing an amazing, efficient, and simple desktop application framework/library.
|
|
||||||
47
THEMES.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
1. Download your favorite theme! (You can find some in the `#themes` channel on Discord)
|
1. Download your favorite theme! (You can find some in the `#themes` channel on Discord)
|
||||||
2. Place the unzipped theme folder inside of `%appdata%/cultivation/themes` (The path should look something like this: `cultivation/themes/theme_name/index.json`)
|
2. Place the unzipped theme folder inside of `%appdata%/cultivation/themes` (The path should look something like this: `cultivation/themes/theme_name/index.json`)
|
||||||
3. Enable within Cultivation!
|
4. Enable within Cultivation!
|
||||||
|
|
||||||
# Creating your own theme
|
# Creating your own theme
|
||||||
|
|
||||||
@@ -16,16 +16,16 @@ You will need CSS and JS experience if you want to do anything cool.
|
|||||||
|
|
||||||
`index.json` is where you tell Cultivation which files and images to include. It supports the following properties:
|
`index.json` is where you tell Cultivation which files and images to include. It supports the following properties:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| :--- | :--- |
|
||||||
| `name` | The name of the theme. |
|
| `name` | The name of the theme. |
|
||||||
| `version` | Not shown anywhere, the version of the theme. |
|
| `version` | Not shown anywhere, the version of the theme. |
|
||||||
| `description` | Not shown anywhere, the description of the theme. |
|
| `description` | Not shown anywhere, the description of the theme. |
|
||||||
| `includes` | The files and folders to include. |
|
| `includes` | The files and folders to include. |
|
||||||
| `includes.css` | Array of CSS files to include. Example: `css: ["index.css"]` |
|
| `includes.css` | Array of CSS files to include. Example: `css: ["index.css"]` |
|
||||||
| `includes.js` | Array of JS files to includes. Example `js: ["index.js"]` |
|
| `includes.js` | Array of JS files to includes. Example `js: ["index.js"]` |
|
||||||
| `customBackgroundURL` | A custom image URL to set as the background. Backgrounds that users set in their config supercede this. Example: `"https://website.com/image.png"` |
|
| `customBackgroundURL` | A custom image URL to set as the background. Backgrounds that users set in their config supercede this. Example: `"https://website.com/image.png"` |
|
||||||
| `customBackgroundFile` | Path to a custom background image file. Backgrounds that users set in their config supercede this. Example: `"/image.png"` |
|
| `customBackgroundFile` | Path to a custom background image file. Backgrounds that users set in their config supercede this. Example: `"/image.png"` |
|
||||||
|
|
||||||
A full, complete `index.json` will look something like this:
|
A full, complete `index.json` will look something like this:
|
||||||
|
|
||||||
@@ -55,17 +55,15 @@ Below are some small examples of what you can do:
|
|||||||
```css
|
```css
|
||||||
/* Change the font */
|
/* Change the font */
|
||||||
body {
|
body {
|
||||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif !important;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* Remove the news section */
|
/* Remove the news section */
|
||||||
.NewsSection {
|
.NewsSection {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* Change the right bar width */
|
/* Change the right bar width */
|
||||||
.RightBar {
|
.RightBar {
|
||||||
@@ -74,7 +72,6 @@ body {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## How can I change XYZ element?
|
## How can I change XYZ element?
|
||||||
|
|
||||||
Every element is documented and describe [here](/docs/elementIds.md). Every\* single DOM element is assigned an ID to allow for easy and hyper-specific editing.
|
Every element is documented and describe [here](/docs/elementIds.md). Every\* single DOM element is assigned an ID to allow for easy and hyper-specific editing.
|
||||||
|
|
||||||
## Writing your JS
|
## Writing your JS
|
||||||
@@ -86,26 +83,24 @@ Below are some examples of what you can do:
|
|||||||
```js
|
```js
|
||||||
/* Change the version number every 500ms */
|
/* Change the version number every 500ms */
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
document.getElementById('version').innerHTML = 'v' + Math.floor(Math.random() * 100)
|
document.getElementById("version").innerHTML = "v" + Math.floor(Math.random() * 100);
|
||||||
}, 500)
|
}, 500);
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/* Load a custom font */
|
/* Load a custom font */
|
||||||
const head = document.head
|
const head = document.head
|
||||||
const link = document.createElement('link')
|
const link = document.createElement("link")
|
||||||
|
|
||||||
link.href = 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap'
|
link.href = "https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap"
|
||||||
link.rel = 'stylesheet'
|
link.rel = "stylesheet"
|
||||||
link.type = 'text/css'
|
link.type = "text/css"
|
||||||
|
|
||||||
head.appendChild(link)
|
head.appendChild(link)
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/* Create a new button that does nothing */
|
/* Create a new button that does nothing */
|
||||||
const newButton = document.createElement('button')
|
const newButton = document.createElement("button");
|
||||||
newButton.innerHTML = 'New Button'
|
newButton.innerHTML = "New Button";
|
||||||
|
|
||||||
document.body.appendChild(newButton)
|
document.body.appendChild(newButton);
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,138 +1,133 @@
|
|||||||
# Documentation of Element ID's and Classes for custom theming
|
# Documentation of Element ID's and Classes for custom theming
|
||||||
|
|
||||||
## IDs
|
## IDs
|
||||||
|
|
||||||
This does not include commonly used components (buttons, divider lines, commit author and message, etc...) for accessing and modifying those elements, please check `Classes` section bellow.
|
This does not include commonly used components (buttons, divider lines, commit author and message, etc...) for accessing and modifying those elements, please check `Classes` section bellow.
|
||||||
|
|
||||||
| #ID | Description |
|
| #ID | Description |
|
||||||
| ------------------------------------ | --------------------------------------------------------------- |
|
|----------------------------------------|-----------------------------------------------------------------|
|
||||||
| `#miniDialogContainer` | Main container of MiniDialog |
|
| `#miniDialogContainer` | Main container of MiniDialog |
|
||||||
| `#miniDialogContainerTop` | Affects only top section of MiniDialog |
|
| `#miniDialogContainerTop` | Affects only top section of MiniDialog |
|
||||||
| `#miniDialogButtonClose` | Close button (SVG) of MiniDialog |
|
| `#miniDialogButtonClose` | Close button (SVG) of MiniDialog |
|
||||||
| `#miniDialogContent` | MiniDialog content |
|
| `#miniDialogContent` | MiniDialog content |
|
||||||
| `#rightBarContainer` | Main container of RightBar |
|
| `#rightBarContainer` | Main container of RightBar |
|
||||||
| `#rightBarContent` | RightBar content |
|
| `#rightBarContent` | RightBar content |
|
||||||
| `#rightBarButtonDiscord` | Discord button on the RightBar |
|
| `#rightBarButtonDiscord` | Discord button on the RightBar |
|
||||||
| `#rightBarButtonGithub` | Github button on the RightBar |
|
| `#rightBarButtonGithub` | Github button on the RightBar |
|
||||||
| `#playButton` | Main container for whole launch buttons section |
|
| `#playButton` | Main container for whole launch buttons section |
|
||||||
| `#serverControls` | Container of "play on grasscutter" checkbox |
|
| `#serverControls` | Container of "play on grasscutter" checkbox |
|
||||||
| `#enableGC` | "play on grasscutter" checkbox |
|
| `#enableGC` | "play on grasscutter" checkbox |
|
||||||
| `#ip` | Server ip input if play on grasscutter is enabled |
|
| `#ip` | Server ip input if play on grasscutter is enabled |
|
||||||
| `#port` | Server port input if play on grasscutter is enabled |
|
| `#port` | Server port input if play on grasscutter is enabled |
|
||||||
| `#httpsEnable` | "Enable https" checkbox if play on grasscutter is enabled |
|
| `#httpsEnable` | "Enable https" checkbox if play on grasscutter is enabled |
|
||||||
| `#officialPlay` | Launch button |
|
| `#officialPlay` | Launch button |
|
||||||
| `#serverLaunch` | Launch server button |
|
| `#serverLaunch` | Launch server button |
|
||||||
| `#serverlaunchIcon` | Icon (SVG) of server launch button |
|
| `#serverlaunchIcon` | Icon (SVG) of server launch button |
|
||||||
| `#serverConfigContainer` | Main container of server configuration section |
|
| `#serverConfigContainer` | Main container of server configuration section |
|
||||||
| `#serverLaunchContainer` | Main container of launch buttons (includes launch server) |
|
| `#serverLaunchContainer` | Main container of launch buttons (includes launch server) |
|
||||||
| `#topBarContainer` | Main container of launcher TopBar (minimize, exit, settings...) |
|
| `#topBarContainer` | Main container of launcher TopBar (minimize, exit, settings...) |
|
||||||
| `#title` | Title of the TopBar |
|
| `#title` | Title of the TopBar |
|
||||||
| `#version` | Version of the launcher in TopBar |
|
| `#version` | Version of the launcher in TopBar |
|
||||||
| `#topBarButtonContainer` | Container of launcher TopBar buttons only |
|
| `#topBarButtonContainer` | Container of launcher TopBar buttons only |
|
||||||
| `#closeBtn` | Exit launcher button |
|
| `#closeBtn` | Exit launcher button |
|
||||||
| `#minBtn` | Minimize launcher button |
|
| `#minBtn` | Minimize launcher button |
|
||||||
| `#settingsBtn` | Settings button |
|
| `#settingsBtn` | Settings button |
|
||||||
| `#downloadsBtn` | Downloads button (grasscutter resources, grasscutter...) |
|
| `#downloadsBtn` | Downloads button (grasscutter resources, grasscutter...) |
|
||||||
| `#newsContainer` | Main container of the news section |
|
| `#newsContainer` | Main container of the news section |
|
||||||
| `#newsTabsContainer` | Container for news tabs |
|
| `#newsTabsContainer` | Container for news tabs |
|
||||||
| `#commits` | News tabs container commits button |
|
| `#commits` | News tabs container commits button |
|
||||||
| `#latest_version` | News tabs for latest version button |
|
| `#latest_version` | News tabs for latest version button |
|
||||||
| `#newsContent` | Content section of news container |
|
| `#newsContent` | Content section of news container |
|
||||||
| `#newsCommitsTable` | Commits table of news section |
|
| `#newsCommitsTable` | Commits table of news section |
|
||||||
| `#downloadMenuContainerGCStable` | Grasscutter stable update container |
|
| `#downloadMenuContainerGCStable` | Grasscutter stable update container |
|
||||||
| `#downloadMenuLabelGCStable` | Label for stable update button |
|
| `#downloadMenuLabelGCStable` | Label for stable update button |
|
||||||
| `#downloadMenuButtonGCStable` | Button container for stable update button |
|
| `#downloadMenuButtonGCStable` | Button container for stable update button |
|
||||||
| `#grasscutterStableBtn` | "Update grasscutter stable" button |
|
| `#grasscutterStableBtn` | "Update grasscutter stable" button |
|
||||||
| `#downloadMenuContainerGCDev` | Grasscutter development update container |
|
| `#downloadMenuContainerGCDev` | Grasscutter development update container |
|
||||||
| `#downloadMenuLabelGCDev` | Label for latest update button |
|
| `#downloadMenuLabelGCDev` | Label for latest update button |
|
||||||
| `#downloadMenuButtonGCDev` | Button container for latest update button |
|
| `#downloadMenuButtonGCDev` | Button container for latest update button |
|
||||||
| `grasscutterLatestBtn` | "Update grasscutter latest" button |
|
| `grasscutterLatestBtn` | "Update grasscutter latest" button |
|
||||||
| `#downloadMenuContainerGCStableData` | Grasscutter stable data update container |
|
| `#downloadMenuContainerGCStableData` | Grasscutter stable data update container |
|
||||||
| `#downloadMenuLabelGCStableData` | Label for stable data update |
|
| `#downloadMenuLabelGCStableData` | Label for stable data update |
|
||||||
| `#downloadMenuButtonGCStableData` | Button container for stable data update button |
|
| `#downloadMenuButtonGCStableData` | Button container for stable data update button |
|
||||||
| `#grasscutterStableRepo` | "Update grasscutter stable data" button |
|
| `#grasscutterStableRepo` | "Update grasscutter stable data" button |
|
||||||
| `#downloadMenuContainerGCDevData` | Grasscutter latest data update container |
|
| `#downloadMenuContainerGCDevData` | Grasscutter latest data update container |
|
||||||
| `#downloadMenuLabelGCDevData` | Label for latest data update |
|
| `#downloadMenuLabelGCDevData` | Label for latest data update |
|
||||||
| `#downloadMenuButtonGCDevData` | Button container for latest data update button |
|
| `#downloadMenuButtonGCDevData` | Button container for latest data update button |
|
||||||
| `#grasscutterDevRepo` | "Update grasscutter latest data" button |
|
| `#grasscutterDevRepo` | "Update grasscutter latest data" button |
|
||||||
| `#downloadMenuContainerResources` | Container for grasscutter resources download |
|
| `#downloadMenuContainerResources` | Container for grasscutter resources download |
|
||||||
| `#downloadMenuLabelResources` | label for resources download |
|
| `#downloadMenuLabelResources` | label for resources download |
|
||||||
| `#downloadMenuButtonResources` | Button container for resources download button |
|
| `#downloadMenuButtonResources` | Button container for resources download button |
|
||||||
| `#resourcesBtn` | "Download grasscutter resources" button |
|
| `#resourcesBtn` | "Download grasscutter resources" button |
|
||||||
| `#menuContainer` | Generic Popup modal like menu container |
|
| `#menuContainer` | Generic Popup modal like menu container |
|
||||||
| `#menuContainerTop` | Top section of menu container |
|
| `#menuContainerTop` | Top section of menu container |
|
||||||
| `#menuHeading` | Menu title |
|
| `#menuHeading` | Menu title |
|
||||||
| `#menuButtonCloseContainer` | Container for menu close button |
|
| `#menuButtonCloseContainer` | Container for menu close button |
|
||||||
| `#menuButtonCloseIcon` | Menu close icon (SVG) |
|
| `#menuButtonCloseIcon` | Menu close icon (SVG) |
|
||||||
| `#menuContent` | Content section of the menu |
|
| `#menuContent` | Content section of the menu |
|
||||||
| `#menuOptionsContainerGameExec` | Container for game executable option section |
|
| `#menuOptionsContainerGameExec` | Container for game executable option section |
|
||||||
| `#menuOptionsLabelGameExec` | Label for game executable option |
|
| `#menuOptionsLabelGameExec` | Label for game executable option |
|
||||||
| `#menuOptionsDirGameExec` | Set game executable file browser |
|
| `#menuOptionsDirGameExec` | Set game executable file browser |
|
||||||
| `#menuOptionsContainerGCJar` | Container for grasscutter jar option |
|
| `#menuOptionsContainerGCJar` | Container for grasscutter jar option |
|
||||||
| `#menuOptionsLabelGCJar` | Label for grasscutter jar option |
|
| `#menuOptionsLabelGCJar` | Label for grasscutter jar option |
|
||||||
| `#menuOptionsDirGCJar` | Set grasscutter jar file browser |
|
| `#menuOptionsDirGCJar` | Set grasscutter jar file browser |
|
||||||
| `#menuOptionsContainerToggleEnc` | Container for toggle encryption option |
|
| `#menuOptionsContainerToggleEnc` | Container for toggle encryption option |
|
||||||
| `#menuOptionsLabelToggleEnc` | Label for toggle encryption option |
|
| `#menuOptionsLabelToggleEnc` | Label for toggle encryption option |
|
||||||
| `#menuOptionsButtonToggleEnc` | Toggle encryption button container |
|
| `#menuOptionsButtonToggleEnc` | Toggle encryption button container |
|
||||||
| `#toggleEnc` | Toggle encryption button |
|
| `#toggleEnc` | Toggle encryption button |
|
||||||
| `#menuOptionsContainerGCWGame` | Container for "grasscutter with game" option |
|
| `#menuOptionsContainerGCWGame` | Container for "grasscutter with game" option |
|
||||||
| `#menuOptionsLabelGCWDame` | Label for "grasscutter with game" option |
|
| `#menuOptionsLabelGCWDame` | Label for "grasscutter with game" option |
|
||||||
| `#menuOptionsCheckboxGCWGame` | Container for "grasscutter with game" option checkbox |
|
| `#menuOptionsCheckboxGCWGame` | Container for "grasscutter with game" option checkbox |
|
||||||
| `#gcWithGame` | Grasscutter with game checkbox |
|
| `#gcWithGame` | Grasscutter with game checkbox |
|
||||||
| `#menuOptionsContainerThemes` | Container for themes section |
|
| `#menuOptionsContainerThemes` | Container for themes section |
|
||||||
| `#menuOptionsLabelThemes` | Label for set themes option |
|
| `#menuOptionsLabelThemes` | Label for set themes option |
|
||||||
| `#menuOptionsSelectThemes` | Container for themes select menu |
|
| `#menuOptionsSelectThemes` | Container for themes select menu |
|
||||||
| `#menuOptionsSelectMenuThemes` | Set theme select menu |
|
| `#menuOptionsSelectMenuThemes` | Set theme select menu |
|
||||||
| `#menuOptionsContainerJavaPath` | Container for Java Path option |
|
| `#menuOptionsContainerJavaPath` | Container for Java Path option |
|
||||||
| `#menuOptionsLabelJavaPath` | Label for Java path option |
|
| `#menuOptionsLabelJavaPath` | Label for Java path option |
|
||||||
| `#menuOptionsDirJavaPath` | Container for java path file browser |
|
| `#menuOptionsDirJavaPath` | Container for java path file browser |
|
||||||
| `#menuOptionsContainerBG` | Container for Background option |
|
| `#menuOptionsContainerBG` | Container for Background option |
|
||||||
| `#menuOptionsLabelBG` | Label for background option |
|
| `#menuOptionsLabelBG` | Label for background option |
|
||||||
| `#menuOptionsDirBG` | Container for background url/local path option |
|
| `#menuOptionsDirBG` | Container for background url/local path option |
|
||||||
| `#menuOptionsContainerUseThemeBG` | Container for forcing theme background option |
|
| `#menuOptionsContainerLang` | Container for language change option |
|
||||||
| `#menuOptionsLabelUseThemeBG` | Label for forcing theme background option |
|
| `#menuOptionsLabelLang` | Label for language change option |
|
||||||
| `#menuOptionsUseThemeBG` | Toggle forcing theme background button container |
|
| `#menuOptionsSelectLang` | Container for language change select menu |
|
||||||
| `#menuOptionsContainerLang` | Container for language change option |
|
| `#menuOptionsSelectMenuLang` | Language select menu |
|
||||||
| `#menuOptionsLabelLang` | Label for language change option |
|
| `#DownloadProgress` | Download progress container |
|
||||||
| `#menuOptionsSelectLang` | Container for language change select menu |
|
| `#bottomSectionContainer` | Bottom section container |
|
||||||
| `#menuOptionsSelectMenuLang` | Language select menu |
|
| `#miniDownloadContainer` | Container for mini download |
|
||||||
| `#DownloadProgress` | Download progress container |
|
|
||||||
| `#bottomSectionContainer` | Bottom section container |
|
|
||||||
| `#miniDownloadContainer` | Container for mini download |
|
|
||||||
|
|
||||||
## Classes
|
## Classes
|
||||||
|
|
||||||
This is not full list of all classes, rather its list of classes for commonly used components that can not be accessed using element id system.
|
This is not full list of all classes, rather its list of classes for commonly used components that can not be accessed using element id system.
|
||||||
|
|
||||||
| .Class | Description |
|
| .Class | Description |
|
||||||
| ------------------------- | ------------------------------------------------------- |
|
|-----------------------------|---------------------------------------------------------|
|
||||||
| `.BigButton` | Class for all buttons |
|
| `.BigButton` | Class for all buttons |
|
||||||
| `.BigButtonText` | Text inside a button |
|
| `.BigButtonText` | Text inside a button | |
|
||||||
| `.Checkbox` | Checkbox container |
|
| `.Checkbox` | Checkbox container |
|
||||||
| `.CheckboxDisplay` | Content of checkbox |
|
| `.CheckboxDisplay` | Content of checkbox |
|
||||||
| `.DirInput` | Container for DirInput |
|
| `.DirInput` | Container for DirInput |
|
||||||
| `.FileSelectIcon` | Icon of DirInput |
|
| `.FileSelectIcon` | Icon of DirInput |
|
||||||
| `.DownloadList` | List of all downloads |
|
| `.DownloadList` | List of all downloads |
|
||||||
| `.DownloadSection` | Container for each download |
|
| `.DownloadSection` | Container for each download |
|
||||||
| `.DownloadTitle` | Contains file download path and current status |
|
| `.DownloadTitle` | Contains file download path and current status |
|
||||||
| `.DownloadPath` | Path of a download |
|
| `.DownloadPath` | Path of a download |
|
||||||
| `.DownloadStatus` | Status of a download |
|
| `.DownloadStatus` | Status of a download |
|
||||||
| `.DownloadSectionInner` | Contains progressbar of the download section |
|
| `.DownloadSectionInner` | Contains progressbar of the download section |
|
||||||
| `.HelpSection` | Container for help "?" circle button |
|
| `.HelpSection` | Container for help "?" circle button |
|
||||||
| `.HelpButton` | HelpButton itself |
|
| `.HelpButton` | HelpButton itself |
|
||||||
| `.HelpContents` | Content of help button once expanded |
|
| `.HelpContents` | Content of help button once expanded |
|
||||||
| `.MainProgressBarWrapper` | Container for MainProgressBar |
|
| `.MainProgressBarWrapper` | Container for MainProgressBar |
|
||||||
| `.ProgressBar` | ProgressBar (creativity left the brain) |
|
| `.ProgressBar` | ProgressBar (creativity left the brain) |
|
||||||
| `.InnerProgress` | ProgressBar percentage |
|
| `.InnerProgress` | ProgressBar percentage |
|
||||||
| `.MainProgressText` | Text for MainProgressBar |
|
| `.MainProgressText` | Text for MainProgressBar |
|
||||||
| `.ProgressBarWrapper` | Container for ProgressBar |
|
| `.ProgressBarWrapper` | Container for ProgressBar |
|
||||||
| `.DownloadControls` | DownloadControls of ProgressBar |
|
| `.DownloadControls` | DownloadControls of ProgressBar |
|
||||||
| `.downloadStop` | Container for download stop icon (SVG) |
|
| `.downloadStop` | Container for download stop icon (SVG) |
|
||||||
| `.ProgressText` | Text of the ProgressBar display current download status |
|
| `.ProgressText` | Text of the ProgressBar display current download status |
|
||||||
| `.TextInputWrapper` | Container for TextInput |
|
| `.TextInputWrapper` | Container for TextInput |
|
||||||
| `.TextClear` | Container for clear input content button |
|
| `.TextClear` | Container for clear input content button |
|
||||||
| `.TextInputClear` | TextInput clear button icon (SVG) |
|
| `.TextInputClear` | TextInput clear button icon (SVG) |
|
||||||
| `.Divider` | Container for line dividers |
|
| `.Divider` | Container for line dividers |
|
||||||
| `.DividerLine` | Divider line itself |
|
| `.DividerLine` | Divider line itself |
|
||||||
| `.CommitAuthor` | Author of a commit |
|
| `.CommitAuthor` | Author of a commit |
|
||||||
| `.CommitMessage` | Message of a commit |
|
| `.CommitMessage` | Message of a commit |
|
||||||
@@ -1,19 +1,15 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
A guide dedicated for trying to troubleshoot Cultivation.
|
A guide dedicated for trying to troubleshoot Cultivation.
|
||||||
|
|
||||||
## The launcher doesn't appear to open.
|
## The launcher doesn't appear to open.
|
||||||
|
|
||||||
Try running the launcher with **administrative privileges**.\
|
Try running the launcher with **administrative privileges**.\
|
||||||
If this fixes your issue, you can force enable it in the **Compatability**\
|
If this fixes your issue, you can force enable it in the **Compatability**\
|
||||||
tab for the launcher's executable.
|
tab for the launcher's executable.
|
||||||
|
|
||||||
## Unable to play on `localhost`.
|
## Unable to play on `localhost`.
|
||||||
|
|
||||||
Make sure your server is running with **encryption disabled** and `useInRouting` to **false**.\
|
Make sure your server is running with **encryption disabled** and `useInRouting` to **false**.\
|
||||||
Additionally, make sure Cultivation **is set to not use HTTPS**.
|
Additionally, make sure Cultivation **is set to not use HTTPS**.
|
||||||
|
|
||||||
## "I can't do anything requiring the internet after closing Cultivation!"
|
## "I can't do anything requiring the internet after closing Cultivation!"
|
||||||
|
|
||||||
You probably didn't close Cultivation properly.\
|
You probably didn't close Cultivation properly.\
|
||||||
Go to your _Windows Settings_, then _Network_, then _Proxy_, then disable it.
|
Go to your *Windows Settings*, then *Network*, then *Proxy*, then disable it.
|
||||||
20
package.json
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "cultivation",
|
"name": "cultivation",
|
||||||
"version": "1.0.26",
|
"version": "1.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^1.0.0-rc.5",
|
"@tauri-apps/api": "^1.0.0-rc.5",
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react": "^13.0.0",
|
"@testing-library/react": "^13.0.0",
|
||||||
"@testing-library/user-event": "^14.2.6",
|
"@testing-library/user-event": "^13.2.1",
|
||||||
"@types/jest": "^28.1.6",
|
"@types/jest": "^27.0.1",
|
||||||
"@types/node": "^18.0.6",
|
"@types/node": "^16.7.13",
|
||||||
"@types/react": "^18.0.0",
|
"@types/react": "^18.0.0",
|
||||||
"@types/react-dom": "^18.0.0",
|
"@types/react-dom": "^18.0.0",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
@@ -20,18 +20,14 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env BROWSER=none react-scripts start",
|
"start": "cross-env BROWSER=none react-scripts start",
|
||||||
"postbuild:windows": "xcopy /E /H /C /I /Y \".\\src-tauri\\lang\" \".\\src-tauri\\target\\release\\lang\"",
|
"postbuild:windows": "xcopy /E /H /C /I /Y \".\\src-tauri\\lang\" \".\\src-tauri\\target\\release\\lang\"",
|
||||||
"postbuild:linux": "cp -r \"./src-tauri/lang\" \"./lang\"",
|
"postbuild:linux": "cp -r \".\\src-tauri\\lang\" \".\\lang\"",
|
||||||
"build:windows": "yarn tauri build",
|
"build:windows": "yarn tauri build",
|
||||||
"build:linux": "yarn tauri build",
|
"build:linux": "yarn tauri build",
|
||||||
"build": "react-scripts build && run-script-os",
|
"build": "react-scripts build && run-script-os",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"start:dev": "tauri dev -- -- --no-admin",
|
"start:dev": "tauri dev"
|
||||||
"format": "cargo fmt --manifest-path ./src-tauri/Cargo.toml --all && yarn prettier --write --cache --loglevel warn .",
|
|
||||||
"lint": "cargo clippy --manifest-path ./src-tauri/Cargo.toml --no-default-features && yarn tsc --noEmit && yarn eslint src",
|
|
||||||
"lint:fix": "cargo clippy --manifest-path ./src-tauri/Cargo.toml --no-default-features --fix --allow-dirty && yarn tsc --noEmit && yarn eslint --fix src",
|
|
||||||
"prepare": "husky install"
|
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
@@ -57,11 +53,7 @@
|
|||||||
"@typescript-eslint/parser": "^5.22.0",
|
"@typescript-eslint/parser": "^5.22.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.15.0",
|
"eslint": "^8.15.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
|
||||||
"eslint-plugin-react": "^7.29.4",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"husky": "^8.0.0",
|
|
||||||
"lint-staged": "^13.0.3",
|
|
||||||
"prettier": "^2.7.1",
|
|
||||||
"run-script-os": "^1.1.6"
|
"run-script-os": "^1.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
@@ -5,11 +5,16 @@
|
|||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="Tauri-powered anime game launcher" />
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Tauri-powered anime game launcher"
|
||||||
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<title>Cultivation</title>
|
<title>Cultivation</title>
|
||||||
|
<script src="%PUBLIC_URL%/theme-engine.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
14
public/theme-engine.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Passes a message through to the React backend.
|
||||||
|
* @param type The message type.
|
||||||
|
* @param data The message data.
|
||||||
|
*/
|
||||||
|
function passthrough(type, data) {
|
||||||
|
document.dispatchEvent(new CustomEvent('domMessage', {
|
||||||
|
type, msg: data
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
function setConfigValue(key, value) {
|
||||||
|
passthrough('updateConfig', {setting: key, value})
|
||||||
|
}
|
||||||
2486
src-tauri/Cargo.lock
generated
@@ -1,9 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cultivation"
|
name = "cultivation"
|
||||||
version = "1.2.0"
|
version = "1.0.1"
|
||||||
description = "A custom launcher for anime game."
|
description = "A custom launcher for anime game."
|
||||||
authors = ["KingRainbow44", "SpikeHD"]
|
authors = ["KingRainbow44", "SpikeHD"]
|
||||||
license = ""
|
license = "Apache-2.0"
|
||||||
repository = "https://github.com/Grasscutters/Cultivation.git"
|
repository = "https://github.com/Grasscutters/Cultivation.git"
|
||||||
default-run = "cultivation"
|
default-run = "cultivation"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -13,70 +13,47 @@ rust-version = "1.57"
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "1.0.0-rc.8", features = [] }
|
tauri-build = { version = "1.0.0-rc.8", features = [] }
|
||||||
cc = "1.0"
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
|
||||||
registry = "1.2.1"
|
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
|
||||||
sudo = "0.6.0"
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
|
||||||
anyhow = "1.0.58"
|
|
||||||
os_type = "2.6"
|
|
||||||
term-detect = "0.1.7"
|
|
||||||
which = "4.4"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tauri = { version = "1.0.9", features = ["api-all"] }
|
tauri = { version = "1.0.0-rc.9", features = ["api-all", "updater"] }
|
||||||
|
|
||||||
# Arg parsing
|
|
||||||
args = "2.0"
|
|
||||||
getopts = "0.2"
|
|
||||||
|
|
||||||
# Access system process info.
|
# Access system process info.
|
||||||
sysinfo = "0.28.4"
|
sysinfo = "0.23.12"
|
||||||
|
|
||||||
# ZIP-archive library.
|
# ZIP-archive library.
|
||||||
zip-extract = "0.1.1"
|
zip-extract = "0.1.1"
|
||||||
unrar = "0.4.4"
|
|
||||||
zip = "0.6.2"
|
zip = "0.6.2"
|
||||||
sevenz-rust = "0.2.9"
|
|
||||||
|
# For creating a "global" downloads list.
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
# Access to the Windows Registry.
|
||||||
|
registry = "1.2.1"
|
||||||
|
|
||||||
# Program opener.
|
# Program opener.
|
||||||
open = "3.0.2"
|
open = "2.1.2"
|
||||||
|
duct = "0.13.5"
|
||||||
# Services
|
|
||||||
windows-service = "0.6.0"
|
|
||||||
|
|
||||||
# Serialization.
|
# Serialization.
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
||||||
|
# System process elevation.
|
||||||
|
is_elevated = "0.1.2"
|
||||||
|
runas = "0.2.1"
|
||||||
|
|
||||||
# Dependencies for the HTTP(S) proxy.
|
# Dependencies for the HTTP(S) proxy.
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
hudsucker = "0.19.2"
|
hudsucker = "0.17.2"
|
||||||
tracing = "0.1.21"
|
tracing = "0.1.21"
|
||||||
tokio-rustls = "0.23.0"
|
tokio-rustls = "0.23.0"
|
||||||
tokio = { version = "1.20.4", features = ["signal"] }
|
tokio-tungstenite = "0.17.0"
|
||||||
|
tokio = { version = "1.18.2", features = ["signal"] }
|
||||||
rustls-pemfile = "1.0.0"
|
rustls-pemfile = "1.0.0"
|
||||||
reqwest = { version = "0.11.3", features = ["stream"] }
|
reqwest = { version = "0.11.3", features = ["stream"] }
|
||||||
futures-util = "0.3.14"
|
futures-util = "0.3.14"
|
||||||
rcgen = { version = "0.9", features = ["x509-parser"] }
|
rcgen = { version = "0.9", features = ["x509-parser"] }
|
||||||
|
|
||||||
# metadata stuff
|
|
||||||
regex = "1"
|
|
||||||
|
|
||||||
# other
|
|
||||||
rust-ini = "0.18.0"
|
|
||||||
ctrlc = "3.2.3"
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies.anime-launcher-sdk]
|
|
||||||
git = "https://github.com/an-anime-team/anime-launcher-sdk.git"
|
|
||||||
tag = "1.11.1"
|
|
||||||
default-features = false
|
|
||||||
features = ["all", "genshin"]
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 74 KiB |
@@ -1 +0,0 @@
|
|||||||
<RSAKeyValue><Modulus>AMW28dptX3h8q0O4z/vJrQxf6cmC6yVilgHRL98GazrYzmc3ixj87JpHIJ3IKEYV+HU/tYrUjEfY/ZtPzsLB9lKBelN9i8QjkFkA9QDICGYwJCXibxU67Z/HzENe9NQpG2i01SI0TJU8PJDV7zQPwPVGraIg5ouExRupq8UymaSHEyJ7zxKZCtgO0LKdROLJBSvI5srMu7kYTGmB7T07Ab8T9M595YSgd1vh06qZ3nsF1h4wg3y+zW28vdY28+RCj2V1i7oVyL0dQruLYq7qK8FycZl2j9R0GaJ8rRAjVP1Dsz+hjS3atHhQxOG9OFo6d/euedRvfWIhT9p6h1SeTjE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<RSAKeyValue>
|
|
||||||
<Exponent>AQAB</Exponent>
|
|
||||||
<Modulus>yytg/H9lz7Lm0XcA8LMqIyXPVNApYTcSepT4VDLB4qqqFC3s
|
|
||||||
/Huv8vN7zA/P4uoREIu8KMenADFk7uwrZSxoMWwJgn6A7sbAt1cqAaUXB
|
|
||||||
9J4NzhL0x3AFTiHEQbw86hRvm2VGkbA5sWnr0NZw8SGBBY+EODwNIt51G
|
|
||||||
dBA7eoUQU=</Modulus>
|
|
||||||
</RSAKeyValue>
|
|
||||||
@@ -8,52 +8,27 @@
|
|||||||
"ip_placeholder": "IP 地址...",
|
"ip_placeholder": "IP 地址...",
|
||||||
"port_placeholder": "端口...",
|
"port_placeholder": "端口...",
|
||||||
"files_downloading": "文件下载中:",
|
"files_downloading": "文件下载中:",
|
||||||
"files_extracting": "文件解压中:",
|
"files_extracting": "文件解压中:"
|
||||||
"game_path_notify": "未找到游戏路径,请记得在设置中进行设置"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"enabled": "已启用",
|
"game_exec": "选择游戏可执行文件",
|
||||||
"disabled": "已禁用",
|
|
||||||
"game_path": "选择游戏安装路径",
|
|
||||||
"game_command": "启动游戏的命令行",
|
|
||||||
"game_executable": "选择游戏可执行文件",
|
|
||||||
"recover_rsa": "紧急情况下删除补丁文件",
|
|
||||||
"grasscutter_jar": "选择 Grasscutter JAR 文件",
|
"grasscutter_jar": "选择 Grasscutter JAR 文件",
|
||||||
"toggle_encryption": "启用加密",
|
"java_path": "设置自定义 Java 路径",
|
||||||
"install_certificate": "安装代理证书",
|
|
||||||
"java_path": "选择自定义 Java 路径",
|
|
||||||
"grasscutter_with_game": "随游戏自动启动 Grasscutter",
|
"grasscutter_with_game": "随游戏自动启动 Grasscutter",
|
||||||
"language": "选择语言",
|
"language": "语言",
|
||||||
"background": "设置自定义背景(链接或文件)",
|
"background": "设置自定义背景(链接或文件)",
|
||||||
"use_theme_background": "使用所选主题提供的背景",
|
"theme": "设置主题"
|
||||||
"theme": "设置主题",
|
|
||||||
"patch_rsa": "自动修改RSA",
|
|
||||||
"use_proxy": "使用内置代理",
|
|
||||||
"wipe_login": "清除登录缓存",
|
|
||||||
"horny_mode": "Horny 模式",
|
|
||||||
"auto_mongodb": "自动启动 MongoDB",
|
|
||||||
"un_elevated": "非提升运行游戏(无管理员)",
|
|
||||||
"redirect_more": "还可以重定向其他MHY游戏",
|
|
||||||
"web_cache": "删除 webCaches 文件夹",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"grasscutter_fullbuild": "下载 Grasscutter 一体化",
|
|
||||||
"grasscutter_fullquest": "下载 Quest 一体化",
|
|
||||||
"grasscutter_stable_data": "下载 Grasscutter 稳定版数据",
|
"grasscutter_stable_data": "下载 Grasscutter 稳定版数据",
|
||||||
"grasscutter_latest_data": "下载 Grasscutter 开发版数据",
|
"grasscutter_latest_data": "下载 Grasscutter 开发版数据",
|
||||||
"grasscutter_stable_data_update": "更新 Grasscutter 稳定版数据",
|
"grasscutter_stable_data_update": "更新 Grasscutter 稳定版数据",
|
||||||
"grasscutter_latest_data_update": "更新 Grasscutter 开发版数据",
|
"grasscutter_latest_data_update": "更新 Grasscutter 开发版数据",
|
||||||
"grasscutter_unstable": "下载 Grasscutter 稳定版",
|
"grasscutter_stable": "下载 Grasscutter 稳定版",
|
||||||
"grasscutter_latest": "下载 Grasscutter 开发版",
|
"grasscutter_latest": "下载 Grasscutter 开发版",
|
||||||
"grasscutter_unstable_update": "更新 Grasscutter 稳定版",
|
"grasscutter_stable_update": "更新 Grasscutter 稳定版",
|
||||||
"grasscutter_latest_update": "更新 Grasscutter 开发版",
|
"grasscutter_latest_update": "更新 Grasscutter 开发版",
|
||||||
"resources": "下载 Grasscutter 资源",
|
"resources": "下载 Grasscutter 资源"
|
||||||
"game": "下载游戏",
|
|
||||||
"aio_header": "多合一下载:",
|
|
||||||
"individual_header": "个别部分下载:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "下载 GIMI 3dmigoto"
|
|
||||||
},
|
},
|
||||||
"download_status": {
|
"download_status": {
|
||||||
"downloading": "下载中",
|
"downloading": "下载中",
|
||||||
@@ -65,36 +40,19 @@
|
|||||||
"components": {
|
"components": {
|
||||||
"select_file": "选择文件或文件夹...",
|
"select_file": "选择文件或文件夹...",
|
||||||
"select_folder": "选择文件夹...",
|
"select_folder": "选择文件夹...",
|
||||||
"download": "下载",
|
"download": "下载"
|
||||||
"delete": "删除",
|
|
||||||
"install": "安装"
|
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"latest_commits": "最近提交",
|
"latest_commits": "最近的PR",
|
||||||
"latest_version": "最新版本"
|
"latest_version": "最新版本"
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"port_help_text": "确保这是 Dispatch 服务器端口,而不是游戏服务器端口。大部分服务器的端口都是 443。",
|
"port_help_text": "确保这是 Dispatch 服务器端口,而不是游戏服务器端口。大部分服务器的端口都是 443。",
|
||||||
"game_help_text": "你不需要另外的游戏备份来使用 Grasscutter。这是给想要降级到 2.6 或没有安装游戏的人使用的。",
|
"game_help_text": "你不需要另外的游戏备份来使用 Grasscutter。这是给想要降级到 2.6 或没有安装游戏的人使用的。",
|
||||||
"gc_stable_jar": "下载当前的 Grasscutter 稳定版,包括 JAR 文件和数据。",
|
"gc_stable_jar": "下载当前的 Grasscutter 稳定版,包括 JAR 文件和数据。",
|
||||||
"gc_fullbuild": "下载完整的 Grasscutter 构建版本,包括存储库、jar 和资源。 已完全设置,不需要从此菜单下载任何其他内容",
|
|
||||||
"gc_dev_jar": "下载最新的 Grasscutter 开发版,包括 JAR 文件和数据。",
|
"gc_dev_jar": "下载最新的 Grasscutter 开发版,包括 JAR 文件和数据。",
|
||||||
"gc_stable_data": "下载当前的 Grasscutter 稳定版数据,不包括 JAR 文件。此选项在更新时有帮助。",
|
"gc_stable_data": "下载当前的 Grasscutter 稳定版数据,不包括 JAR 文件。此选项在更新时有帮助。",
|
||||||
"gc_dev_data": "下载最新的 Grasscutter 开发版数据,不包括 JAR 文件。此选项在更新时有帮助。",
|
"gc_dev_data": "下载最新的 Grasscutter 开发版数据,不包括 JAR 文件。此选项在更新时有帮助。",
|
||||||
"encryption": "此项设置通常应该处于关闭状态。",
|
"resources": "资源文件在运行 Grasscutter 服务器时是必要的。此选项在已经存在资源文件时不可选。"
|
||||||
"resources": "资源文件在运行 Grasscutter 服务器时是必要的。此选项在已经存在资源文件时不可选。",
|
|
||||||
"emergency_rsa": "在出现意外情况时自动将 RSA 恢复到原始版本",
|
|
||||||
"use_proxy": "使用 Cultivation 的内置代理。除非你使用 Fiddler 等软件,否则应启用此项。",
|
|
||||||
"patch_rsa": "自动修改和恢复 RSA 补丁。 除非您玩的是旧版/非官方版本,或者您手动修改了 RSA,否则应该启用此功能。",
|
|
||||||
"add_delay": "在 3dmigoto 加载程序中设置延迟! \n这应该可以解决加载问题,但会在启动游戏时加载 3dmigoto 时增加一点延迟。 \n您现在可以再次使用 3dmigoto 启动。",
|
|
||||||
"migoto": "用于从 GameBanana 导入模型"
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "选择 Akebi 可执行文件",
|
|
||||||
"migoto": "选择 3DMigoto 可执行文件",
|
|
||||||
"reshade": "选择 Reshade 注入器"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,52 +8,30 @@
|
|||||||
"ip_placeholder": "IP地址...",
|
"ip_placeholder": "IP地址...",
|
||||||
"port_placeholder": "通訊埠...",
|
"port_placeholder": "通訊埠...",
|
||||||
"files_downloading": "檔案下載中:",
|
"files_downloading": "檔案下載中:",
|
||||||
"files_extracting": "檔案解壓縮中:",
|
"files_extracting": "檔案解壓縮中:"
|
||||||
"game_path_notify": "找不到遊戲路徑,記得在設置裡設置!"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"enabled": "已啟用",
|
"enabled": "已啟用",
|
||||||
"disabled": "未啟用",
|
"disabled": "未啟用",
|
||||||
"game_path": "選擇遊戲安裝路徑",
|
"game_exec": "選擇遊戲執行檔",
|
||||||
"game_command": "遊戲啟動命令",
|
|
||||||
"game_executable": "選擇遊戲執行檔",
|
|
||||||
"recover_rsa": "緊急恢復RSA",
|
|
||||||
"grasscutter_jar": "選擇伺服器JAR檔案",
|
"grasscutter_jar": "選擇伺服器JAR檔案",
|
||||||
"toggle_encryption": "設定加密",
|
"toggle_encryption": "設定加密",
|
||||||
"install_certificate": "安裝代理憑證",
|
"java_path": "設定自定義Java路徑",
|
||||||
"java_path": "選擇自定義Java路徑",
|
|
||||||
"grasscutter_with_game": "伴隨遊戲一起啟動Grasscutter",
|
"grasscutter_with_game": "伴隨遊戲一起啟動Grasscutter",
|
||||||
"language": "語言",
|
"language": "語言",
|
||||||
"background": "選擇自定義背景(網址或檔案)",
|
"background": "設定自定義背景(網址或檔案)",
|
||||||
"use_theme_background": "使用所選主題提供的背景",
|
"theme": "設定主題"
|
||||||
"theme": "選擇主題",
|
|
||||||
"patch_rsa": "自動修補RSA",
|
|
||||||
"use_proxy": "使用內建代理伺服器",
|
|
||||||
"wipe_login": "擦除登錄緩存",
|
|
||||||
"horny_mode": "Horny模式",
|
|
||||||
"auto_mongodb": "自動啟動 MongoDB",
|
|
||||||
"un_elevated": "在不升高的情况下运行游戏(没有管理员)。",
|
|
||||||
"redirect_more": "同時重定向其他 MHY 遊戲",
|
|
||||||
"web_cache": "刪除 webCaches 文件夾",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"grasscutter_fullbuild": "下載Grasscutter多合一下載",
|
|
||||||
"grasscutter_fullquest": "下载 Quest 一体化",
|
|
||||||
"grasscutter_stable_data": "下載Grasscutter穩定版數據(Data)",
|
"grasscutter_stable_data": "下載Grasscutter穩定版數據(Data)",
|
||||||
"grasscutter_latest_data": "下載Grasscutter開發板數據(Data)",
|
"grasscutter_latest_data": "下載Grasscutter開發板數據(Data)",
|
||||||
"grasscutter_stable_data_update": "更新Grasscutter穩定版數據(Data)",
|
"grasscutter_stable_data_update": "更新Grasscutter穩定版數據(Data)",
|
||||||
"grasscutter_latest_data_update": "更新Grasscutter開發板數據(Data)",
|
"grasscutter_latest_data_update": "更新Grasscutter開發板數據(Data)",
|
||||||
"grasscutter_unstable": "下載Grasscutter穩定版",
|
"grasscutter_stable": "下載Grasscutter穩定版",
|
||||||
"grasscutter_latest": "下載Grasscutter開發板",
|
"grasscutter_latest": "下載Grasscutter開發板",
|
||||||
"grasscutter_unstable_update": "更新Grasscutter穩定版",
|
"grasscutter_stable_update": "更新Grasscutter穩定版",
|
||||||
"grasscutter_latest_update": "更新Grasscutter開發板",
|
"grasscutter_latest_update": "更新Grasscutter開發板",
|
||||||
"resources": "下載Grasscutter資源(Resources)",
|
"resources": "下載Grasscutter資源(Resources)"
|
||||||
"game": "下載遊戲",
|
|
||||||
"aio_header": "多合一下載:",
|
|
||||||
"individual_header": "個別部分下載:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "下載GIMI 3dmigoto"
|
|
||||||
},
|
},
|
||||||
"download_status": {
|
"download_status": {
|
||||||
"downloading": "下載中",
|
"downloading": "下載中",
|
||||||
@@ -65,9 +43,7 @@
|
|||||||
"components": {
|
"components": {
|
||||||
"select_file": "選擇檔案或資料夾...",
|
"select_file": "選擇檔案或資料夾...",
|
||||||
"select_folder": "選擇資料夾...",
|
"select_folder": "選擇資料夾...",
|
||||||
"download": "下載",
|
"download": "下載"
|
||||||
"delete": "刪除",
|
|
||||||
"install": "安裝"
|
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"latest_commits": "最近的PR",
|
"latest_commits": "最近的PR",
|
||||||
@@ -75,26 +51,11 @@
|
|||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"port_help_text": "確保這是Dispatch伺服器端口,不是遊戲伺服器端口。 大部分伺服器的端口都是443。",
|
"port_help_text": "確保這是Dispatch伺服器端口,不是遊戲伺服器端口。 大部分伺服器的端口都是443。",
|
||||||
"game_help_text": "您不需要另外一個遊戲備份來使用Grasscutter。這是給想要降級到2.6或者還沒安裝遊戲的人使用的。",
|
"game_help_text": "你不需要另外一個遊戲備份來使用Grasscutter。這是給想要降級到2.6或者還沒安裝遊戲的人使用的。",
|
||||||
"gc_stable_jar": "下載當前的Grasscutter穩定版本,包括JAR答案還有資料文件。",
|
"gc_stable_jar": "下載當前的Grasscutter穩定版本,包括JAR答案還有資料文件。",
|
||||||
"gc_fullbuild": "下載完整的 Grasscutter 構建版本,包括存儲庫、jar 和資源。 已完全設置,不需要從此菜單下載任何其他內容",
|
|
||||||
"gc_dev_jar": "下載當前的Grasscutter穩定版本資料文件,其中不會附帶JAR文件。這個選項在更新時很有用。",
|
"gc_dev_jar": "下載當前的Grasscutter穩定版本資料文件,其中不會附帶JAR文件。這個選項在更新時很有用。",
|
||||||
"gc_stable_data": "下載當前最新的Grasscutter開發版本資料文件,其中不會附帶JAR文件。這個選項在更新時很有用。",
|
"gc_stable_data": "下載當前最新的Grasscutter開發版本資料文件,其中不會附帶JAR文件。這個選項在更新時很有用。",
|
||||||
"gc_dev_data": "下載當前最新的Grasscutter開發版本的資料文件,其中不會附帶JAR文件。這個選項在更新時很有用。",
|
"gc_dev_data": "下載當前最新的Grasscutter開發版本的資料文件,其中不會附帶JAR文件。這個選項在更新時很有用。",
|
||||||
"encryption": "在正常情況下,此選項應該被關閉。",
|
"resources": "資源文件在架設一個Grasscutter伺服器時是必要的。 這個選項會在你已經有裡面有檔案的資源資料夾時不可選。"
|
||||||
"resources": "資源文件在架設一個Grasscutter伺服器時是必要的。 這個選項會在您已經有裡面有檔案的資源資料夾時不可選。",
|
|
||||||
"emergency_rsa": "一旦有東西出了問題,此選項可以把您的rsa恢復成官方版本。",
|
|
||||||
"use_proxy": "使用Cultivation內建的代理伺服器。此選項應該被啟用,除非你使用其他的代理伺服器。",
|
|
||||||
"patch_rsa": "自動修補和恢復RSA。除非您的遊戲版本是舊的或者是非官方的,此選項應該被啟用。",
|
|
||||||
"add_delay": "在 3dmigoto 加載程序中設置延遲! \n這應該可以解決加載問題,但會在啟動遊戲時加載 3dmigoto 時增加一點延遲。 \n您現在可以再次使用 3dmigoto 啟動。",
|
|
||||||
"migoto": "用於從 GameBanana 導入模型"
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "選擇Akebi執行檔",
|
|
||||||
"migoto": "選擇3DMigoto執行檔",
|
|
||||||
"reshade": "選擇Reshade注入器"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,103 +1,61 @@
|
|||||||
{
|
{
|
||||||
"lang_name": "Deutsch",
|
"lang_name": "Deutsch",
|
||||||
"main": {
|
"main": {
|
||||||
"title": "Cultivation",
|
"title": "Cultivation",
|
||||||
"launch_button": "Starten",
|
"launch_button": "Starten",
|
||||||
"gc_enable": "Mit Grasscutter verbinden",
|
"gc_enable": "Über Grasscutter verbinden",
|
||||||
"https_enable": "HTTPS verwenden",
|
"https_enable": "HTTPS nutzen",
|
||||||
"ip_placeholder": "Server-Adresse",
|
"ip_placeholder": "Server Adresse...",
|
||||||
"port_placeholder": "Port",
|
"port_placeholder": "Port...",
|
||||||
"files_downloading": "Dateien herunterladen: ",
|
"files_downloading": "Herunterladen von Dateien: ",
|
||||||
"files_extracting": "Dateien extrahieren: ",
|
"files_extracting": "Extrahieren von Dateien: "
|
||||||
"game_path_notify": "Spielverzeichnis nicht gefunden, bitte lege es in den Einstellungen fest!"
|
},
|
||||||
},
|
"options": {
|
||||||
"options": {
|
"enabled": "Aktiviert",
|
||||||
"enabled": "Aktiviert",
|
"disabled": "Deaktiviert",
|
||||||
"disabled": "Deaktiviert",
|
"game_exec": "Spiel Datei auswählen",
|
||||||
"game_path": "Spielinstallationspfad festlegen",
|
"grasscutter_jar": "Grasscuter JAR auswählen",
|
||||||
"game_command": "Spielstartbefehl",
|
"toggle_encryption": "Verschlüsselung umschalten",
|
||||||
"game_executable": "Spiele Datei festlegen",
|
"java_path": "Benutzerdefinierten Java Pfad setzen",
|
||||||
"recover_rsa": "Notfall-RSA löschen",
|
"grasscutter_with_game": "Grasscutter automatisch mit dem Spiel starten",
|
||||||
"grasscutter_jar": "Grasscutter-JAR festlegen",
|
"language": "Sprache auswählen",
|
||||||
"toggle_encryption": "Verschlüsselung umschalten",
|
"background": "Benutzerdefinierten Hintergrund festlegen (link oder bild)",
|
||||||
"install_certificate": "Proxy-Zertifikat installieren",
|
"theme": "Theme auswählen"
|
||||||
"java_path": "Benutzerdefinierten Java-Pfad festlegen",
|
},
|
||||||
"grasscutter_with_game": "Grasscutter automatisch mit dem Spiel starten",
|
"downloads": {
|
||||||
"language": "Sprache auswählen",
|
"grasscutter_stable_data": "Stabile Grasscutter Daten herunterladen",
|
||||||
"background": "Benutzerdefinierten Hintergrund festlegen (Link oder Bild-Datei)",
|
"grasscutter_latest_data": "Aktuellste Grasscutter Daten herunterladen",
|
||||||
"use_theme_background": "Hintergrund des ausgewählten Themes verwenden",
|
"grasscutter_stable_data_update": "Stabile Grasscutter Daten aktualisieren",
|
||||||
"theme": "Theme festlegen",
|
"grasscutter_latest_data_update": "Aktuellste Grasscutter Daten aktualisieren",
|
||||||
"patch_rsa": "RSA automatisch patchen",
|
"grasscutter_stable": "Stabile Grasscutter Version herunterladen",
|
||||||
"use_proxy": "Internen Proxy verwenden",
|
"grasscutter_latest": "Aktuellste Grasscutter Version herunterladen",
|
||||||
"wipe_login": "Login-Cache löschen",
|
"grasscutter_stable_update": "Stabile Grasscutter Version aktualisieren",
|
||||||
"horny_mode": "Horny Modus",
|
"grasscutter_latest_update": "Aktuellste Grasscutter Version aktualisieren",
|
||||||
"auto_mongodb": "MongoDB automatisch starten",
|
"resources": "Grasscutter Ressourcen herunterladen"
|
||||||
"un_elevated": "Spiel ohne Administratorrechte ausführen",
|
},
|
||||||
"redirect_more": "Auch andere miHoYo-Spiele umleiten",
|
"download_status": {
|
||||||
"check_aagl": "Für weitere Optionen, schaue weiter",
|
"downloading": "Lädt herunter",
|
||||||
"grasscutter_elevation": "Methode zur Ausführung von GC auf eingeschränkten Ports",
|
"extracting": "Extrahiert",
|
||||||
"web_cache": "WebCaches-Ordner löschen",
|
"error": "Fehler",
|
||||||
"launch_args": "Launch Args"
|
"finished": "Fertig",
|
||||||
},
|
"stopped": "Gestoppt"
|
||||||
"downloads": {
|
},
|
||||||
"grasscutter_fullbuild": "Grasscutter All-in-One herunterladen",
|
"components": {
|
||||||
"grasscutter_fullquest": "Questing All-in-One herunterladen",
|
"select_file": "Datei oder Ordner auswählen...",
|
||||||
"grasscutter_stable_data": "Stabile Grasscutter-Daten herunterladen",
|
"select_folder": "Ordner auswählen...",
|
||||||
"grasscutter_latest_data": "Neueste Grasscutter-Daten herunterladen",
|
"download": "Herunterladen"
|
||||||
"grasscutter_stable_data_update": "Stabile Grasscutter-Daten aktualisieren",
|
},
|
||||||
"grasscutter_latest_data_update": "Neueste Grasscutter-Daten aktualisieren",
|
"news": {
|
||||||
"grasscutter_unstable": "Grasscutter Questing herunterladen",
|
"latest_commits": "Letzte Commits",
|
||||||
"grasscutter_latest": "Neueste Grasscutter-Version herunterladen",
|
"latest_version": "Letzte Version"
|
||||||
"grasscutter_unstable_update": "Grasscutter Questing aktualisieren",
|
},
|
||||||
"grasscutter_latest_update": "Neueste Grasscutter-Version aktualisieren",
|
"help": {
|
||||||
"resources": "Grasscutter-Ressourcen herunterladen",
|
"port_help_text": "Vergewissern Sie sich, dass es sich um den Port des Dispatch-Servers handelt, nicht um den Port des Spiel-Servers. Dieser ist fast immer '443'.",
|
||||||
"game": "Spiel herunterladen",
|
"game_help_text": "Sie müssen keine separate Kopie verwenden, um mit Grasscutter zu spielen. Dies ist entweder für ein Downgrade auf die Version 2.6 oder wenn Sie das Spiel nicht installiert haben.",
|
||||||
"aio_header": "Alles-in-Einem Downloads:",
|
"gc_stable_jar": "Laden Sie den aktuellen stabilen Grasscutter-Build herunter, der eine Jar-Datei und Datendateien enthält.",
|
||||||
"individual_header": "Einzelne Downloads:",
|
"gc_dev_jar": "Laden Sie die neueste Grasscutter-Entwicklungsversion herunter, welche eine Jar-Datei und Datendateien enthält.",
|
||||||
"mods_header": "Mods:",
|
"gc_stable_data": "Laden Sie die stabilen Grasscutter Daten herunter, welche keine Jar-Datei enthalten. Dies ist nützlich zum Aktualisieren.",
|
||||||
"migoto": "GIMI 3dmigoto herunterladen"
|
"gc_dev_data": "Laden Sie die neuesten Grasscutter-Entwicklungsdateien herunter, welche keine Jar-Datei enthält. Dies ist nützlich zum Aktualisieren.",
|
||||||
},
|
"resources": "Diese werden auch benötigt, um einen Grasscutter-Server auszuführen. Diese Schaltfläche ist grau, wenn Sie einen bestehenden Ressourcenordner mit Inhalten haben"
|
||||||
"download_status": {
|
}
|
||||||
"downloading": "Herunterladen",
|
}
|
||||||
"extracting": "Extrahieren",
|
|
||||||
"error": "Fehler",
|
|
||||||
"finished": "Abgeschlossen",
|
|
||||||
"stopped": "Gestoppt"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "Datei oder Ordner auswählen...",
|
|
||||||
"select_folder": "Ordner auswählen...",
|
|
||||||
"download": "Herunterladen",
|
|
||||||
"delete": "Löschen",
|
|
||||||
"install": "Installieren"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "Neueste Commits",
|
|
||||||
"latest_version": "Neueste Version"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "Stelle sicher, dass dies der Port des Dispatch-Servers ist, nicht der des Spielservers. Dies ist fast immer '443'.",
|
|
||||||
"game_help_text": "Du musst keine separate Kopie verwenden, um mit Grasscutter zu spielen. Dies ist entweder für ein Downgrade auf Version 2.6 oder wenn du das Spiel nicht installiert hast.",
|
|
||||||
"gc_stable_jar": "Lade die aktuelle stabile Grasscutter-Version herunter, die die JAR-Datei und Daten enthält.",
|
|
||||||
"gc_fullbuild": "Lade eine vollständige Grasscutter-Version herunter, inklusive Repository, JAR-Datei und Ressourcen. Sie ist vollständig eingerichtet und erfordert keine weiteren Downloads aus diesem Menü.",
|
|
||||||
"gc_dev_jar": "Lade die neueste Entwicklungsversion von Grasscutter herunter, die die JAR-Datei und Daten enthält.",
|
|
||||||
"gc_stable_data": "Lade die aktuellen stabilen Grasscutter-Daten herunter, die keine JAR-Datei enthalten. Dies ist nützlich für Updates.",
|
|
||||||
"gc_dev_data": "Lade die neuesten Entwicklungsdetails von Grasscutter herunter, die keine JAR-Datei enthalten. Dies ist nützlich für Updates.",
|
|
||||||
"encryption": "Dies sollte normalerweise deaktiviert sein.",
|
|
||||||
"resources": "Diese werden auch benötigt, um einen Grasscutter-Server auszuführen. Diese Schaltfläche ist grau, wenn bereits ein Ressourcenordner mit Inhalten vorhanden ist.",
|
|
||||||
"emergency_rsa": "Für den Fall, dass etwas schiefgegangen ist, erzwingt das Löschen des RSA-Patches.",
|
|
||||||
"use_proxy": "Verwende den internen Cultivation-Proxy. Dies sollte aktiviert sein, es sei denn, du verwendest etwas wie Fiddler.",
|
|
||||||
"patch_rsa": "Patche und entpatche dein Spiel-RSA automatisch. Dies sollte aktiviert sein, es sei denn, du spielst mit alten/nicht offiziellen Versionen (Versionen 3.0 und älter).",
|
|
||||||
"add_delay": "Setze eine Verzögerung im 3dmigoto-Loader! Dies sollte Ladeprobleme beheben, fügt jedoch eine geringfügige Verzögerung hinzu, wenn 3dmigoto beim Starten des Spiels geladen wird. Du kannst jetzt wieder mit 3dmigoto starten.",
|
|
||||||
"migoto": "Zum Importieren von Modellen von GameBanana",
|
|
||||||
"grasscutter_elevation_help_text": "Die Methode, die verwendet wird, um Grasscutter zu ermöglichen, Port 443 zu binden (was für normale Benutzer unter Linux nicht erlaubt ist). Verfügbare Methoden:\n Capability - gewähre der Java Virtual Machine die Fähigkeit, Ports unter 1024 zu binden. Dies ermöglicht auch allen anderen Programmen, die auf dieser JVM ausgeführt werden, diese Ports zu binden.\n Root - führe GC als Root aus. Dies ermöglicht auch dem GC-Server, seinen Plugins und der JVM so ziemlich alles, einschließlich das Senden deiner Bilder an die NSA, CIA und die Alphabet-Boys.\n None - für keine Methode. Dies erfordert, dass du den GC-Dispatch-Port änderst."
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Akebi/Acrepi Ausführbare Datei festlegen",
|
|
||||||
"migoto": "3DMigoto Ausführbare Datei festlegen",
|
|
||||||
"reshade": "Reshade Injector festlegen"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,59 +3,35 @@
|
|||||||
"main": {
|
"main": {
|
||||||
"title": "Cultivation",
|
"title": "Cultivation",
|
||||||
"launch_button": "Launch",
|
"launch_button": "Launch",
|
||||||
"gc_enable": "Connect to Grasscutter",
|
"gc_enable": "Connect via Grasscutter",
|
||||||
"https_enable": "Use HTTPS",
|
"https_enable": "Use HTTPS",
|
||||||
"ip_placeholder": "Server Address...",
|
"ip_placeholder": "Server Address...",
|
||||||
"port_placeholder": "Port...",
|
"port_placeholder": "Port...",
|
||||||
"files_downloading": "Files Downloading: ",
|
"files_downloading": "Files Downloading: ",
|
||||||
"files_extracting": "Files Extracting: ",
|
"files_extracting": "Files Extracting: "
|
||||||
"game_path_notify": "Game path not found, remember to set it in settings!"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"game_path": "Set Game Install Path",
|
"game_exec": "Set Game Executable",
|
||||||
"game_command": "Game Launch Command",
|
|
||||||
"game_executable": "Set Game Executable",
|
|
||||||
"recover_rsa": "Emergency Delete RSA",
|
|
||||||
"grasscutter_jar": "Set Grasscutter JAR",
|
"grasscutter_jar": "Set Grasscutter JAR",
|
||||||
"toggle_encryption": "Toggle Encryption",
|
"toggle_encryption": "Toggle Encryption",
|
||||||
"install_certificate": "Install Proxy Certificate",
|
|
||||||
"java_path": "Set Custom Java Path",
|
"java_path": "Set Custom Java Path",
|
||||||
"grasscutter_with_game": "Automatically launch Grasscutter with game",
|
"grasscutter_with_game": "Automatically launch Grasscutter with game",
|
||||||
"language": "Select Language",
|
"language": "Select Language",
|
||||||
"background": "Set Custom Background (link or image file)",
|
"background": "Set Custom Background (link or image file)",
|
||||||
"use_theme_background": "Use the background supplied by selected theme",
|
"theme": "Set Theme"
|
||||||
"theme": "Set Theme",
|
|
||||||
"patch_rsa": "Automatically Patch RSA",
|
|
||||||
"use_proxy": "Use Internal Proxy",
|
|
||||||
"wipe_login": "Wipe Login Cache",
|
|
||||||
"horny_mode": "Horny Mode",
|
|
||||||
"auto_mongodb": "Automatically Start MongoDB",
|
|
||||||
"un_elevated": "Run the game non-elevated (no admin)",
|
|
||||||
"redirect_more": "Also redirect other MHY games",
|
|
||||||
"check_aagl": "For more options, check the other launcher",
|
|
||||||
"grasscutter_elevation": "Method of running GC on restricted ports",
|
|
||||||
"web_cache": "Delete webCaches folder",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"grasscutter_fullbuild": "Download Grasscutter All-in-One",
|
|
||||||
"grasscutter_fullquest": "Download Questing All-in-One",
|
|
||||||
"grasscutter_stable_data": "Download Grasscutter Stable Data",
|
"grasscutter_stable_data": "Download Grasscutter Stable Data",
|
||||||
"grasscutter_latest_data": "Download Grasscutter Latest Data",
|
"grasscutter_latest_data": "Download Grasscutter Latest Data",
|
||||||
"grasscutter_stable_data_update": "Update Grasscutter Stable Data",
|
"grasscutter_stable_data_update": "Update Grasscutter Stable Data",
|
||||||
"grasscutter_latest_data_update": "Update Grasscutter Latest Data",
|
"grasscutter_latest_data_update": "Update Grasscutter Latest Data",
|
||||||
"grasscutter_unstable": "Download Grasscutter Questing",
|
"grasscutter_stable": "Download Grasscutter Stable",
|
||||||
"grasscutter_latest": "Download Grasscutter Latest",
|
"grasscutter_latest": "Download Grasscutter Latest",
|
||||||
"grasscutter_unstable_update": "Update Grasscutter Questing",
|
"grasscutter_stable_update": "Update Grasscutter Stable",
|
||||||
"grasscutter_latest_update": "Update Grasscutter Latest",
|
"grasscutter_latest_update": "Update Grasscutter Latest",
|
||||||
"resources": "Download Grasscutter Resources",
|
"resources": "Download Grasscutter Resources"
|
||||||
"game": "Download Game",
|
|
||||||
"aio_header": "All-in-One Downloads:",
|
|
||||||
"individual_header": "Individual downloads:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "Download GIMI 3dmigoto"
|
|
||||||
},
|
},
|
||||||
"download_status": {
|
"download_status": {
|
||||||
"downloading": "Downloading",
|
"downloading": "Downloading",
|
||||||
@@ -67,9 +43,7 @@
|
|||||||
"components": {
|
"components": {
|
||||||
"select_file": "Select file or folder...",
|
"select_file": "Select file or folder...",
|
||||||
"select_folder": "Select folder...",
|
"select_folder": "Select folder...",
|
||||||
"download": "Download",
|
"download": "Download"
|
||||||
"delete": "Delete",
|
|
||||||
"install": "Install"
|
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"latest_commits": "Recent Commits",
|
"latest_commits": "Recent Commits",
|
||||||
@@ -79,25 +53,9 @@
|
|||||||
"port_help_text": "Ensure this is the Dispatch server port, not the Game server port. This is almost always '443'.",
|
"port_help_text": "Ensure this is the Dispatch server port, not the Game server port. This is almost always '443'.",
|
||||||
"game_help_text": "You do not need to use a separate copy to play with Grasscutter. This is for either downgrading to 2.6 or if you do not have the game installed.",
|
"game_help_text": "You do not need to use a separate copy to play with Grasscutter. This is for either downgrading to 2.6 or if you do not have the game installed.",
|
||||||
"gc_stable_jar": "Download the current stable Grasscutter build, which includes jar file and data files.",
|
"gc_stable_jar": "Download the current stable Grasscutter build, which includes jar file and data files.",
|
||||||
"gc_fullbuild": "Download a full Grasscutter build, including repo, jar, and resources. Is fully set up and does not require any other downloads from this menu.",
|
|
||||||
"gc_dev_jar": "Download the latest development Grasscutter build, which includes jar file and data files.",
|
"gc_dev_jar": "Download the latest development Grasscutter build, which includes jar file and data files.",
|
||||||
"gc_stable_data": "Download the current stable Grasscutter data files, which does not come with a jar file. This is useful for updating.",
|
"gc_stable_data": "Download the current stable Grasscutter data files, which does not come with a jar file. This is useful for updating.",
|
||||||
"gc_dev_data": "Download the latest development Grasscutter data files, which does not come with a jar file. This is useful for updating.",
|
"gc_dev_data": "Download the latest development Grasscutter data files, which does not come with a jar file. This is useful for updating.",
|
||||||
"encryption": "This should usually be disabled.",
|
"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"
|
||||||
"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.",
|
|
||||||
"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",
|
|
||||||
"grasscutter_elevation_help_text": "The method used to allow Grasscutter to bind port 443 (which is not allowed for regular users on Linux)\nAvailable methods:\n Capability - grant the Java Virtual Machine the capability to bind ports below 1024. This also allows all other programs running on that JVM to bind these ports.\n Root - run GC as root. This also allows the GC server, its plugins and the JVM to do pretty much anything, including sending your nudes to the NSA, CIA, and the alphabet boys.\n None - for no method. This requires you to change the GC Dispatch port."
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Set Akebi/Acrepi Executable",
|
|
||||||
"migoto": "Set 3DMigoto Executable",
|
|
||||||
"reshade": "Set Reshade Injector"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
{
|
|
||||||
"lang_name": "Español",
|
|
||||||
"main": {
|
|
||||||
"title": "Cultivation",
|
|
||||||
"launch_button": "Launch",
|
|
||||||
"gc_enable": "Conectar Via Grasscutter",
|
|
||||||
"https_enable": "Usar HTTPS",
|
|
||||||
"ip_placeholder": "Dirección del servidor...",
|
|
||||||
"port_placeholder": "Puerto...",
|
|
||||||
"files_downloading": "Archivos Descargandose: ",
|
|
||||||
"files_extracting": "Archivos Extrayendose: ",
|
|
||||||
"game_path_notify": "Ruta de juego no encontrada, ¡recuerda configurarla en ajustes!"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"enabled": "Activado",
|
|
||||||
"disabled": "Desactivado",
|
|
||||||
"game_path": "Ruta de instalación del juego",
|
|
||||||
"game_command": "Comando de lanzamiento del juego",
|
|
||||||
"game_executable": "Establecer ejecutable del juego",
|
|
||||||
"recover_rsa": "Recuperación de RSA de Emergencia",
|
|
||||||
"grasscutter_jar": "Establecer JAR de Grasscutter",
|
|
||||||
"toggle_encryption": "Alternar Cifrado",
|
|
||||||
"install_certificate": "Instalar Certificado Proxy",
|
|
||||||
"java_path": "Establecer ruta personalizada de Java",
|
|
||||||
"grasscutter_with_game": "Iniciar automáticamente Grasscutter con el juego",
|
|
||||||
"language": "Seleccionar idioma",
|
|
||||||
"background": "Establecer fondo personalizado (link o archivo de imagen)",
|
|
||||||
"use_theme_background": "Usar fondo proporcionado por el tema seleccionado",
|
|
||||||
"patch_rsa": "Parchear RSA automáticamente",
|
|
||||||
"theme": "Establecer tema",
|
|
||||||
"use_proxy": "Usar proxy interno",
|
|
||||||
"wipe_login": "Borrar caché de inicio de sesión",
|
|
||||||
"horny_mode": "Modo cachondo",
|
|
||||||
"auto_mongodb": "Iniciar automáticamente MongoDB",
|
|
||||||
"un_elevated": "Ejecutar el juego sin permisos de administrador",
|
|
||||||
"redirect_more": "También redirigir otros juegos MHY",
|
|
||||||
"web_cache": "Eliminar la carpeta webCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"grasscutter_fullbuild": "Descargar datos todo en uno de Grasscutter",
|
|
||||||
"grasscutter_fullquest": "Descargar datos todo en uno de Questing",
|
|
||||||
"grasscutter_stable_data": "Descargar datos Estables de Grasscutter",
|
|
||||||
"grasscutter_latest_data": "Descargar datos más Recientes de Grasscutter",
|
|
||||||
"grasscutter_stable_data_update": "Actualizar datos estables de Grasscutter",
|
|
||||||
"grasscutter_latest_data_update": "Actualizar datos más recientes de Grasscutter",
|
|
||||||
"grasscutter_unstable": "Descargar Grasscutter estable",
|
|
||||||
"grasscutter_latest": "Descargar Grasscutter más reciente",
|
|
||||||
"grasscutter_unstable_update": "Actualizar Grasscutter estable",
|
|
||||||
"grasscutter_latest_update": "Actualizar Grasscutter más reciente",
|
|
||||||
"resources": "Descargar recursos de Grasscutter",
|
|
||||||
"game": "Descarga el juego",
|
|
||||||
"aio_header": "Descargas todo en uno:",
|
|
||||||
"individual_header": "Descargas de piezas individuales:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "Descargar GIMI 3dmigoto"
|
|
||||||
},
|
|
||||||
"download_status": {
|
|
||||||
"downloading": "Descargando",
|
|
||||||
"extracting": "Extrayendo",
|
|
||||||
"error": "Error",
|
|
||||||
"finished": "Finalizado",
|
|
||||||
"stopped": "Detenido"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "Seleccionar el archivo o carpeta",
|
|
||||||
"select_folder": "Seleccionar la carpeta",
|
|
||||||
"download": "Descargar",
|
|
||||||
"delete": "Borrar",
|
|
||||||
"install": "Instalar"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "Commits recientes",
|
|
||||||
"latest_version": "Ultima versión"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "Asegúrese de que este sea el puerto del servidor Dispatch, no el Game server port. Este es casi siempre '443'.",
|
|
||||||
"game_help_text": "No necesitas usar una copia separada para jugar con Grasscutter. Esto es para cambiar a 2.6 o si no tienes el juego instalado.",
|
|
||||||
"gc_stable_jar": "Descargue la versión estable actual de Grasscutter, que incluye el archivo .jar y los archivos de datos.",
|
|
||||||
"gc_fullbuild": "Descarga una compilación completa de Grasscutter, incluyendo repo, jar y recursos. Está totalmente configurado y no requiere ninguna otra descarga desde este menú.",
|
|
||||||
"gc_dev_jar": "Descargue la última versión de desarrollo de Grasscutter, que incluye archivos .jar y archivos de datos.",
|
|
||||||
"gc_stable_data": "Descargue los archivos de datos estables actuales de Grasscutter, que no vienen con un archivo .jar. Esto es útil para actualizar.",
|
|
||||||
"gc_dev_data": "Descargue los últimos archivos de datos de desarrollo de Grasscutter, que no vienen con un archivo .jar. Esto es útil para actualizar.",
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,90 +8,54 @@
|
|||||||
"ip_placeholder": "Adresse du serveur...",
|
"ip_placeholder": "Adresse du serveur...",
|
||||||
"port_placeholder": "Port...",
|
"port_placeholder": "Port...",
|
||||||
"files_downloading": "Fichiers en cours de telechargement: ",
|
"files_downloading": "Fichiers en cours de telechargement: ",
|
||||||
"files_extracting": "Fichiers en cours d'extraction: ",
|
"files_extracting": "Fichiers en cours d'extraction: "
|
||||||
"game_path_notify": "Chemin d'accès au jeu non trouvé, n'oubliez pas de le définir dans les options !"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"enabled": "Activé",
|
"enabled": "active",
|
||||||
"disabled": "Désractivé",
|
"disabled": "desactiver",
|
||||||
"game_path": "Définir le chemin d'installation du jeu",
|
"game_exec": "definir l'executable du jeu",
|
||||||
"game_command": "Commande de lancement du jeu",
|
"grasscutter_jar": "definir le Jar Grasscutter",
|
||||||
"game_executable": "Définir l'executable du jeu",
|
"toggle_encryption": "activer l'encryption",
|
||||||
"recover_rsa": "Récupération d'urgence des RSA",
|
"java_path": "definir un chemin java personnalise",
|
||||||
"grasscutter_jar": "Définir le Jar Grasscutter",
|
|
||||||
"toggle_encryption": "Activer l'encryption",
|
|
||||||
"install_certificate": "Installer le certificat du proxy",
|
|
||||||
"java_path": "Définir un chemin java personnalise",
|
|
||||||
"grasscutter_with_game": "Lancer Grasscutter automatiquement avec le jeu",
|
"grasscutter_with_game": "Lancer Grasscutter automatiquement avec le jeu",
|
||||||
"language": "Choisir la langue",
|
"language": "Choisir la langue",
|
||||||
"background": "Définir un arriere plan personnalisé (lien ou fichier image)",
|
"background": "definir un arriere plan personnalise (lien ou fichier image)",
|
||||||
"use_theme_background": "Utiliser l'arrière-plan fourni par le thème sélectionné",
|
"theme": "definir un theme"
|
||||||
"theme": "Définir un theme",
|
|
||||||
"patch_rsa": "Patcher automatiquement les clés RSA",
|
|
||||||
"use_proxy": "Utiliser le proxy interne",
|
|
||||||
"wipe_login": "Effacer le cache de connexion",
|
|
||||||
"horny_mode": "Mode horny",
|
|
||||||
"auto_mongodb": "Démarrer automatiquement MongoDB",
|
|
||||||
"un_elevated": "Exécuter le jeu sans élévation (pas d'administrateur)",
|
|
||||||
"redirect_more": "Réorienter également les autres jeux MHY",
|
|
||||||
"web_cache": "Supprimer le dossier webCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"grasscutter_fullbuild": "Telecharger Grasscutter tout-en-un",
|
"grasscutter_stable_data": "Telecharger les donnees de Grasscutter (version stable)",
|
||||||
"grasscutter_fullquest": "Télécharger les Quêtes tout-en-un",
|
"grasscutter_latest_data": "Telecharger les donnees de Grasscutter (derniere version)",
|
||||||
"grasscutter_stable_data": "Télécharger les donnees de Grasscutter (version stable)",
|
"grasscutter_stable_data_update": "Mettre a jour les donnees de Grasscutter (version stable)",
|
||||||
"grasscutter_latest_data": "Télécharger les donnees de Grasscutter (derniere version)",
|
"grasscutter_latest_data_update": "Mettre a jour les donnees de Grasscutter (derniere version)",
|
||||||
"grasscutter_stable_data_update": "Mettre à jour les données de Grasscutter (version stable)",
|
"grasscutter_stable": "Telecharger Grasscutter (version stable)",
|
||||||
"grasscutter_latest_data_update": "Mettre à jour les données de Grasscutter (derniere version)",
|
"grasscutter_latest": "Telecharger Grasscutter (derniere version)",
|
||||||
"grasscutter_unstable": "Télécharger Grasscutter (version stable)",
|
"grasscutter_stable_update": "Mettre a jour Grasscutter (version stable)",
|
||||||
"grasscutter_latest": "Télécharger Grasscutter (derniere version)",
|
"grasscutter_latest_update": "Mettre a jour Grasscutter (derniere version)",
|
||||||
"grasscutter_unstable_update": "Mettre à jour Grasscutter (version stable)",
|
"resources": "Telecharger les ressources logicielles de Grasscutter"
|
||||||
"grasscutter_latest_update": "Mettre à jour Grasscutter (derniere version)",
|
|
||||||
"resources": "Telecharger les ressources de Grasscutter",
|
|
||||||
"aio_header": "Telechargements tout-en-un:",
|
|
||||||
"individual_header": "Telechargements individuels:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "Telecharger GIMI 3dmigoto"
|
|
||||||
},
|
},
|
||||||
"download_status": {
|
"download_status": {
|
||||||
"downloading": "Téléchargement",
|
"downloading": "Telechargement",
|
||||||
"extracting": "Extraction",
|
"extracting": "Extraction",
|
||||||
"error": "Erreur",
|
"error": "Erreur",
|
||||||
"finished": "Terminé",
|
"finished": "Termine",
|
||||||
"stopped": "Arrêté"
|
"stopped": "Arrete"
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"select_file": "Choisir un fichier ou un dossier...",
|
"select_file": "choisir fichier ou dossier...",
|
||||||
"select_folder": "Choisir un dossier...",
|
"select_folder": "choisir dossier...",
|
||||||
"download": "Télécharger",
|
"download": "Telecharger"
|
||||||
"delete": "Supprimer",
|
|
||||||
"install": "Installer"
|
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"latest_commits": "Commits récents",
|
"latest_commits": "Recents Commits",
|
||||||
"latest_version": "Dernière version"
|
"latest_version": "Derniere version"
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"port_help_text": "Assurez-vous que c'est le port du serveur de Dispatch, et non le port du serveur de jeu. C'est presque toujours '433'.",
|
"port_help_text": "Assurez-vous que c'est le port serveur Dispatch, et non le port du serveur de jeu. C'est presque toujours '433'.",
|
||||||
"game_help_text": "Il n'y a pas besoin d'une copie differente du jeu pour jouer avec Grasscutter. C'est utile pour downgrade en 2.6 ou si vous n'avez pas le jeu d'installe",
|
"game_help_text": "Vous n'avez pas besoin d'une copie differente du jeu pour jouer avec Grasscutter. Cela est ou pour retrograder en 2.6 ou si vous n'avez pas le jeu d'installe",
|
||||||
"gc_stable_jar": "Télécharge le dernier build stable de Grasscutter, ce qui inclut le fichier jar et les fichiers de données",
|
"gc_stable_jar": "Telecharger le dernier build stable de Grasscutter, ce qui inclut le fichier jar et les fichiers de donnees",
|
||||||
"gc_fullbuild": "Télécharge un build complet de Grasscutter, incluant le repo, le jar et les ressources. Il est entièrement configuré et ne nécessite aucun autre téléchargement à partir de ce menu.",
|
"gc_dev_jar": "Telecharger le dernier build en development de Grasscutter, ce qui inclut le fichier jar et les fichiers de donnees",
|
||||||
"gc_dev_jar": "Télécharge le dernier build de development de Grasscutter, ce qui inclut le fichier jar et les fichiers de données",
|
"gc_stable_data": "Telecharger le dernier build stable de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
|
||||||
"gc_stable_data": "Télécharge le dernier build stable de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
|
"gc_dev_data": "Telecharger le dernier build en development de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
|
||||||
"gc_dev_data": "Télécharge le dernier build de development de Grasscutter, ce qui n'inclut pasle fichier jar. Cela est utile pour mettre a jour",
|
"resources": "Les ressources sont aussi necessaires pour lancer un serveur Grasscutter. Ce bouton deviendra gris si vous avez deja un fichier ressources avec les donnees dedans."
|
||||||
"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éfinit le délai du chargement de 3dmigoto ! \nCela devrait résoudre les problèmes de chargement, mais ajoutera un petit délai au chargement de 3dmigoto lors du lancement du jeu. \nVous pouvez maintenant lancer le jeu avec 3dmigoto.",
|
|
||||||
"use_proxy": "Active le proxy interne de Cultivation. Il faut activer cette option si un logiciel tel que Fiddler n'est pas installé.",
|
|
||||||
"patch_rsa": "Patch et dépatche les clés RSA du jeu automatiquement. A moins de jouer avec d'anciennes versons ou des versions non officielles (3.0 ou plus ancien), cette option doit être activée.",
|
|
||||||
"migoto": "Pour importer des modèles depuis GameBanana"
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Définir l'exécutable d'Akebid'aAcrepi",
|
|
||||||
"migoto": "Définir l'exécutable de 3DMigoto",
|
|
||||||
"reshade": "Définir l'injecteur de Reshade"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,51 +7,27 @@
|
|||||||
"ip_placeholder": "Alamat Server...",
|
"ip_placeholder": "Alamat Server...",
|
||||||
"port_placeholder": "Port...",
|
"port_placeholder": "Port...",
|
||||||
"files_downloading": "Mendownload File Yang Diperlukan: ",
|
"files_downloading": "Mendownload File Yang Diperlukan: ",
|
||||||
"files_extracting": "MengExtract File: ",
|
"files_extracting": "MengExtract File: "
|
||||||
"game_path_notify": "Jalur permainan tidak ditemukan, ingatlah untuk mengaturnya dalam pengaturan!"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"enabled": "Diaktifkan",
|
"game_exec": "Set Game Executable",
|
||||||
"disabled": "Dinonaktifkan",
|
|
||||||
"game_path": "Mengatur jalur penginstalan game",
|
|
||||||
"game_command": "Perintah peluncuran game",
|
|
||||||
"game_executable": "Mengatur game yang dapat dieksekusi",
|
|
||||||
"recover_rsa": "Pemulihan RSA darurat",
|
|
||||||
"grasscutter_jar": "Path ke Grasscutter JAR",
|
"grasscutter_jar": "Path ke Grasscutter JAR",
|
||||||
"toggle_encryption": "Alihkan enkripsi",
|
|
||||||
"install_certificate": "Instal sertifikat proxy",
|
|
||||||
"java_path": "Atur kustom Java path",
|
"java_path": "Atur kustom Java path",
|
||||||
"grasscutter_with_game": "Otomatis Menjalankan Grasscutter Dengan Game",
|
"grasscutter_with_game": "Otomatis Menjalankan Grasscutter Dengan Game",
|
||||||
"language": "Pilih Bahasa",
|
"language": "Pilih Bahasa",
|
||||||
"background": "Atur Kustom Latar Belakang (link atau gambar file)",
|
"background": "Atur Kustom Latar Belakang (link atau gambar file)",
|
||||||
"use_theme_background": "Gunakan latar belakang yang disediakan oleh tema yang dipilih",
|
"theme": "Atur Tema"
|
||||||
"theme": "Atur Tema",
|
|
||||||
"patch_rsa": "Automatically Patch RSA",
|
|
||||||
"use_proxy": "Gunakan Proxy Internal",
|
|
||||||
"wipe_login": "Menghapus Cache Login",
|
|
||||||
"horny_mode": "Mode Terangsang",
|
|
||||||
"auto_mongodb": "Mulai MongoDB secara otomatis",
|
|
||||||
"un_elevated": "Jalankan game yang tidak ditinggikan (tanpa admin)",
|
|
||||||
"redirect_more": "Juga mengarahkan ulang game MHY lainnya",
|
|
||||||
"web_cache": "Hapus folder webCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"grasscutter_fullbuild": "Sedang Mendownload Grasscutter Semua Dalam Satu",
|
|
||||||
"grasscutter_fullquest": "Unduh pencarian semua dalam satu",
|
|
||||||
"grasscutter_stable_data": "Sedang Mendownload Grasscutter Versi Stabil",
|
"grasscutter_stable_data": "Sedang Mendownload Grasscutter Versi Stabil",
|
||||||
"grasscutter_latest_data": "Sedang Mendownload Grasscutter Data Terbaru",
|
"grasscutter_latest_data": "Sedang Mendownload Grasscutter Data Terbaru",
|
||||||
"grasscutter_stable_data_update": "Memperbaharui Grasscutter Data Stabil",
|
"grasscutter_stable_data_update": "Memperbaharui Grasscutter Data Stabil",
|
||||||
"grasscutter_latest_data_update": "Memperbaharui Grasscutter Data Terbaru",
|
"grasscutter_latest_data_update": "Memperbaharui Grasscutter Data Terbaru",
|
||||||
"grasscutter_unstable": "Download Grasscutter Stabil Version ",
|
"grasscutter_stable": "Download Grasscutter Stabil Version ",
|
||||||
"grasscutter_latest": "Download Grasscutter Terbaru Version",
|
"grasscutter_latest": "Download Grasscutter Terbaru Version",
|
||||||
"grasscutter_unstable_update": "Sedang MengUpdate Grasscutter Stabil",
|
"grasscutter_stable_update": "Sedang MengUpdate Grasscutter Stabil",
|
||||||
"grasscutter_latest_update": "Sedang MengUpdate Grasscutter Terbaru",
|
"grasscutter_latest_update": "Sedang MengUpdate Grasscutter Terbaru",
|
||||||
"resources": "Mendownload Grasscutter Resources",
|
"resources": "Mendownload Grasscutter Resources"
|
||||||
"aio_header": "Unduhan Semua Dalam Satu:",
|
|
||||||
"individual_header": "Unduhan Bagian Individual:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "Sedang Mendownload GIMI 3dmigoto"
|
|
||||||
},
|
},
|
||||||
"download_status": {
|
"download_status": {
|
||||||
"downloading": "Sedang Mendownload",
|
"downloading": "Sedang Mendownload",
|
||||||
@@ -63,8 +39,7 @@
|
|||||||
"components": {
|
"components": {
|
||||||
"select_file": "Pilih File Atau Folder...",
|
"select_file": "Pilih File Atau Folder...",
|
||||||
"select_folder": "Pilih Folder...",
|
"select_folder": "Pilih Folder...",
|
||||||
"download": "download",
|
"download": "download"
|
||||||
"delete": "Menghapus"
|
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"latest_commits": "Commit Terbaru",
|
"latest_commits": "Commit Terbaru",
|
||||||
@@ -74,12 +49,9 @@
|
|||||||
"port_help_text": "Pastikan ini adalah port server port, bukan port server Game. ini Hampir Selalu '443'.",
|
"port_help_text": "Pastikan ini adalah port server port, bukan port server Game. ini Hampir Selalu '443'.",
|
||||||
"game_help_text": "Anda tidak perlu menggunakan salinan Genshin Impact untuk bermain dengan Grasscutter. Ini untuk menurunkan versi ke 2.6 atau jika Anda belum menginstal game..",
|
"game_help_text": "Anda tidak perlu menggunakan salinan Genshin Impact untuk bermain dengan Grasscutter. Ini untuk menurunkan versi ke 2.6 atau jika Anda belum menginstal game..",
|
||||||
"gc_stable_jar": "Unduh Build Stabil Grasscutter Saat ini, Dimana Ada Jar File Dan Data File.",
|
"gc_stable_jar": "Unduh Build Stabil Grasscutter Saat ini, Dimana Ada Jar File Dan Data File.",
|
||||||
"gc_fullbuild": "Unduh versi lengkap Grasscutter, termasuk repo, jar, dan sumber daya. Sudah diatur sepenuhnya dan tidak memerlukan unduhan lain dari menu ini.",
|
|
||||||
"gc_dev_jar": "Unduh Build Development Grasscutter saat ini, Dimana Ada Jar File Dan Data File.",
|
"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_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.",
|
"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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
{
|
|
||||||
"lang_name": "Italiano",
|
|
||||||
"main": {
|
|
||||||
"title": "Cultivation",
|
|
||||||
"launch_button": "Avvia",
|
|
||||||
"gc_enable": "Connettiti a Grasscutter",
|
|
||||||
"https_enable": "Usa HTTPS",
|
|
||||||
"ip_placeholder": "Indirizzo Del Server...",
|
|
||||||
"port_placeholder": "Porta...",
|
|
||||||
"files_downloading": "File in Download: ",
|
|
||||||
"files_extracting": "File in Estrazione: ",
|
|
||||||
"game_path_notify": "Percorso del gioco non trovato, ricordati di impostarlo nelle impostazioni!"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"enabled": "Abilitato",
|
|
||||||
"disabled": "Disabilitato",
|
|
||||||
"game_path": "Imposta percorso di installazione del gioco",
|
|
||||||
"game_command": "Commando d'avvio del gioco",
|
|
||||||
"game_executable": "Imposta l'executable del gioco",
|
|
||||||
"recover_rsa": "Eliminazione d'emergenza dell'RSA",
|
|
||||||
"grasscutter_jar": "Imposta il file JAR di Grasscutter",
|
|
||||||
"toggle_encryption": "Cittografia",
|
|
||||||
"install_certificate": "Installa il Certificato del Proxy",
|
|
||||||
"java_path": "Imposta il percorso personalizzato di Java",
|
|
||||||
"grasscutter_with_game": "Avvia automaticamente Grasscutter con il gioco",
|
|
||||||
"language": "Imposta lingua",
|
|
||||||
"background": "Imposta sfondo personalizzato (link o immagine)",
|
|
||||||
"use_theme_background": "Usa lo sfondo fornito dal tema selezionato",
|
|
||||||
"theme": "Imposta tema",
|
|
||||||
"patch_rsa": "Patch RSA automaticamente",
|
|
||||||
"use_proxy": "Usa Proxy Interno",
|
|
||||||
"wipe_login": "Cancella la cache dell'accesso",
|
|
||||||
"horny_mode": "Modalità Horny",
|
|
||||||
"auto_mongodb": "Avvia Automaticamente MongoDB",
|
|
||||||
"un_elevated": "Avvia il gioco non-elevato (non admin)",
|
|
||||||
"redirect_more": "Reindirizza anche altri giochi MHY",
|
|
||||||
"web_cache": "Elimina la cartella webCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"grasscutter_fullbuild": "Scarica Grasscutter Tutto-in-Uno",
|
|
||||||
"grasscutter_fullquest": "Scarica Questing Tutto-in-Uno",
|
|
||||||
"grasscutter_stable_data": "Scarica i dati di Grasscutter Stabili",
|
|
||||||
"grasscutter_latest_data": "Scarica i dati di Grasscutter Più Recenti",
|
|
||||||
"grasscutter_stable_data_update": "Aggiorna i dati di Grasscutter Stabili",
|
|
||||||
"grasscutter_latest_data_update": "Aggiorna i dati di Grasscutter Più Recenti",
|
|
||||||
"grasscutter_unstable": "Scarica Grasscutter Questing",
|
|
||||||
"grasscutter_latest": "Scarica Grasscutter Più Recente",
|
|
||||||
"grasscutter_unstable_update": "Aggiorna Grasscutter Questing",
|
|
||||||
"grasscutter_latest_update": "Aggiorna Grasscutter più Recente",
|
|
||||||
"resources": "Scarica le Risorse di Grasscutter",
|
|
||||||
"game": "Scarica il gioco",
|
|
||||||
"aio_header": "Tutto-in-Uno Download:",
|
|
||||||
"individual_header": "Download individuali:",
|
|
||||||
"mods_header": "Mod:",
|
|
||||||
"migoto": "Scarica GIMI 3dmigoto"
|
|
||||||
},
|
|
||||||
"download_status": {
|
|
||||||
"downloading": "Scaricando",
|
|
||||||
"extracting": "Estraendo",
|
|
||||||
"error": "Errore",
|
|
||||||
"finished": "Completato",
|
|
||||||
"stopped": "Interrotto"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "Seleziona file o cartella...",
|
|
||||||
"select_folder": "Seleziona cartella...",
|
|
||||||
"download": "Scarica",
|
|
||||||
"delete": "Cancella",
|
|
||||||
"install": "Installa"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "Commit Recenti",
|
|
||||||
"latest_version": "Ultima Versione"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "Assicurati che questa sia la porta del server Dispatch, non la porta del server di gioco. È quasi sempre '443'.",
|
|
||||||
"game_help_text": "Non ti serve una copia separata per giocare con Grasscutter. Questo è per fare il downgrade a 2.6 o se non hai il gioco installato.",
|
|
||||||
"gc_stable_jar": "Scarica la build stabile di Grasscutter più recente, che include il file jar e i dati.",
|
|
||||||
"gc_fullbuild": "Scarica la build completa di Grasscutter più recente, che include repo, jar e risorse. È completamente configurato e non richiede altri download da questo menu.",
|
|
||||||
"gc_dev_jar": "Scarica la build in sviluppo di Grasscutter più recente, che include il file jar e i dati.",
|
|
||||||
"gc_stable_data": "Scarica i dati della build stabile di Grasscutter più recente, che non include il file jar. È utile per aggiornare.",
|
|
||||||
"gc_dev_data": "Scarica i dati della build in sviluppo di Grasscutter più recente, che non include il file jar. È utile per aggiornare.",
|
|
||||||
"encryption": "Di solito questo dovrebbe essere disabilitato.",
|
|
||||||
"resources": "Queste sono anche necessari per eseguire un server Grasscutter. Questo bottone è grigio se hai una cartella delle risorse esistente con contenuto all'interno.",
|
|
||||||
"emergency_rsa": "In caso qualcosa è andato storto, forza l'eliminazione dell'RSA.",
|
|
||||||
"use_proxy": "Usa il proxy interno di Cultivation. Dovresti averlo attivato a meno che tu non usi qualcosa come Fiddler.",
|
|
||||||
"patch_rsa": "Patch e unpatch l'RSA del gioco automaticamente. A meno che tu non usi versioni vecchie/non ufficiali del gioco (3.0 e precedenti), questo dovrebbe essere attivato.",
|
|
||||||
"add_delay": "Imposta il ritardo nel caricatore 3dmigoto! \nQuesto dovrebbe risolvere i problemi di caricamento, ma aggiungerà un piccolo ritardo al caricamento di 3dmigoto all'avvio del gioco. \nOra puoi avviare il gioco con 3dmigoto di nuovo.",
|
|
||||||
"migoto": "Per importare modelli da GameBanana"
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Imposta l'Executable di Akebi/Acrepi",
|
|
||||||
"migoto": "Imposta l'Executable di 3DMigoto",
|
|
||||||
"reshade": "Imposta l'Injector di Reshade"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
{
|
|
||||||
"lang_name": "한국어",
|
|
||||||
"main": {
|
|
||||||
"title": "Cultivation",
|
|
||||||
"launch_button": "게임 시작",
|
|
||||||
"gc_enable": "Grasscutter 연결",
|
|
||||||
"https_enable": "HTTPS 사용",
|
|
||||||
"ip_placeholder": "서버 주소",
|
|
||||||
"port_placeholder": "포트",
|
|
||||||
"files_downloading": "파일 다운로드 중: ",
|
|
||||||
"files_extracting": "파일 추출 중: ",
|
|
||||||
"game_path_notify": "게임 경로를 찾을 수 없습니다. 설정에서 설정하는 것을 잊지 마세요!"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"enabled": "활성",
|
|
||||||
"disabled": "비활성",
|
|
||||||
"game_path": "게임 설치 경로 설정",
|
|
||||||
"game_command": "게임 시작 명령",
|
|
||||||
"game_executable": "게임 실행 파일 설정",
|
|
||||||
"recover_rsa": "긴급 RSA 복원",
|
|
||||||
"grasscutter_jar": "그래스커터 JAR 설정",
|
|
||||||
"toggle_encryption": "암호화 전환",
|
|
||||||
"install_certificate": "프록시 인증서 설치",
|
|
||||||
"java_path": "사용자 지정 Java 경로 설정",
|
|
||||||
"grasscutter_with_game": "게임에서 자동으로 그래스커터 실행",
|
|
||||||
"language": "언어 선택",
|
|
||||||
"background": "사용자 지정 배경 설정(링크 또는 이미지 파일)",
|
|
||||||
"use_theme_background": "선택한 테마에서 제공하는 배경 사용",
|
|
||||||
"theme": "테마 설정",
|
|
||||||
"patch_rsa": "RSA 패치 자동 적용",
|
|
||||||
"use_proxy": "내부 프록시 사용",
|
|
||||||
"wipe_login": "로그인 캐시 지우기",
|
|
||||||
"horny_mode": "Horny 모드",
|
|
||||||
"auto_mongodb": "MongoDB 자동 시작",
|
|
||||||
"un_elevated": "게임 비상승 실행(관리자 없음)",
|
|
||||||
"redirect_more": "다른 MHY 게임도 리디렉션",
|
|
||||||
"web_cache": "webCaches 폴더 삭제",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"grasscutter_fullbuild": "올인원 Grasscutter 다운로드",
|
|
||||||
"grasscutter_fullquest": "퀘스트 올인원 다운로드",
|
|
||||||
"grasscutter_stable_data": "안정적인 데이터 다운로드",
|
|
||||||
"grasscutter_latest_data": "최신 데이터 다운로드",
|
|
||||||
"grasscutter_stable_data_update": "안정적 데이터 업데이트",
|
|
||||||
"grasscutter_latest_data_update": "최신 데이터 업데이트",
|
|
||||||
"grasscutter_unstable": "안정 다운로드",
|
|
||||||
"grasscutter_latest": "최신 다운로드",
|
|
||||||
"grasscutter_unstable_update": "안정 업데이트",
|
|
||||||
"grasscutter_latest_update": "최신 업데이트",
|
|
||||||
"resources": "리소스 다운로드",
|
|
||||||
"game": "게임 다운로드",
|
|
||||||
"aio_header": "올인원 다운로드",
|
|
||||||
"individual_header": "개별 부품 다운로드:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "GIMI 3dmigoto 다운로드"
|
|
||||||
},
|
|
||||||
"download_status": {
|
|
||||||
"downloading": "다운로드 중",
|
|
||||||
"extracting": "추출 중",
|
|
||||||
"error": "오류",
|
|
||||||
"finished": "완료",
|
|
||||||
"stopped": "중지"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "파일 또는 폴더 선택...",
|
|
||||||
"select_folder": "폴더 선택...",
|
|
||||||
"download": "다운로드",
|
|
||||||
"delete": "삭제",
|
|
||||||
"install": "설치"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "공지 사항",
|
|
||||||
"latest_version": "최신 버전"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "게임 서버 포트가 아닌 패치 서버 포트인지 확인하십시오. (기본 포트: 443)",
|
|
||||||
"game_help_text": "그래스커터를 사용하기 위해 별도의 복사본을 사용할 필요가 없습니다. 이는 2.6으로 다운그레이드 하거나 게임을 설치하지 않은 경우에 적용됩니다.",
|
|
||||||
"gc_stable_jar": "jar 파일과 데이터 파일이 포함된 현재 안정적인 Grasscuter 빌드를 다운로드합니다.",
|
|
||||||
"gc_fullbuild": "저장소, 저장소, 리소스를 포함한 Grasscutter 정식 버전을 다운로드하세요. 모든 준비가 완료되었으며 이 메뉴에서 다른 다운로드는 필요하지 않습니다.",
|
|
||||||
"gc_dev_jar": "jar 파일 및 데이터 파일이 포함된 최신 개발 Grasscuter 빌드를 다운로드하십시오.",
|
|
||||||
"gc_stable_data": "jar 파일과 함께 제공되지 않는 현재 안정적인 Grasscuter 데이터 파일을 다운로드합니다. 이것은 업데이트하는 데 유용합니다.",
|
|
||||||
"gc_dev_data": "jar 파일과 함께 제공되지 않는 최신 개발 Grasscuter 데이터 파일을 다운로드합니다. 이것은 업데이트하는 데 유용합니다.",
|
|
||||||
"encryption": "일반적으로 이 기능을 사용하지 않도록 설정해야 합니다.",
|
|
||||||
"resources": "또한 Grasscutter 서버를 실행하는 데도 필요합니다. 내용이 포함된 기존 리소스 폴더가 있는 경우 이 버튼은 회색으로 표시됩니다",
|
|
||||||
"emergency_rsa": "문제가 있는 경우 RSA 패치를 제거하십시오.",
|
|
||||||
"use_proxy": "Culturation 내부 프록시를 사용합니다. 피들러와 같은 것을 사용하지 않는 한 이 기능을 활성화해야 합니다",
|
|
||||||
"patch_rsa": "게임 RSA를 자동으로 패치 및 패치 해제합니다. 이전/비공식 버전을 사용하거나 RSA를 수동으로 패치하지 않은 경우 이 기능을 활성화해야 합니다.",
|
|
||||||
"add_delay": "3dmigoto 로더에서 지연을 설정하세요! \n이렇게하면 로딩 문제가 해결되지만 게임을 시작할 때 3dmigoto가로드되는시기에 약간의 지연이 추가됩니다. \n이제 3dmigoto로 다시 시작할 수 있습니다.",
|
|
||||||
"migoto": "GameBanana에서 모델 가져오기"
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Akebi 실행 파일 설정",
|
|
||||||
"migoto": "3DMigoto 실행 파일 설정",
|
|
||||||
"reshade": "Reshade 인젝터 설정"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,49 +8,30 @@
|
|||||||
"ip_placeholder": "Servera Adrese...",
|
"ip_placeholder": "Servera Adrese...",
|
||||||
"port_placeholder": "Ports...",
|
"port_placeholder": "Ports...",
|
||||||
"files_downloading": "Failu Lejupielāde: ",
|
"files_downloading": "Failu Lejupielāde: ",
|
||||||
"files_extracting": "Failu Izvilkšana: ",
|
"files_extracting": "Failu Izvilkšana: "
|
||||||
"game_path_notify": "Spēles ceļš nav atrasts, atcerieties to iestatījumos!"
|
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"enabled": "Iespējots",
|
"enabled": "Iespējots",
|
||||||
"disabled": "Atspējots",
|
"disabled": "Atspējots",
|
||||||
"game_executable": "Iestatīt spēles izpildāmu",
|
"game_exec": "Iestatīt spēles izpildāmu",
|
||||||
"recover_rsa": "Avārijas RSA atjaunošana",
|
|
||||||
"grasscutter_jar": "Iestatiet Grasscutter JAR",
|
"grasscutter_jar": "Iestatiet Grasscutter JAR",
|
||||||
"toggle_encryption": "Pārslēgt Šifrēšanu",
|
"toggle_encryption": "Pārslēgt Šifrēšanu",
|
||||||
"install_certificate": "Proxy sertifikāta instalēšana",
|
|
||||||
"java_path": "Iestatiet pielāgotu Java ceļu",
|
"java_path": "Iestatiet pielāgotu Java ceļu",
|
||||||
"grasscutter_with_game": "Automātiski palaidiet Grasscutter ar spēli",
|
"grasscutter_with_game": "Automātiski palaidiet Grasscutter ar spēli",
|
||||||
"language": "Izvēlēties valodu",
|
"language": "Izvēlēties valodu",
|
||||||
"background": "Iestatīt pielāgotu fonu (saite vai attēla fails)",
|
"background": "Iestatīt pielāgotu fonu (saite vai attēla fails)",
|
||||||
"use_theme_background": "Izmantojiet atlasītā motīva nodrošināto fonu",
|
"theme": "Iestatīt tēmu"
|
||||||
"theme": "Iestatīt tēmu",
|
|
||||||
"patch_rsa": "Automātiski ielāpot RSA",
|
|
||||||
"use_proxy": "Izmantot iekšējo starpniekserveri",
|
|
||||||
"wipe_login": "Noslaucīt pieteikšanās kešatmiņu",
|
|
||||||
"horny_mode": "Uzbudināts režīms",
|
|
||||||
"auto_mongodb": "Automātiski startējiet MongoDB",
|
|
||||||
"un_elevated": "Palaist spēli bez paaugstinājuma (bez administratora)",
|
|
||||||
"redirect_more": "Arī novirzīt citas MHY spēles",
|
|
||||||
"web_cache": "Dzēsiet mapi WebCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"grasscutter_fullbuild": "Lejupielādējiet Grasscutter viss vienā",
|
|
||||||
"grasscutter_fullquest": "Lejupielādēt questing viss vienā",
|
|
||||||
"grasscutter_stable_data": "Lejupielādējiet Grasscutter stabilos datus",
|
"grasscutter_stable_data": "Lejupielādējiet Grasscutter stabilos datus",
|
||||||
"grasscutter_latest_data": "Lejupielādējiet Grasscutter jaunākos datus",
|
"grasscutter_latest_data": "Lejupielādējiet Grasscutter jaunākos datus",
|
||||||
"grasscutter_stable_data_update": "Atjauniniet Grasscutter stabilos datus",
|
"grasscutter_stable_data_update": "Atjauniniet Grasscutter stabilos datus",
|
||||||
"grasscutter_latest_data_update": "Atjauniniet Grasscutter jaunākos datus",
|
"grasscutter_latest_data_update": "Atjauniniet Grasscutter jaunākos datus",
|
||||||
"grasscutter_unstable": "Lejupielādēt Grasscutter stabilo",
|
"grasscutter_stable": "Lejupielādēt Grasscutter stabilo",
|
||||||
"grasscutter_latest": "Lejupielādēt Grasscutter jaunāko",
|
"grasscutter_latest": "Lejupielādēt Grasscutter jaunāko",
|
||||||
"grasscutter_unstable_update": "Atjauniet Grasscutter stabilo",
|
"grasscutter_stable_update": "Atjauniet Grasscutter stabilo",
|
||||||
"grasscutter_latest_update": "Atjauniet Grasscutter jaunāko",
|
"grasscutter_latest_update": "Atjauniet Grasscutter jaunāko",
|
||||||
"resources": "Lejupielādējiet Grasscutter resursi",
|
"resources": "Lejupielādējiet Grasscutter resursi"
|
||||||
"aio_header": "Lejupielādes viss vienā",
|
|
||||||
"individual_header": "Atsevišķu daļu lejupielādes:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "Lejupielādēt GIMI 3dmigoto"
|
|
||||||
},
|
},
|
||||||
"download_status": {
|
"download_status": {
|
||||||
"downloading": "Notiek lejupielāde",
|
"downloading": "Notiek lejupielāde",
|
||||||
@@ -62,8 +43,7 @@
|
|||||||
"components": {
|
"components": {
|
||||||
"select_file": "Izvēlēties failu vai mapu...",
|
"select_file": "Izvēlēties failu vai mapu...",
|
||||||
"select_folder": "Izvēlēties mapu...",
|
"select_folder": "Izvēlēties mapu...",
|
||||||
"download": "Lejupielādēt",
|
"download": "Lejupielādēt"
|
||||||
"delete": "Dzēst"
|
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"latest_commits": "Nesen kommitus",
|
"latest_commits": "Nesen kommitus",
|
||||||
@@ -73,12 +53,9 @@
|
|||||||
"port_help_text": "Pārliecinieties, vai tas ir Dispatch-servera ports, nevis spēļu servera ports. Tas gandrīz vienmēr ir '443'.",
|
"port_help_text": "Pārliecinieties, vai tas ir Dispatch-servera ports, nevis spēļu servera ports. Tas gandrīz vienmēr ir '443'.",
|
||||||
"game_help_text": "Lai spēlētu ar Grasscutter, jums nav jāizmanto atsevišķa kopija. Tas ir izveidots, lai pazeminātu versiju uz 2.6 vai ja jums nav instalēta spēle.",
|
"game_help_text": "Lai spēlētu ar Grasscutter, jums nav jāizmanto atsevišķa kopija. Tas ir izveidots, lai pazeminātu versiju uz 2.6 vai ja jums nav instalēta spēle.",
|
||||||
"gc_stable_jar": "Lejupielādējiet pašreizējo stabilo Grasscutter versiju, kuram ir jar failu un datu failus.",
|
"gc_stable_jar": "Lejupielādējiet pašreizējo stabilo Grasscutter versiju, kuram ir jar failu un datu failus.",
|
||||||
"gc_fullbuild": "Lejupielādējiet pilnu Grasscutter versiju, tostarp repozitorijus, krātuves un resursus. Viss ir gatavs, un no šīs izvēlnes nav nepieciešama nekāda cita lejupielāde.",
|
|
||||||
"gc_dev_jar": "Lejupielādējiet jaunāko izstrāde Grasscutter versiju, kuram ir jar failu un datu failus.",
|
"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_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.",
|
"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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
{
|
|
||||||
"lang_name": "Nederlands",
|
|
||||||
"main": {
|
|
||||||
"title": "Cultivation",
|
|
||||||
"launch_button": "Start",
|
|
||||||
"gc_enable": "Verbind Met Grasscutter",
|
|
||||||
"https_enable": "Gebruik HTTPS",
|
|
||||||
"ip_placeholder": "Server Address...",
|
|
||||||
"port_placeholder": "Poort...",
|
|
||||||
"files_downloading": "Bestanden Aan Downloaden: ",
|
|
||||||
"files_extracting": "Bestanden Uitpakken: ",
|
|
||||||
"game_path_notify": "Spelpad niet gevonden, denk eraan dit in te stellen in instellingen!"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"enabled": "Ingeschakeld",
|
|
||||||
"disabled": "Uitgeschakeld",
|
|
||||||
"game_path": "Spel Installatie Pad Instellen",
|
|
||||||
"game_executable": "Stel De Exe Van Het Spel In",
|
|
||||||
"recover_rsa": "Noodherstel Van De RSA",
|
|
||||||
"grasscutter_jar": "Stel De Grasscutter JAR In",
|
|
||||||
"toggle_encryption": "Versleuteling Inschakelen",
|
|
||||||
"install_certificate": "Proxy-certificaat installeren",
|
|
||||||
"java_path": "Aangepast Java-pad Instellen",
|
|
||||||
"grasscutter_with_game": "Start Automatisch Grasscutter Met Spel",
|
|
||||||
"language": "Selecteer Taal",
|
|
||||||
"background": "Aangepaste Achtergrond Instellen (link of afbeeldingsbestand)",
|
|
||||||
"use_theme_background": "Gebruik de achtergrond geleverd door het geselecteerde thema",
|
|
||||||
"theme": "Thema instellen",
|
|
||||||
"patch_rsa": "RSA Automatisch Bijwerken",
|
|
||||||
"use_proxy": "Gebruik Interne Proxy",
|
|
||||||
"wipe_login": "Login cache wissen",
|
|
||||||
"horny_mode": "Geile modus",
|
|
||||||
"auto_mongodb": "Start automatisch MongoDB",
|
|
||||||
"un_elevated": "Voer het spel uit zonder hoogtevrees (geen admin)",
|
|
||||||
"redirect_more": "Richt ook andere MHY-spellen",
|
|
||||||
"web_cache": "Verwijder de webCaches-map",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"grasscutter_fullbuild": "Grasscutter Alles-in-één Downloaden",
|
|
||||||
"grasscutter_fullquest": "Alles-in-één zoeken downloaden",
|
|
||||||
"grasscutter_stable_data": "Download Stabiele Gegevens Van Grasscutter",
|
|
||||||
"grasscutter_latest_data": "Download De Nieuwste Gegevens Van Grasscutter",
|
|
||||||
"grasscutter_stable_data_update": "Stabiele gegevens Van Grasscutter bijwerken",
|
|
||||||
"grasscutter_latest_data_update": "Nieuwste gegevens Van Grasscutter bijwerken",
|
|
||||||
"grasscutter_unstable": "Download Stabiele Versie Van Grasscutter",
|
|
||||||
"grasscutter_latest": "Download De Nieuwste Versie Van Grasscutter",
|
|
||||||
"grasscutter_unstable_update": "Update Grasscutter Naar De Stabiele Versie",
|
|
||||||
"grasscutter_latest_update": "Update Grasscutter Naar De Nieuwste Versie",
|
|
||||||
"resources": "Download Grasscutter bronnen",
|
|
||||||
"game": "Download Spel",
|
|
||||||
"aio_header": "Alles-in-één Downloads:",
|
|
||||||
"individual_header": "Downloads van afzonderlijke onderdelen:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "Download GIMI 3dmigoto"
|
|
||||||
},
|
|
||||||
"download_status": {
|
|
||||||
"downloading": "Aan Het Downloading",
|
|
||||||
"extracting": "Uitpakken",
|
|
||||||
"error": "Fout",
|
|
||||||
"finished": "Voltooid",
|
|
||||||
"stopped": "Gestopt"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "Select file or folder...",
|
|
||||||
"select_folder": "Select folder...",
|
|
||||||
"download": "Download",
|
|
||||||
"delete": "Verwijder",
|
|
||||||
"install": "Install"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "Recente Opdrachten",
|
|
||||||
"latest_version": "Nieuwste Versie"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "Zorg ervoor dat dit de Dispatch server poort is, niet de Game server poort. Dit is bijna altijd '443'.",
|
|
||||||
"game_help_text": "U hoeft geen aparte kopie te gebruiken om met Grasscutter te spelen. Dit is voor downgraden naar 2.6 of als u het spel niet geinstalleerd heeft.",
|
|
||||||
"gc_stable_jar": "Download de huidige stabiele Grasscutter build, die jar file en data bestanden bevat.",
|
|
||||||
"gc_fullbuild": "Download een volledige Grasscutter build, inclusief repo, jar en resources. Is volledig ingesteld en vereist geen andere downloads uit dit menu.",
|
|
||||||
"gc_dev_jar": "Download de laatste ontwikkeling Grasscutter build, die jar file en data bestanden bevat.",
|
|
||||||
"gc_stable_data": "Download de huidige stabiele versie van de Grasscutter data bestanden, die niet met een jar file komen. Dit is handig voor het bijwerken.",
|
|
||||||
"gc_dev_data": "Download de nieuwste versie van de Grasscutter data bestanden, die niet met een jar file komen. Dit is handig voor het bijwerken.",
|
|
||||||
"encryption": "Dit wordt meestal uitgeschakeld.",
|
|
||||||
"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.",
|
|
||||||
"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",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Stel Akebi Exe Bestand In",
|
|
||||||
"migoto": "Stel 3DMigoto Exe Bestand In",
|
|
||||||
"reshade": "Stel Reshade Injector In"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
{
|
|
||||||
"lang_name": "Polski",
|
|
||||||
"main": {
|
|
||||||
"title": "Cultivation",
|
|
||||||
"launch_button": "Uruchom",
|
|
||||||
"gc_enable": "Połącz z Grasscutter",
|
|
||||||
"https_enable": "Używaj HTTPS",
|
|
||||||
"ip_placeholder": "Adres Serwera...",
|
|
||||||
"port_placeholder": "Port...",
|
|
||||||
"files_downloading": "Pobierane pliki: ",
|
|
||||||
"files_extracting": "Wypakowywane pliki: ",
|
|
||||||
"game_path_notify": "Ścieżka gry nie znaleziona. Pamiętaj by ustawić ją w ustawieniach!"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"enabled": "Włączone",
|
|
||||||
"disabled": "Wyłączone",
|
|
||||||
"game_path": "Ustaw ścieżkę instalacji gry",
|
|
||||||
"game_command": "Komenda uruchamiania gry",
|
|
||||||
"game_executable": "Ustaw plik wykonywalny gry",
|
|
||||||
"recover_rsa": "Awaryjne usunięcie patcha RSA",
|
|
||||||
"grasscutter_jar": "Ustaw plik JAR Grasscuttera",
|
|
||||||
"toggle_encryption": "Włącz szyfrowanie",
|
|
||||||
"install_certificate": "Zainstaluj certyfikat proxy",
|
|
||||||
"java_path": "Ustaw własną ścieżkę Javy",
|
|
||||||
"grasscutter_with_game": "Automatycznie uruchom Grasscutter z grą",
|
|
||||||
"language": "Wybierz Język",
|
|
||||||
"background": "Ustaw własne tło (link lub plik graficzny)",
|
|
||||||
"use_theme_background": "Użyj tła dostarczonego przez wybrany motyw",
|
|
||||||
"theme": "Ustaw motyw",
|
|
||||||
"patch_rsa": "Automatycznie patchuj RSA",
|
|
||||||
"use_proxy": "Używaj wewnętrznego Proxy",
|
|
||||||
"wipe_login": "Wyczyść pamięć podręczną logowania",
|
|
||||||
"horny_mode": "Tryb 34",
|
|
||||||
"auto_mongodb": "Automatycznie uruchamiaj MongoDB",
|
|
||||||
"un_elevated": "Uruchamiaj grę bez uprawnień administratora/roota",
|
|
||||||
"redirect_more": "Przekieruj też inne gry MHY",
|
|
||||||
"check_aagl": "Więcej opcji znajdziesz w drugim launcherze",
|
|
||||||
"grasscutter_elevation": "Sposób uruchomienia GC na ograniczonym porcie",
|
|
||||||
"web_cache": "Usuń folder webCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"grasscutter_fullbuild": "Pobierz Grasscutter (wszystko w jednym)",
|
|
||||||
"grasscutter_fullquest": "Pobierz Questing (wszystko w jednym)",
|
|
||||||
"grasscutter_stable_data": "Pobierz stabilne dane Grasscuttera",
|
|
||||||
"grasscutter_latest_data": "Pobierz najnowsze dane Grasscuttera",
|
|
||||||
"grasscutter_stable_data_update": "Zaaktualizuj stabilne dane Grasscuttera",
|
|
||||||
"grasscutter_latest_data_update": "Zaaktualizuj najnowsze dane Grasscuttera",
|
|
||||||
"grasscutter_unstable": "Pobierz Grasscutter Questing",
|
|
||||||
"grasscutter_latest": "Pobierz Grasscutter Latest",
|
|
||||||
"grasscutter_unstable_update": "Zaaktualizuj Grasscutter Questing",
|
|
||||||
"grasscutter_latest_update": "Zaaktualizuj Grasscutter Latest",
|
|
||||||
"resources": "Pobierz zasoby Grasscuttera",
|
|
||||||
"game": "Pobierz grę",
|
|
||||||
"aio_header": "Grupowe pobierania:",
|
|
||||||
"individual_header": "Pojedyńcze pobierania:",
|
|
||||||
"mods_header": "Mody:",
|
|
||||||
"migoto": "Pobierz GIMI 3dmigoto"
|
|
||||||
},
|
|
||||||
"download_status": {
|
|
||||||
"downloading": "Pobieranie",
|
|
||||||
"extracting": "Wypakowywanie",
|
|
||||||
"error": "Błąd",
|
|
||||||
"finished": "Zakończono",
|
|
||||||
"stopped": "Zatrzymano"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "Wybierz plik lub folder...",
|
|
||||||
"select_folder": "Wybierz folder...",
|
|
||||||
"download": "Pobierz",
|
|
||||||
"delete": "Usuń",
|
|
||||||
"install": "Zainstaluj"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "Ostatnie Commity",
|
|
||||||
"latest_version": "Najnowsza Wersja"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "Upewnij się, że to jest port serwera Dispatch, a nie port serwera gry. To prawie zawsze '443'.",
|
|
||||||
"game_help_text": "Nie potrzebujesz osobnej kopii gry, żeby używać Grasscuttera. To służy do deaktualizowania do wersji 2.6 albo jeśli nie masz zainstalowanej gry.",
|
|
||||||
"gc_stable_jar": "Pobierz ostatni stabilny build Grasscuttera, który nie zawiera pliku jar i plików danych.",
|
|
||||||
"gc_fullbuild": "Pobierz pełen build Grasscuttera, wliczając repo, plik jar i zasoby. Jest w pełni ustawiony i nie wymaga żadnych innych pobierań z tego menu.",
|
|
||||||
"gc_dev_jar": "Pobierz najnowszy deweloperski build Grasscuttera, który nie zawiera pliku jar i plików danych.",
|
|
||||||
"gc_stable_data": "Pobierz ostatnie stabilne pliki danych Grasscuttera, które nie zawierają pliku jar. Ta opcja jest przydatna do aktualizowania.",
|
|
||||||
"gc_dev_data": "Pobierz najnowsze deweloperskie pliki danych Grasscuttera, które nie zawierają pliku jar. Ta opcja jest przydatna do aktualizowania.",
|
|
||||||
"encryption": "To zazwyczaj powinno być wyłączone.",
|
|
||||||
"resources": "One są potrzebne do uruchomienia serwera Grasscutter. Ten przycisk będzie szary, jeśli już będziesz miałx folder z zasobami",
|
|
||||||
"emergency_rsa": "Jeżeli coś poszło nie tak, wymuś usunięcie patcha RSA.",
|
|
||||||
"use_proxy": "Używaj wewnętrznego proxy Cultivation. To powinno być włączone, chyba że używasz czegoś jak np. Fiddler",
|
|
||||||
"patch_rsa": "Patchuj i odpatchuj RSA gry automatycznie. Jeżeli nie grasz w starą lub nieoficjalną wersję (3.0 lub starszą), to powinno być włączone.",
|
|
||||||
"add_delay": "Ustaw opóźnienie 3dmigoto loadera! \nTo powinno naprawić problemy z ładowaniem, ale doda małe opóźnienie do czasu ładowania 3dmigoto do gry. \nTeraz możecie uruchamiać grę z 3dmigoto.",
|
|
||||||
"migoto": "Do importowania modeli z GameBanana",
|
|
||||||
"grasscutter_elevation_help_text": "Metoda używana przez Grasscuttera do zbindowania portu 443 (co nie jest dozwolone dla zywkłych użytkowników w Linuxie)\nDostępne metody:\n Capability - daje wirtualnej maszynie Javy możliwość zbindowania portów poniżej 1024. To też pozwala wszystkim innym programom odpalonym na tej maszynie JVM zbindować te porty.\n Root - uruchamia GC jako root. To pozwala serwerowi GC, jego pluginom i maszynie JVM zrobić praktycznie wszystko, wliczając w to wysyłanie twoich nudesów do ABW, CBŚ, i innych trzyliterowych służb.\n None - czyli żadna metoda. Ta opcja wymaga zmiana portu Dispatch serwera GC."
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Ustaw plik wykonywalny Akebi/Acrepi",
|
|
||||||
"migoto": "Ustaw plik wykonywalny 3DMigoto",
|
|
||||||
"reshade": "Ustaw Reshade Injector"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
{
|
|
||||||
"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: ",
|
|
||||||
"game_path_notify": "Caminho do jogo não encontrado, lembre-se de defini-lo nas configurações!"
|
|
||||||
},
|
|
||||||
"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)",
|
|
||||||
"use_theme_background": "Use o plano de fundo fornecido pelo tema selecionado",
|
|
||||||
"theme": "Definir Tema",
|
|
||||||
"patch_rsa": "Automaticamente Corrigir RSA",
|
|
||||||
"use_proxy": "Usar Proxy Interno",
|
|
||||||
"wipe_login": "Limpar Cache de Login",
|
|
||||||
"horny_mode": "Modo com tesão",
|
|
||||||
"auto_mongodb": "Iniciar MongoDB Automaticamente",
|
|
||||||
"un_elevated": "Executar o jogo não-elevated (sem admin)",
|
|
||||||
"redirect_more": "Também redirecionar outros jogos MHY",
|
|
||||||
"web_cache": "Excluir pasta webCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"grasscutter_fullbuild": "Baixar o Grasscutter Tudo-em-Um",
|
|
||||||
"grasscutter_fullquest": "Baixar de missões em um só lugar",
|
|
||||||
"grasscutter_stable_data": "Baixar os Dados do Grasscutter Estável",
|
|
||||||
"grasscutter_latest_data": "Baixar os Dados do Grasscutter Mais Recente",
|
|
||||||
"grasscutter_stable_data_update": "Atualizar os Dados do Grasscutter Estável",
|
|
||||||
"grasscutter_latest_data_update": "Atualizar os Dados do Grasscutter Mais Recente",
|
|
||||||
"grasscutter_unstable": "Baixar o Grasscutter Estável",
|
|
||||||
"grasscutter_latest": "Baixar o Grasscutter Mais Recente",
|
|
||||||
"grasscutter_unstable_update": "Atualizar o Grasscutter Estável",
|
|
||||||
"grasscutter_latest_update": "Atualizar o Grasscutter Mais Recente",
|
|
||||||
"resources": "Baixar os Recursos do Grasscutter ",
|
|
||||||
"game": "Baixar o Jogo",
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +1,61 @@
|
|||||||
{
|
{
|
||||||
"lang_name": "Русский",
|
"lang_name": "Русский",
|
||||||
"main": {
|
"main": {
|
||||||
"title": "Cultivation",
|
"title": "Cultivation",
|
||||||
"launch_button": "Запустить",
|
"launch_button": "Запустить",
|
||||||
"gc_enable": "Подключиться с Grasscutter",
|
"gc_enable": "Подключиться с Grasscutter",
|
||||||
"https_enable": "Исп. HTTPS",
|
"https_enable": "Исп. HTTPS",
|
||||||
"ip_placeholder": "Айпи адрес...",
|
"ip_placeholder": "Айпи адрес...",
|
||||||
"port_placeholder": "Порт...",
|
"port_placeholder": "Порт...",
|
||||||
"files_downloading": "Файлов скачано: ",
|
"files_downloading": "Файлов скачано: ",
|
||||||
"files_extracting": "Извлечено файлов: ",
|
"files_extracting": "Извлечено файлов: "
|
||||||
"game_path_notify": "Путь к игре не найден, не забудьте установить его в настройках!"
|
},
|
||||||
},
|
"options": {
|
||||||
"options": {
|
"enabled": "Включено",
|
||||||
"enabled": "Включено",
|
"disabled": "Выключено",
|
||||||
"disabled": "Выключено",
|
"game_exec": "Установить исполняемый файл игры",
|
||||||
"game_path": "Установить путь к файлам игры",
|
"grasscutter_jar": "Установить Grasscutter JAR",
|
||||||
"game_executable": "Установить исполняемый файл игры",
|
"toggle_encryption": "Переключить шифрование",
|
||||||
"recover_rsa": "Принудительное удаление RSA",
|
"java_path": "Установить пользовательский путь Java",
|
||||||
"grasscutter_jar": "Установить Grasscutter JAR",
|
"grasscutter_with_game": "Автоматически запускать Grasscutter вместе с игрой",
|
||||||
"toggle_encryption": "Переключить шифрование",
|
"language": "Установить язык",
|
||||||
"install_certificate": "Установить сертификат для работы Прокси",
|
"background": "Установить свой фон (ссылка или файл)",
|
||||||
"java_path": "Установить пользовательский путь Java",
|
"theme": "Установить тему"
|
||||||
"grasscutter_with_game": "Автоматически запускать Grasscutter вместе с игрой",
|
},
|
||||||
"language": "Установить язык",
|
"downloads": {
|
||||||
"background": "Установить свой фон (ссылка или файл)",
|
"grasscutter_stable_data": "Скачать стабильные данные Grasscutter",
|
||||||
"use_theme_background": "Использовать фон из выбранной темы",
|
"grasscutter_latest_data": "Скачать последние данные Grasscutter",
|
||||||
"theme": "Установить тему",
|
"grasscutter_stable_data_update": "Обновить стабильные данные Grasscutter",
|
||||||
"patch_rsa": "Автоматическое исправление RSA",
|
"grasscutter_latest_data_update": "Обновить последние данные Grasscutter",
|
||||||
"use_proxy": "Использовать встроенный Прокси",
|
"grasscutter_stable": "Скачать стабильную версию Grasscutter",
|
||||||
"wipe_login": "Очистить кэш входа в систему",
|
"grasscutter_latest": "Скачать последнюю версию Grasscutter",
|
||||||
"horny_mode": "роговой режим",
|
"grasscutter_stable_update": "Обновить стабильную версию Grasscutter",
|
||||||
"auto_mongodb": "Автоматически запускать MongoDB",
|
"grasscutter_latest_update": "Обновить последнюю версию Grasscutter",
|
||||||
"un_elevated": "Запустите игру в неэлегантном режиме (без администратора)",
|
"resources": "Скачать ресурсы Grasscutter"
|
||||||
"redirect_more": "Также перенаправьте другие игры MHY",
|
},
|
||||||
"web_cache": "Удалить папку webCaches",
|
"download_status": {
|
||||||
"launch_args": "Launch Args"
|
"downloading": "Скачивание",
|
||||||
},
|
"extracting": "Извлечение",
|
||||||
"downloads": {
|
"error": "Ошибка",
|
||||||
"grasscutter_fullbuild": "Скачать все в одном Grasscutter",
|
"finished": "Закончено",
|
||||||
"grasscutter_fullquest": "Скачать квесты все в одном",
|
"stopped": "Остановлено"
|
||||||
"grasscutter_stable_data": "Скачать стабильные данные Grasscutter",
|
},
|
||||||
"grasscutter_latest_data": "Скачать последние данные Grasscutter",
|
"components": {
|
||||||
"grasscutter_stable_data_update": "Обновить стабильные данные Grasscutter",
|
"select_file": "Выберите файл или папку...",
|
||||||
"grasscutter_latest_data_update": "Обновить последние данные Grasscutter",
|
"select_folder": "Выберите папку...",
|
||||||
"grasscutter_unstable": "Скачать стабильную версию Grasscutter",
|
"download": "Скачать"
|
||||||
"grasscutter_latest": "Скачать последнюю версию Grasscutter",
|
},
|
||||||
"grasscutter_unstable_update": "Обновить стабильную версию Grasscutter",
|
"news": {
|
||||||
"grasscutter_latest_update": "Обновить последнюю версию Grasscutter",
|
"latest_commits": "Последние коммиты",
|
||||||
"resources": "Скачать ресурсы Grasscutter",
|
"latest_version": "Последняя версия"
|
||||||
"game": "Скачать Игру",
|
},
|
||||||
"aio_header": "Все в одной загрузке:",
|
"help": {
|
||||||
"individual_header": "загрузка отдельных частей:",
|
"port_help_text": "Убедитесь, что это порт Dispatch-сервера, не порт игрового сервера. Обычно это '443'.",
|
||||||
"mods_header": "Mods:",
|
"game_help_text": "Вам не нужно устанавливать еще одну копию, что бы играть с Grascutter. Это нужно или для версии 2.6, или если у Вас не установлена игра.",
|
||||||
"migoto": "Скачать GIMI 3dmigoto"
|
"gc_stable_jar": "Скачать последнюю стабильную версию Grasscutter, которая содержит jar файл и данные.",
|
||||||
},
|
"gc_dev_jar": "Скачать последнюю версию для разработки Grasscutter, которая содержит jar файл и данные.",
|
||||||
"download_status": {
|
"gc_stable_data": "Скачать стабильные данные Grasscutter, в которой нету jar файла. Это полезно для обновления.",
|
||||||
"downloading": "Скачивание",
|
"gc_dev_data": "Скачать последнюю версию для разработки Grasscutter, в которой нету jar файла. Это полезно для обновления.",
|
||||||
"extracting": "Извлечение",
|
"resources": "Это необходимо для запуска сервера Grasscutter. Эта кнопка будет серой, если у Вас уже есть не пустая папка с ресурсами."
|
||||||
"error": "Ошибка",
|
}
|
||||||
"finished": "Закончено",
|
}
|
||||||
"stopped": "Остановлено"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "Выберите файл или папку...",
|
|
||||||
"select_folder": "Выберите папку...",
|
|
||||||
"download": "Скачать",
|
|
||||||
"delete": "Удалить",
|
|
||||||
"install": "Установить"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "Последние коммиты",
|
|
||||||
"latest_version": "Последняя версия"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "Убедитесь, что это порт Dispatch-сервера, не порт игрового сервера. Обычно это '443'.",
|
|
||||||
"game_help_text": "Вам не нужно устанавливать еще одну копию, что бы играть с Grascutter. Это нужно или для версии 2.6, или если у Вас не установлена игра.",
|
|
||||||
"gc_stable_jar": "Скачать последнюю стабильную версию Grasscutter, которая содержит jar файл и данные.",
|
|
||||||
"gc_fullbuild": "Загрузите полную сборку Grasscutter, включая репо, jar и ресурсы. Полностью настроена и не требует других загрузок из этого меню.",
|
|
||||||
"gc_dev_jar": "Скачать последнюю версию для разработки Grasscutter, которая содержит jar файл и данные.",
|
|
||||||
"gc_stable_data": "Скачать стабильные данные Grasscutter, в которой нету jar файла. Это полезно для обновления.",
|
|
||||||
"gc_dev_data": "Скачать последнюю версию для разработки Grasscutter, в которой нету jar файла. Это полезно для обновления.",
|
|
||||||
"encryption": "Обычно это должно быть выключено.",
|
|
||||||
"resources": "Это необходимо для запуска сервера Grasscutter. Эта кнопка будет серой, если у Вас уже есть не пустая папка с ресурсами.",
|
|
||||||
"emergency_rsa": "Если что-то пошло не так, восстановит RSA до последней официальной версии.",
|
|
||||||
"use_proxy": "Использовать встроенный Прокси. Отключите если используете Fiddler или подобную программу",
|
|
||||||
"patch_rsa": "Патчит и восстанавливает RSA автоматически. Если вы не играете на старых/модифицированых версиях, или сами в ручную патчите Метаданные, эта опция должна быть включена.",
|
|
||||||
"add_delay": "Установите задержку в загрузчике 3dmigoto! \nЭто должно исправить проблемы с загрузкой, но добавит небольшую задержку в момент загрузки 3dmigoto при запуске игры. \nТеперь вы снова можете запускать игру с помощью 3dmigoto.",
|
|
||||||
"migoto": "Для импорта моделей из GameBanana"
|
|
||||||
},
|
|
||||||
"swag": {
|
|
||||||
"akebi_name": "Akebi",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Путь к исполняемому файлу Akebi",
|
|
||||||
"migoto": "Путь к исполняемому файлу 3DMigoto ",
|
|
||||||
"reshade": "Путь к инжектору Reshade"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
{
|
|
||||||
"lang_name": "Tiếng Việt",
|
|
||||||
"main": {
|
|
||||||
"title": "Cultivation",
|
|
||||||
"launch_button": "Khởi Chạy",
|
|
||||||
"gc_enable": "Kết nối qua Grasscutter",
|
|
||||||
"https_enable": "Dùng HTTPS",
|
|
||||||
"ip_placeholder": "Địa chỉ máy chủ...",
|
|
||||||
"port_placeholder": "Cổng...",
|
|
||||||
"files_downloading": "Đang tải tập tin: ",
|
|
||||||
"files_extracting": "Đang giải nén tập tin: ",
|
|
||||||
"game_path_notify": "Không tìm thấy đường dẫn trò chơi, hãy nhớ đặt nó trong cài đặt!"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"enabled": "Bật",
|
|
||||||
"disabled": "Tắt",
|
|
||||||
"game_path": "Đường dẫn cài game",
|
|
||||||
"game_command": "Lệnh khởi chạy game",
|
|
||||||
"game_executable": "Tập tin thực thi game",
|
|
||||||
"recover_rsa": "Khôi phục RSA khẩn cấp",
|
|
||||||
"grasscutter_jar": "Tập tin JAR Grasscutter",
|
|
||||||
"toggle_encryption": "Bật/tắt mã hóa",
|
|
||||||
"install_certificate": "Cài chứng chỉ proxy",
|
|
||||||
"java_path": "Đường dẫn Java tùy chỉnh",
|
|
||||||
"grasscutter_with_game": "Tự động chạy Grasscutter cùng với game",
|
|
||||||
"language": "Ngôn ngữ",
|
|
||||||
"background": "Hình nền tùy chỉnh (liên kết hoặc tập tin hình ảnh)",
|
|
||||||
"use_theme_background": "Sử dụng nền được cung cấp bởi chủ đề đã chọn",
|
|
||||||
"theme": "Giao diện",
|
|
||||||
"patch_rsa": "Tự động vá RSA",
|
|
||||||
"use_proxy": "Sử dụng proxy nội bộ",
|
|
||||||
"wipe_login": "Tẩy sạch cache đăng nhập",
|
|
||||||
"horny_mode": "Chế độ hứng tình",
|
|
||||||
"auto_mongodb": "Tự động khởi động MongoDB",
|
|
||||||
"un_elevated": "Chạy trò chơi không nâng cao (không có quản trị viên)",
|
|
||||||
"redirect_more": "Đồng thời chuyển hướng các trò chơi MHY khác",
|
|
||||||
"web_cache": "Xóa thư mục webCaches",
|
|
||||||
"launch_args": "Launch Args"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"grasscutter_fullbuild": "Tải Grasscutter tất cả trong một",
|
|
||||||
"grasscutter_fullquest": "Tải xuống truy vấn tất cả trong một",
|
|
||||||
"grasscutter_stable_data": "Tải dữ liệu Grasscutter bản ổn định",
|
|
||||||
"grasscutter_latest_data": "Tải dữ liệu Grasscutter bản mới nhất",
|
|
||||||
"grasscutter_stable_data_update": "Cập nhật dữ liệu Grasscutter bản ổn định",
|
|
||||||
"grasscutter_latest_data_update": "Cập nhật dữ liệu Grasscutter bản mới nhất",
|
|
||||||
"grasscutter_unstable": "Tải Grasscutter bản ổn định",
|
|
||||||
"grasscutter_latest": "Tải Grasscutter bản mới nhất",
|
|
||||||
"grasscutter_unstable_update": "Cập nhật Grasscutter bản ổn định",
|
|
||||||
"grasscutter_latest_update": "Cập nhật Grasscutter bản mới nhất",
|
|
||||||
"resources": "Tải tài nguyên Grasscutter",
|
|
||||||
"game": "Tải game",
|
|
||||||
"aio_header": "Tải xuống tất cả trong một:",
|
|
||||||
"individual_header": "Tải xuống từng phần:",
|
|
||||||
"mods_header": "Mods:",
|
|
||||||
"migoto": "Tải GIMI 3dmigoto"
|
|
||||||
},
|
|
||||||
"download_status": {
|
|
||||||
"downloading": "Đang tải",
|
|
||||||
"extracting": "Đang giải nén",
|
|
||||||
"error": "Lỗi",
|
|
||||||
"finished": "Đã hoàn thành",
|
|
||||||
"stopped": "Đã dừng"
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"select_file": "Chọn tập tin hoặc thư mục...",
|
|
||||||
"select_folder": "Chọn thư mục...",
|
|
||||||
"download": "Tải",
|
|
||||||
"delete": "Xóa bỏ",
|
|
||||||
"install": "Cài"
|
|
||||||
},
|
|
||||||
"news": {
|
|
||||||
"latest_commits": "Thay Đổi Gần Đây",
|
|
||||||
"latest_version": "Phiên Bản Mới Nhất"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"port_help_text": "Hãy đảm bảo đây là cổng của máy chủ Dispatch, không phải cổng của máy chủ game. Thường sẽ là '443'.",
|
|
||||||
"game_help_text": "Bạn không cần phải sử dụng một bản sao riêng để chơi với Grasscutter. Việc này chỉ xảy ra nếu bạn hạ phiên bản xuống 2.6 hoặc chưa cài game.",
|
|
||||||
"gc_stable_jar": "Tải xuống phiên bản ổn định của Grasscutter, bao gồm tập tin jar và các tệp dữ liệu.",
|
|
||||||
"gc_fullbuild": "Tải xuống bản dựng Grasscutter đầy đủ, bao gồm repo, jar và tài nguyên. Được thiết lập đầy đủ và không yêu cầu bất kỳ tải xuống nào khác từ menu này",
|
|
||||||
"gc_dev_jar": "Tải xuống phiên bản phát triển mới nhất của Grasscutter, bao gồm tập tin jar và các tệp dữ liệu.",
|
|
||||||
"gc_stable_data": "Tải xuống tệp dữ liệu phiên bản ổn định hiện hành của Grasscutter. Bản này không đi kèm với tập tin jar, hữu dụng khi muốn cập nhật.",
|
|
||||||
"gc_dev_data": "Tải xuống tệp dữ liệu phiên bản mới nhất của Grasscutter. Bản này không đi kèm với tập tin jar, hữu dụng khi muốn cập nhật.",
|
|
||||||
"encryption": "Mục này nên được tắt.",
|
|
||||||
"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.",
|
|
||||||
"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",
|
|
||||||
"migoto_name": "Migoto",
|
|
||||||
"reshade_name": "Reshade",
|
|
||||||
"akebi": "Tập tin thực thi Akebi",
|
|
||||||
"migoto": "Tập tin thực thi 3dMigoto",
|
|
||||||
"reshade": "Tập tin inject Reshade"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
newline_style = "Unix"
|
|
||||||
tab_spaces = 2
|
|
||||||
use_field_init_shorthand = true
|
|
||||||
use_try_shorthand = true
|
|
||||||
147
src-tauri/src/downloader.rs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::cmp::min;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
|
||||||
|
// This will create a downloads list that will be used to check if we should continue downloading the file
|
||||||
|
lazy_static! {
|
||||||
|
static ref DOWNLOADS: Mutex<Vec<String>> = {
|
||||||
|
let m = Vec::new();
|
||||||
|
Mutex::new(m)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lots of help from: https://gist.github.com/giuliano-oliveira/4d11d6b3bb003dba3a1b53f43d81b30d
|
||||||
|
// and docs ofc
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn download_file(window: tauri::Window, url: &str, path: &str) -> Result<(), String> {
|
||||||
|
// Reqwest setup
|
||||||
|
let res = match reqwest::get(url)
|
||||||
|
.await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(_e) => {
|
||||||
|
emit_download_err(window, format!("Failed to request {}", url), path);
|
||||||
|
return Err(format!("Failed to request {}", url));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let total_size = res
|
||||||
|
.content_length()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
// Create file path
|
||||||
|
let mut file = match File::create(path) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(_e) => {
|
||||||
|
emit_download_err(window, format!("Failed to create file '{}'", path), path);
|
||||||
|
return Err(format!("Failed to create file '{}'", path));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut downloaded: u64 = 0;
|
||||||
|
let mut total_downloaded: u64 = 0;
|
||||||
|
|
||||||
|
// File stream
|
||||||
|
let mut stream = res.bytes_stream();
|
||||||
|
|
||||||
|
// Assuming all goes well, add to the downloads list
|
||||||
|
DOWNLOADS.lock().unwrap().push(path.to_string());
|
||||||
|
|
||||||
|
// Await chunks
|
||||||
|
while let Some(item) = stream.next().await {
|
||||||
|
// Stop the loop if the download is removed from the list
|
||||||
|
if !DOWNLOADS.lock().unwrap().contains(&path.to_string()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chunk = match item {
|
||||||
|
Ok(itm) => itm,
|
||||||
|
Err(e) => {
|
||||||
|
emit_download_err(window, format!("Error while downloading file"), path);
|
||||||
|
return Err(format!("Error while downloading file: {}", e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let vect = &chunk.to_vec()[..];
|
||||||
|
|
||||||
|
// Write bytes
|
||||||
|
match file.write_all(&vect) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
emit_download_err(window, format!("Error while writing file"), path);
|
||||||
|
return Err(format!("Error while writing file: {}", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New progress
|
||||||
|
let new = min(downloaded + (chunk.len() as u64), total_size);
|
||||||
|
downloaded = new;
|
||||||
|
|
||||||
|
total_downloaded = total_downloaded + chunk.len() as u64;
|
||||||
|
|
||||||
|
let mut res_hash = std::collections::HashMap::new();
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"downloaded".to_string(),
|
||||||
|
downloaded.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"total".to_string(),
|
||||||
|
total_size.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"path".to_string(),
|
||||||
|
path.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"total_downloaded".to_string(),
|
||||||
|
total_downloaded.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create event to send to frontend
|
||||||
|
window.emit("download_progress", &res_hash).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// One more "finish" event
|
||||||
|
window.emit("download_finished", &path).unwrap();
|
||||||
|
|
||||||
|
// We are done
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emit_download_err(window: tauri::Window, msg: std::string::String, path: &str) {
|
||||||
|
let mut res_hash = std::collections::HashMap::new();
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"error".to_string(),
|
||||||
|
msg.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"path".to_string(),
|
||||||
|
path.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.emit("download_error", &res_hash).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn stop_download(path: String) {
|
||||||
|
// Check if the path is in the downloads list
|
||||||
|
let mut downloads = DOWNLOADS.lock().unwrap();
|
||||||
|
let index = downloads.iter().position(|x| x == &path);
|
||||||
|
|
||||||
|
// Remove from list
|
||||||
|
if let Some(i) = index {
|
||||||
|
downloads.remove(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the file from disk
|
||||||
|
if let Err(_e) = std::fs::remove_file(&path) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src-tauri/src/file_helpers.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn rename(path: String, new_name: String) {
|
||||||
|
let mut new_path = path.clone();
|
||||||
|
|
||||||
|
// Check if file/folder to replace exists
|
||||||
|
if !fs::metadata(&path).is_ok() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if path uses forward or back slashes
|
||||||
|
if new_path.contains("\\") {
|
||||||
|
new_path = path.replace("\\", "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
let path_replaced = &path.replace(&new_path.split("/").last().unwrap(), &new_name);
|
||||||
|
|
||||||
|
fs::rename(path, &path_replaced).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn dir_exists(path: &str) -> bool {
|
||||||
|
return fs::metadata(&path).is_ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn dir_is_empty(path: &str) -> bool {
|
||||||
|
return fs::read_dir(&path).unwrap().count() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn dir_delete(path: &str) {
|
||||||
|
fs::remove_dir_all(path).unwrap();
|
||||||
|
}
|
||||||
56
src-tauri/src/lang.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use crate::system_helpers::*;
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_lang(window: tauri::Window, lang: String) -> String {
|
||||||
|
let lang = lang.to_lowercase();
|
||||||
|
|
||||||
|
// Send contents of language file back
|
||||||
|
let lang_path: PathBuf = [&install_location(), "lang", &format!("{}.json", lang)].iter().collect();
|
||||||
|
let contents = match std::fs::read_to_string(&lang_path) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
emit_lang_err(window, format!("Failed to read language file: {}", e));
|
||||||
|
return "".to_string();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_languages() -> std::collections::HashMap<String, String> {
|
||||||
|
// for each lang file, set the key as the filename and the value as the lang_name contained in the file
|
||||||
|
let mut languages = std::collections::HashMap::new();
|
||||||
|
|
||||||
|
let mut lang_files = std::fs::read_dir(Path::new(&install_location()).join("lang")).unwrap();
|
||||||
|
|
||||||
|
while let Some(entry) = lang_files.next() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
|
let content = match std::fs::read_to_string(&path) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to read language file: {}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
languages.insert(filename.to_string(), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return languages;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emit_lang_err(window: tauri::Window, msg: std::string::String) {
|
||||||
|
let mut res_hash = std::collections::HashMap::new();
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"error".to_string(),
|
||||||
|
msg.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.emit("lang_error", &res_hash).unwrap();
|
||||||
|
}
|
||||||
234
src-tauri/src/main.rs
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
#![cfg_attr(
|
||||||
|
all(not(debug_assertions), target_os = "windows"),
|
||||||
|
windows_subsystem = "windows"
|
||||||
|
)]
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::{sync::Mutex, collections::HashMap};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use std::thread;
|
||||||
|
use sysinfo::{System, SystemExt};
|
||||||
|
use structs::{APIQuery};
|
||||||
|
|
||||||
|
mod structs;
|
||||||
|
mod system_helpers;
|
||||||
|
mod file_helpers;
|
||||||
|
mod unzip;
|
||||||
|
mod downloader;
|
||||||
|
mod lang;
|
||||||
|
mod proxy;
|
||||||
|
mod web;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref WATCH_GAME_PROCESS: Mutex<String> = {
|
||||||
|
let m = "".to_string();
|
||||||
|
Mutex::new(m)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Start the game process watcher.
|
||||||
|
process_watcher();
|
||||||
|
|
||||||
|
// Make BG folder if it doesn't exist.
|
||||||
|
let bg_folder: PathBuf = [&system_helpers::install_location(), "bg"].iter().collect();
|
||||||
|
std::fs::create_dir_all(&bg_folder).unwrap();
|
||||||
|
|
||||||
|
tauri::Builder::default()
|
||||||
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
enable_process_watcher,
|
||||||
|
connect,
|
||||||
|
disconnect,
|
||||||
|
req_get,
|
||||||
|
get_bg_file,
|
||||||
|
is_game_running,
|
||||||
|
get_theme_list,
|
||||||
|
system_helpers::run_command,
|
||||||
|
system_helpers::run_program,
|
||||||
|
system_helpers::run_jar,
|
||||||
|
system_helpers::open_in_browser,
|
||||||
|
system_helpers::copy_file,
|
||||||
|
system_helpers::install_location,
|
||||||
|
system_helpers::is_elevated,
|
||||||
|
proxy::set_proxy_addr,
|
||||||
|
proxy::generate_ca_files,
|
||||||
|
unzip::unzip,
|
||||||
|
file_helpers::rename,
|
||||||
|
file_helpers::dir_exists,
|
||||||
|
file_helpers::dir_is_empty,
|
||||||
|
file_helpers::dir_delete,
|
||||||
|
downloader::download_file,
|
||||||
|
downloader::stop_download,
|
||||||
|
lang::get_lang,
|
||||||
|
lang::get_languages,
|
||||||
|
web::valid_url
|
||||||
|
])
|
||||||
|
.run(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_watcher() {
|
||||||
|
// Every 5 seconds, see if the game process is still running.
|
||||||
|
// If it is not, then we assume the game has closed and disable the proxy
|
||||||
|
// to prevent any requests from being sent to the game.
|
||||||
|
|
||||||
|
// Start a thread so as to not block the main thread.
|
||||||
|
thread::spawn(|| {
|
||||||
|
let mut system = System::new_all();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Refresh system info
|
||||||
|
system.refresh_all();
|
||||||
|
|
||||||
|
// Grab the game process name
|
||||||
|
let proc = WATCH_GAME_PROCESS.lock().unwrap().to_string();
|
||||||
|
|
||||||
|
if !&proc.is_empty() {
|
||||||
|
let proc_with_name = system.processes_by_exact_name(&proc);
|
||||||
|
let mut exists = false;
|
||||||
|
|
||||||
|
for _p in proc_with_name {
|
||||||
|
exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the game process closes, disable the proxy.
|
||||||
|
if !exists {
|
||||||
|
*WATCH_GAME_PROCESS.lock().unwrap() = "".to_string();
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread::sleep(std::time::Duration::from_secs(5));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn is_game_running() -> bool {
|
||||||
|
// Grab the game process name
|
||||||
|
let proc = WATCH_GAME_PROCESS.lock().unwrap().to_string();
|
||||||
|
|
||||||
|
return !proc.is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn enable_process_watcher(process: String) {
|
||||||
|
*WATCH_GAME_PROCESS.lock().unwrap() = process;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn connect(port: u16, certificate_path: String) {
|
||||||
|
// Log message to console.
|
||||||
|
println!("Connecting to proxy...");
|
||||||
|
|
||||||
|
// Change proxy settings.
|
||||||
|
proxy::connect_to_proxy(port);
|
||||||
|
|
||||||
|
// Create and start a proxy.
|
||||||
|
proxy::create_proxy(port, certificate_path).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn disconnect() {
|
||||||
|
// Log message to console.
|
||||||
|
println!("Disconnecting from proxy...");
|
||||||
|
|
||||||
|
// Change proxy settings.
|
||||||
|
proxy::disconnect_from_proxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn req_get(url: String) -> String {
|
||||||
|
// Send a GET request to the specified URL.
|
||||||
|
let response = web::query(&url.to_string()).await;
|
||||||
|
|
||||||
|
// Send the response body back to the client.
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn get_theme_list(data_dir: String) -> Vec<HashMap<String, String>> {
|
||||||
|
let theme_loc = format!("{}/themes", data_dir);
|
||||||
|
|
||||||
|
// Ensure folder exists
|
||||||
|
if !std::path::Path::new(&theme_loc).exists() {
|
||||||
|
std::fs::create_dir_all(&theme_loc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read each index.json folder in each theme folder
|
||||||
|
let mut themes = Vec::new();
|
||||||
|
|
||||||
|
for entry in std::fs::read_dir(&theme_loc).unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
let index_path = format!("{}/index.json", path.to_str().unwrap());
|
||||||
|
|
||||||
|
if std::path::Path::new(&index_path).exists() {
|
||||||
|
let theme_json = std::fs::read_to_string(&index_path).unwrap();
|
||||||
|
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
map.insert("json".to_string(), theme_json);
|
||||||
|
map.insert("path".to_string(), path.to_str().unwrap().to_string());
|
||||||
|
|
||||||
|
// Push key-value pair containing "json" and "path"
|
||||||
|
themes.push(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
// TODO: Replace with downloading the background file & saving it.
|
||||||
|
async fn get_bg_file(bg_path: String, appdata: String) -> String {
|
||||||
|
let copy_loc = appdata;
|
||||||
|
let query = web::query("https://api.grasscutter.io/cultivation/query").await;
|
||||||
|
let response_data: APIQuery = match serde_json::from_str(&query) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to parse response: {}", e);
|
||||||
|
return "".to_string();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let file_name = response_data.bg_file.to_string();
|
||||||
|
|
||||||
|
// First we see if the file already exists in our local bg folder.
|
||||||
|
if file_helpers::dir_exists(format!("{}\\bg\\{}", copy_loc, file_name).as_str()) {
|
||||||
|
return format!("{}\\{}", copy_loc, response_data.bg_file.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we check if the bg folder, which is one directory above the game_path, exists.
|
||||||
|
let bg_img_path = format!("{}\\{}", bg_path.clone().to_string(), file_name.as_str());
|
||||||
|
|
||||||
|
// If it doesn't, then we do not have backgrounds to grab.
|
||||||
|
if !file_helpers::dir_exists(&bg_path) {
|
||||||
|
return "".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// BG folder does exist, lets see if the image exists.
|
||||||
|
if !file_helpers::dir_exists(&bg_img_path) {
|
||||||
|
// Image doesn't exist
|
||||||
|
return "".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The image exists, lets copy it to our local '\bg' folder.
|
||||||
|
let bg_img_path_local = format!("{}\\bg\\{}", copy_loc, file_name.as_str());
|
||||||
|
|
||||||
|
return match std::fs::copy(bg_img_path, bg_img_path_local) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Copy was successful, lets return true.
|
||||||
|
format!("{}\\{}", copy_loc, response_data.bg_file.as_str())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Copy failed, lets return false
|
||||||
|
println!("Failed to copy background image: {}", e);
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
212
src-tauri/src/proxy.rs
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Built on example code from:
|
||||||
|
* https://github.com/omjadas/hudsucker/blob/main/examples/log.rs
|
||||||
|
*/
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::{sync::Mutex, str::FromStr};
|
||||||
|
|
||||||
|
use rcgen::*;
|
||||||
|
use hudsucker::{
|
||||||
|
async_trait::async_trait,
|
||||||
|
certificate_authority::RcgenAuthority,
|
||||||
|
hyper::{Body, Request, Response},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::path::Path;
|
||||||
|
use registry::{Hive, Data, Security};
|
||||||
|
|
||||||
|
use rustls_pemfile as pemfile;
|
||||||
|
use tauri::http::Uri;
|
||||||
|
use crate::system_helpers::run_command;
|
||||||
|
|
||||||
|
async fn shutdown_signal() {
|
||||||
|
tokio::signal::ctrl_c().await
|
||||||
|
.expect("Failed to install CTRL+C signal handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global ver for getting server address.
|
||||||
|
lazy_static! {
|
||||||
|
static ref SERVER: Mutex<String> = {
|
||||||
|
let m = "http://localhost:443".to_string();
|
||||||
|
Mutex::new(m)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ProxyHandler;
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn set_proxy_addr(addr: String) {
|
||||||
|
*SERVER.lock().unwrap() = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl HttpHandler for ProxyHandler {
|
||||||
|
async fn handle_request(&mut self,
|
||||||
|
_context: &HttpContext,
|
||||||
|
mut request: Request<Body>,
|
||||||
|
) -> RequestOrResponse {
|
||||||
|
let uri = request.uri().to_string();
|
||||||
|
let uri_path = request.uri().path();
|
||||||
|
|
||||||
|
if uri.contains("hoyoverse.com") || uri.contains("mihoyo.com") || uri.contains("yuanshen.com") {
|
||||||
|
// Create new URI.
|
||||||
|
let new_uri = Uri::from_str(format!("{}{}", SERVER.lock().unwrap(), uri_path).as_str()).unwrap();
|
||||||
|
// Set request URI to the new one.
|
||||||
|
*request.uri_mut() = new_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestOrResponse::Request(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_response(&mut self,
|
||||||
|
_context: &HttpContext,
|
||||||
|
response: Response<Body>,
|
||||||
|
) -> Response<Body> { response }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts an HTTP(S) proxy server.
|
||||||
|
*/
|
||||||
|
pub async fn create_proxy(proxy_port: u16, certificate_path: String) {
|
||||||
|
// Get the certificate and private key.
|
||||||
|
let mut private_key_bytes: &[u8] = &fs::read(format!("{}\\private.key", certificate_path)).expect("Could not read private key");
|
||||||
|
let mut ca_cert_bytes: &[u8] = &fs::read(format!("{}\\cert.crt", certificate_path)).expect("Could not read certificate");
|
||||||
|
|
||||||
|
// Parse the private key and certificate.
|
||||||
|
let private_key = rustls::PrivateKey(
|
||||||
|
pemfile::pkcs8_private_keys(&mut private_key_bytes)
|
||||||
|
.expect("Failed to parse private key")
|
||||||
|
.remove(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
let ca_cert = rustls::Certificate(
|
||||||
|
pemfile::certs(&mut ca_cert_bytes)
|
||||||
|
.expect("Failed to parse CA certificate")
|
||||||
|
.remove(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the certificate authority.
|
||||||
|
let authority = RcgenAuthority::new(private_key, ca_cert, 1_000)
|
||||||
|
.expect("Failed to create Certificate Authority");
|
||||||
|
|
||||||
|
// Create an instance of the proxy.
|
||||||
|
let proxy = ProxyBuilder::new()
|
||||||
|
.with_addr(SocketAddr::from(([0, 0, 0, 0], proxy_port)))
|
||||||
|
.with_rustls_client()
|
||||||
|
.with_ca(authority)
|
||||||
|
.with_http_handler(ProxyHandler)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Start the proxy.
|
||||||
|
tokio::spawn(proxy.start(shutdown_signal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the local HTTP(S) proxy server.
|
||||||
|
*/
|
||||||
|
pub fn connect_to_proxy(proxy_port: u16) {
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
// Create 'ProxyServer' string.
|
||||||
|
let server_string: String = format!("http=127.0.0.1:{};https=127.0.0.1:{}", proxy_port, proxy_port);
|
||||||
|
|
||||||
|
// Fetch the 'Internet Settings' registry key.
|
||||||
|
let settings = Hive::CurrentUser.open(r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", Security::Write).unwrap();
|
||||||
|
|
||||||
|
// Set registry values.
|
||||||
|
settings.set_value("ProxyServer", &Data::String(server_string.parse().unwrap())).unwrap();
|
||||||
|
settings.set_value("ProxyEnable", &Data::U32(1)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Connected to the proxy.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects from the local HTTP(S) proxy server.
|
||||||
|
*/
|
||||||
|
pub fn disconnect_from_proxy() {
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
// Fetch the 'Internet Settings' registry key.
|
||||||
|
let settings = Hive::CurrentUser.open(r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", Security::Write).unwrap();
|
||||||
|
|
||||||
|
// Set registry values.
|
||||||
|
settings.set_value("ProxyEnable", &Data::U32(0)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Disconnected from proxy.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates a private key and certificate used by the certificate authority.
|
||||||
|
* Additionally installs the certificate and private key in the Root CA store.
|
||||||
|
* Source: https://github.com/zu1k/good-mitm/raw/master/src/ca/gen.rs
|
||||||
|
*/
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn generate_ca_files(path: &Path) {
|
||||||
|
let mut params = CertificateParams::default();
|
||||||
|
let mut details = DistinguishedName::new();
|
||||||
|
|
||||||
|
// Set certificate details.
|
||||||
|
details.push(DnType::CommonName, "Cultivation");
|
||||||
|
details.push(DnType::OrganizationName, "Grasscutters");
|
||||||
|
details.push(DnType::CountryName, "CN");
|
||||||
|
details.push(DnType::LocalityName, "CN");
|
||||||
|
|
||||||
|
// Set details in the parameter.
|
||||||
|
params.distinguished_name = details;
|
||||||
|
// Set other properties.
|
||||||
|
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
|
||||||
|
params.key_usages = vec![
|
||||||
|
KeyUsagePurpose::DigitalSignature,
|
||||||
|
KeyUsagePurpose::KeyCertSign,
|
||||||
|
KeyUsagePurpose::CrlSign
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create certificate.
|
||||||
|
let cert = Certificate::from_params(params).unwrap();
|
||||||
|
let cert_crt = cert.serialize_pem().unwrap();
|
||||||
|
let private_key = cert.serialize_private_key_pem();
|
||||||
|
|
||||||
|
// Make certificate directory.
|
||||||
|
let cert_dir = path.join("ca");
|
||||||
|
match fs::create_dir(&cert_dir) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => {
|
||||||
|
println!("{}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write the certificate to a file.
|
||||||
|
let cert_path = cert_dir.join("cert.crt");
|
||||||
|
match fs::write(&cert_path, cert_crt) {
|
||||||
|
Ok(_) => println!("Wrote certificate to {}", cert_path.to_str().unwrap()),
|
||||||
|
Err(e) => println!("Error writing certificate to {}: {}", cert_path.to_str().unwrap(), e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the private key to a file.
|
||||||
|
let private_key_path = cert_dir.join("private.key");
|
||||||
|
match fs::write(&private_key_path, private_key) {
|
||||||
|
Ok(_) => println!("Wrote private key to {}", private_key_path.to_str().unwrap()),
|
||||||
|
Err(e) => println!("Error writing private key to {}: {}", private_key_path.to_str().unwrap(), e),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install certificate into the system's Root CA store.
|
||||||
|
install_ca_files(&cert_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempts to install the certificate authority's certificate into the Root CA store.
|
||||||
|
*/
|
||||||
|
pub fn install_ca_files(cert_path: &Path) {
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
run_command("certutil", vec!["-user", "-addstore", "Root", cert_path.to_str().unwrap()]);
|
||||||
|
} else {
|
||||||
|
run_command("security", vec!["add-trusted-cert", "-d", "-r", "trustRoot", "-k", "/Library/Keychains/System.keychain", cert_path.to_str().unwrap()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Installed certificate.");
|
||||||
|
}
|
||||||
8
src-tauri/src/structs.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub(crate) struct APIQuery {
|
||||||
|
pub bg_file: String,
|
||||||
|
}
|
||||||
82
src-tauri/src/system_helpers.rs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
|
||||||
|
use std::thread;
|
||||||
|
use tauri;
|
||||||
|
use open;
|
||||||
|
use duct::cmd;
|
||||||
|
|
||||||
|
use crate::file_helpers;
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn run_program(path: String) {
|
||||||
|
// Open the program from the specified path.
|
||||||
|
|
||||||
|
// Open in new thread to prevent blocking.
|
||||||
|
thread::spawn(move || {
|
||||||
|
open::that(&path).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn run_command(program: &str, args: Vec<&str>) {
|
||||||
|
cmd(program, args).run()
|
||||||
|
.expect("Failed to run command");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn run_jar(path: String, execute_in: String, java_path: String) {
|
||||||
|
let command = if java_path.is_empty() {
|
||||||
|
format!("java -jar \"{}\"", path)
|
||||||
|
} else {
|
||||||
|
format!("\"{}\" -jar \"{}\"", java_path, path)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the program from the specified path.
|
||||||
|
match open::with(format!("/k cd /D \"{}\" & {}", &execute_in, &command).to_string(), "C:\\Windows\\System32\\cmd.exe") {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => println!("Failed to open jar ({} from {}): {}", &path, &execute_in, e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn open_in_browser(url: String) {
|
||||||
|
// Open the URL in the default browser.
|
||||||
|
match open::that(url) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => println!("Failed to open URL: {}", e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn copy_file(path: String, new_path: String) -> bool {
|
||||||
|
let filename = &path.split("/").last().unwrap();
|
||||||
|
let mut new_path_buf = std::path::PathBuf::from(&new_path);
|
||||||
|
|
||||||
|
// If the new path doesn't exist, create it.
|
||||||
|
if !file_helpers::dir_exists(new_path_buf.pop().to_string().as_str()) {
|
||||||
|
std::fs::create_dir_all(&new_path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy old to new
|
||||||
|
match std::fs::copy(&path, format!("{}/{}", new_path, filename)) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to copy file: {}", e);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn install_location() -> String {
|
||||||
|
let mut exe_path = std::env::current_exe().unwrap();
|
||||||
|
|
||||||
|
// Get the path to the executable.
|
||||||
|
exe_path.pop();
|
||||||
|
|
||||||
|
return exe_path.to_str().unwrap().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn is_elevated() -> bool {
|
||||||
|
return is_elevated::is_elevated();
|
||||||
|
}
|
||||||
70
src-tauri/src/unzip.rs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
use zip_extract;
|
||||||
|
use zip;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn unzip(window: tauri::Window, zipfile: String, destpath: String) {
|
||||||
|
// Read file TODO: replace test file
|
||||||
|
let f = match File::open(&zipfile) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to open zip file: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let write_path = path::PathBuf::from(&destpath);
|
||||||
|
|
||||||
|
// Run extraction in seperate thread
|
||||||
|
thread::spawn(move || {
|
||||||
|
let full_path = write_path;
|
||||||
|
|
||||||
|
window.emit("extract_start", &zipfile).unwrap();
|
||||||
|
|
||||||
|
match zip_extract::extract(&f, &full_path, true) {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Extracted zip file to: {}", full_path.to_str().unwrap_or("Error"));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to extract zip file: {}", e);
|
||||||
|
let mut res_hash = std::collections::HashMap::new();
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"error".to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
res_hash.insert(
|
||||||
|
"path".to_string(),
|
||||||
|
zipfile.to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.emit("download_error", &res_hash).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the name of the inenr file in the zip file
|
||||||
|
let mut zip = zip::ZipArchive::new(&f).unwrap();
|
||||||
|
let file = zip.by_index(0).unwrap();
|
||||||
|
let name = file.name();
|
||||||
|
|
||||||
|
// If the contents is a jar file, emit that we have extracted a new jar file
|
||||||
|
if name.ends_with(".jar") {
|
||||||
|
window.emit("jar_extracted", destpath.to_string() + name).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete zip file
|
||||||
|
match std::fs::remove_file(&zipfile) {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Deleted zip file: {}", zipfile);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to delete zip file: {}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.emit("extract_end", &zipfile).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
18
src-tauri/src/web.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use reqwest::header::USER_AGENT;
|
||||||
|
|
||||||
|
pub(crate) async fn query(site: &str) -> String {
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
let response = client.get(site).header(USER_AGENT, "cultivation").send().await.unwrap();
|
||||||
|
return response.text().await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub(crate) async fn valid_url(url: String) -> bool {
|
||||||
|
// Check if we get a 200 response
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
let response = client.get(url).header(USER_AGENT, "cultivation").send().await.unwrap();
|
||||||
|
|
||||||
|
return response.status().as_str() == "200";
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
"$schema": "..\\node_modules/@tauri-apps/cli\\schema.json",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "yarn start",
|
"beforeDevCommand": "yarn start",
|
||||||
"devPath": "http://localhost:3000",
|
"devPath": "http://localhost:3000",
|
||||||
@@ -7,17 +7,25 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "Cultivation",
|
"productName": "Cultivation",
|
||||||
"version": "1.2.0"
|
"version": "1.0.1"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
"fs": {
|
"fs": {
|
||||||
"scope": ["$DATA", "$DATA/cultivation", "$DATA/cultivation/**"]
|
"scope": [
|
||||||
|
"$DATA",
|
||||||
|
"$DATA/cultivation",
|
||||||
|
"$DATA/cultivation/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"all": true,
|
"all": true,
|
||||||
"asset": true,
|
"asset": true,
|
||||||
"assetScope": ["$DATA", "$DATA/cultivation", "$DATA/cultivation/**"]
|
"assetScope": [
|
||||||
|
"$DATA",
|
||||||
|
"$DATA/cultivation",
|
||||||
|
"$DATA/cultivation/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"all": true
|
"all": true
|
||||||
},
|
},
|
||||||
@@ -29,7 +37,13 @@
|
|||||||
"depends": []
|
"depends": []
|
||||||
},
|
},
|
||||||
"externalBin": [],
|
"externalBin": [],
|
||||||
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
|
"icon": [
|
||||||
|
"icons/32x32.png",
|
||||||
|
"icons/128x128.png",
|
||||||
|
"icons/128x128@2x.png",
|
||||||
|
"icons/icon.icns",
|
||||||
|
"icons/icon.ico"
|
||||||
|
],
|
||||||
"identifier": "io.grasscutter",
|
"identifier": "io.grasscutter",
|
||||||
"shortDescription": "A game launcher.",
|
"shortDescription": "A game launcher.",
|
||||||
"longDescription": "A launcher for a certain anime game that proxies all related game traffic to external servers.",
|
"longDescription": "A launcher for a certain anime game that proxies all related game traffic to external servers.",
|
||||||
@@ -40,7 +54,9 @@
|
|||||||
"providerShortName": null,
|
"providerShortName": null,
|
||||||
"signingIdentity": null
|
"signingIdentity": null
|
||||||
},
|
},
|
||||||
"resources": ["lang/*.json", "keys/*", "patch/*"],
|
"resources": [
|
||||||
|
"lang/*.json"
|
||||||
|
],
|
||||||
"targets": "all",
|
"targets": "all",
|
||||||
"windows": {
|
"windows": {
|
||||||
"allowDowngrades": false,
|
"allowDowngrades": false,
|
||||||
@@ -53,10 +69,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"csp": "default-src 'self'; img-src 'self' https://* asset: https://asset.localhost tauri://localhost; media-src https://* asset: https://asset.localhost tauri://localhost; style-src-elem https://* asset: https://asset.localhost tauri://localhost; script-src-elem https://* asset: https://asset.localhost tauri://localhost;"
|
"csp": "default-src 'self' https://asset.localhost; img-src 'self'; img-src https://* asset: https://asset.localhost"
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
"active": false,
|
"active": true,
|
||||||
"dialog": true,
|
"dialog": true,
|
||||||
"endpoints": [
|
"endpoints": [
|
||||||
"https://api.grasscutter.io/cultivation/updater?version={{current_version}}",
|
"https://api.grasscutter.io/cultivation/updater?version={{current_version}}",
|
||||||
@@ -75,4 +91,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: 'MiHoYo_SDK_Web', 'Helvetica Neue', BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
font-family: 'MiHoYo_SDK_Web', 'Helvetica Neue', BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
'Cantarell', 'Fira Sans', 'Droid Sans', sans-serif;
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
|
||||||
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
|
monospace;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,15 +7,29 @@ import Debug from './ui/Debug'
|
|||||||
|
|
||||||
import { getConfigOption } from './utils/configuration'
|
import { getConfigOption } from './utils/configuration'
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
|
const root = ReactDOM.createRoot(
|
||||||
|
document.getElementById('root') as HTMLElement
|
||||||
|
)
|
||||||
|
|
||||||
let isDebug = false
|
let isDebug = false;
|
||||||
|
|
||||||
;async () => {
|
(async() => {
|
||||||
isDebug = await getConfigOption('debug_enabled')
|
isDebug = await getConfigOption('debug_enabled')
|
||||||
}
|
})
|
||||||
|
|
||||||
root.render(<React.StrictMode>{isDebug ? <Debug /> : <App />}</React.StrictMode>)
|
// Render the app.
|
||||||
|
root.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
{
|
||||||
|
isDebug ? <Debug /> : <App />
|
||||||
|
}
|
||||||
|
</React.StrictMode>
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enable web vitals if needed.
|
||||||
import reportWebVitals from './utils/reportWebVitals'
|
import reportWebVitals from './utils/reportWebVitals'
|
||||||
isDebug && reportWebVitals(console.log)
|
isDebug && reportWebVitals(console.log)
|
||||||
|
|
||||||
|
// Setup DOM message passing.
|
||||||
|
import { parseMessageFromDOM } from './utils/dom'
|
||||||
|
document.addEventListener<string>('domMessage', parseMessageFromDOM)
|
||||||
34
src/resources/example-theme/index.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "Example Theme",
|
||||||
|
"version": "420.69",
|
||||||
|
"description": "Show off some of the abilities of the Cultivation theme system",
|
||||||
|
|
||||||
|
"includes": {
|
||||||
|
"_README": "You can include any amount of CSS and JS files here. Paths are relative to the theme directory.",
|
||||||
|
|
||||||
|
"css": ["/index.css"],
|
||||||
|
"js": ["/index.js"]
|
||||||
|
},
|
||||||
|
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"label": "Example Setting",
|
||||||
|
"type": "input",
|
||||||
|
"className": "Input",
|
||||||
|
|
||||||
|
"data": {
|
||||||
|
"placeholder": "Enter a value",
|
||||||
|
"initialValue": "Change this value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Example Setting",
|
||||||
|
"type": "checkbox",
|
||||||
|
"className": "Checkbox"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"_README": "These are optional. Including neither will result in the launcher simply using the default background choice.",
|
||||||
|
"customBackgroundPath": "/background/bg.png",
|
||||||
|
"customBackgroundURL": ""
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 642 KiB |
@@ -1,67 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="1024.000000pt" height="1024.000000pt" viewBox="0 0 1024.000000 1024.000000"
|
|
||||||
preserveAspectRatio="xMidYMid meet">
|
|
||||||
|
|
||||||
<g transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)"
|
|
||||||
fill="#000000" stroke="none">
|
|
||||||
<path d="M7045 10204 c-301 -50 -596 -277 -731 -564 -96 -204 -111 -463 -40
|
|
||||||
-692 16 -52 14 -58 -26 -58 -62 0 -220 -85 -331 -178 -24 -20 -105 -91 -178
|
|
||||||
-157 -74 -66 -177 -156 -229 -200 -208 -175 -629 -573 -1001 -944 -152 -152
|
|
||||||
-286 -284 -297 -294 -18 -17 -27 -17 -75 -8 -96 21 -249 29 -361 20 -321 -26
|
|
||||||
-613 -162 -836 -389 -341 -346 -457 -846 -303 -1301 l36 -106 -66 -100 c-102
|
|
||||||
-155 -212 -343 -303 -518 -353 -683 -556 -1455 -531 -2025 6 -136 29 -341 47
|
|
||||||
-415 36 -156 58 -234 92 -335 47 -137 52 -147 134 -315 90 -182 113 -220 223
|
|
||||||
-375 376 -528 945 -931 1571 -1113 261 -76 439 -94 503 -52 27 17 30 17 105
|
|
||||||
-4 125 -35 209 -50 345 -62 107 -9 152 -8 279 6 118 13 180 15 277 8 214 -14
|
|
||||||
475 -9 566 11 144 31 312 80 395 114 14 6 68 27 120 48 91 36 302 135 365 172
|
|
||||||
180 104 373 265 507 422 346 407 518 977 520 1725 0 287 -10 448 -48 755 -43
|
|
||||||
357 -95 631 -208 1100 -24 102 -47 199 -51 217 -5 26 -1 41 25 78 48 70 108
|
|
||||||
204 132 297 32 118 31 366 0 482 -75 272 -258 503 -507 639 l-77 42 -68 202
|
|
||||||
c-37 112 -70 213 -73 225 -3 13 -14 57 -26 98 -12 41 -33 134 -47 205 -23 115
|
|
||||||
-26 154 -27 345 0 223 1 232 62 580 44 245 54 349 47 490 -10 234 -52 334
|
|
||||||
-206 495 -98 103 -128 150 -167 261 -24 70 -27 94 -28 209 0 135 10 185 58
|
|
||||||
280 49 99 182 235 282 288 179 96 373 112 464 39 62 -49 101 -117 101 -174 0
|
|
||||||
-81 -49 -152 -117 -172 -13 -3 -32 -8 -42 -11 -13 -4 -34 7 -65 34 -26 22 -63
|
|
||||||
45 -84 52 -107 32 -219 -73 -198 -185 7 -37 89 -141 129 -163 137 -76 279 -77
|
|
||||||
428 -3 102 52 190 149 236 263 36 89 42 239 14 326 -36 108 -112 215 -206 286
|
|
||||||
-80 62 -158 92 -265 105 -105 11 -142 11 -245 -6z m-574 -1640 c138 -41 189
|
|
||||||
-186 160 -459 -13 -115 -45 -328 -62 -405 -19 -86 -49 -386 -49 -493 0 -163
|
|
||||||
17 -299 71 -552 7 -36 35 -132 102 -350 l24 -80 -31 -2 c-114 -9 -233 -28
|
|
||||||
-305 -50 -193 -55 -383 -185 -509 -347 -12 -16 -24 -27 -27 -24 -6 5 -22 125
|
|
||||||
-30 223 -3 39 -10 113 -15 165 -10 105 -26 365 -35 595 -5 120 -11 158 -26
|
|
||||||
192 -34 70 -110 104 -187 84 -44 -12 -77 -47 -217 -230 -38 -51 -90 -118 -115
|
|
||||||
-150 -25 -32 -70 -91 -100 -131 -30 -40 -64 -84 -76 -98 l-21 -25 -37 67 c-89
|
|
||||||
159 -229 312 -386 419 l-81 55 213 214 c371 372 775 751 1063 997 94 79 193
|
|
||||||
166 220 192 78 75 185 157 239 184 60 30 136 33 217 9z m-2317 -1783 c351 -93
|
|
||||||
611 -365 682 -712 22 -109 15 -291 -16 -403 -107 -396 -472 -688 -900 -722
|
|
||||||
l-85 -6 70 50 c180 127 282 307 293 513 16 326 -203 611 -533 695 -90 22 -256
|
|
||||||
23 -347 1 -136 -33 -284 -119 -366 -212 -22 -25 -42 -45 -44 -45 -9 0 11 102
|
|
||||||
33 175 104 343 411 610 782 681 104 20 329 12 431 -15z m1310 -406 c21 -268
|
|
||||||
29 -351 51 -545 31 -262 72 -520 120 -765 26 -130 66 -320 75 -360 5 -22 28
|
|
||||||
-128 50 -235 23 -107 45 -213 50 -235 41 -178 113 -614 145 -880 48 -401 57
|
|
||||||
-943 20 -1215 -55 -407 -186 -801 -368 -1102 -107 -178 -168 -262 -258 -355
|
|
||||||
-146 -150 -290 -212 -494 -213 -252 0 -520 107 -800 319 -274 207 -539 609
|
|
||||||
-674 1021 -112 339 -154 603 -154 960 0 278 18 425 82 671 92 348 301 725 615
|
|
||||||
1106 l50 61 87 16 c472 86 871 430 1017 876 42 128 55 211 58 383 l4 168 120
|
|
||||||
157 c169 220 194 252 196 249 1 -1 5 -38 8 -82z m1043 -511 c-144 -112 -216
|
|
||||||
-335 -168 -519 27 -101 69 -171 148 -245 74 -69 141 -104 246 -127 67 -14 90
|
|
||||||
-15 159 -5 145 21 277 102 353 218 60 90 86 178 86 287 0 51 -3 102 -6 112
|
|
||||||
-13 40 26 -17 61 -89 95 -196 84 -447 -28 -633 -183 -303 -569 -423 -917 -284
|
|
||||||
-171 69 -330 226 -398 394 -152 373 46 791 432 913 73 23 82 17 32 -22z
|
|
||||||
m-3393 -1044 c104 -70 239 -133 356 -166 52 -15 97 -28 98 -30 4 -2 -15 -29
|
|
||||||
-83 -124 -60 -83 -171 -254 -217 -335 -185 -323 -305 -691 -349 -1070 -19
|
|
||||||
-158 -16 -519 5 -690 34 -284 98 -554 186 -790 44 -120 179 -400 231 -480 171
|
|
||||||
-266 299 -420 509 -610 50 -45 61 -59 47 -63 -47 -10 -352 117 -535 224 -700
|
|
||||||
409 -1152 1060 -1253 1804 -19 136 -16 466 5 625 78 591 314 1222 678 1813
|
|
||||||
l70 113 87 -84 c48 -46 122 -107 165 -137z m3105 -469 c175 -88 288 -116 481
|
|
||||||
-116 190 0 316 30 470 111 30 16 58 30 61 32 15 7 131 -523 183 -833 64 -382
|
|
||||||
88 -661 88 -1015 -1 -346 -24 -553 -94 -820 -112 -430 -342 -768 -675 -993
|
|
||||||
-139 -94 -386 -208 -643 -297 -67 -24 -174 -50 -255 -64 -94 -17 -350 -22
|
|
||||||
-359 -8 -2 4 16 26 40 47 42 37 171 184 204 231 176 256 269 425 360 654 118
|
|
||||||
295 181 554 221 907 19 168 21 222 16 503 -4 173 -11 369 -16 434 -30 341
|
|
||||||
-103 828 -177 1168 -15 73 -18 108 -7 108 4 0 50 -22 102 -49z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.5 KiB |
@@ -1,10 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
|
||||||
<desc>Created with Fabric.js 1.7.22</desc>
|
|
||||||
<defs>
|
|
||||||
</defs>
|
|
||||||
<g transform="translate(128 128) scale(0.72 0.72)" style="">
|
|
||||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(-175.05 -175.05) scale(3.89 3.89)" >
|
|
||||||
<path d="M 45 0 c 24.813 0 45 20.187 45 45 c 0 24.813 -20.187 45 -45 45 C 20.186 90 0 69.813 0 45 C 0 20.187 20.186 0 45 0 z M 51.263 73.4 l 8.6 -8.6 L 40.064 45 l 19.799 -19.799 l -8.6 -8.6 L 22.864 45 L 51.263 73.4 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1002 B |
@@ -1,11 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
|
||||||
<desc>Created with Fabric.js 1.7.22</desc>
|
|
||||||
<defs>
|
|
||||||
</defs>
|
|
||||||
<g transform="translate(128 128) scale(0.72 0.72)" style="">
|
|
||||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(-175.05 -175.05) scale(3.89 3.89)" >
|
|
||||||
<path d="M 89.307 43.082 C 74.775 25.601 59.868 16.737 45 16.737 c -14.869 0 -29.775 8.864 -44.307 26.345 c -0.924 1.112 -0.924 2.724 0 3.836 C 15.225 64.399 30.131 73.264 45 73.264 c 14.868 0 29.775 -8.864 44.307 -26.346 C 90.231 45.806 90.231 44.194 89.307 43.082 z M 45 62 c -9.374 0 -17 -7.626 -17 -17 s 7.626 -17 17 -17 s 17 7.626 17 17 S 54.374 62 45 62 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
||||||
<circle cx="45" cy="45" r="9" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) "/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,11 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
|
||||||
<desc>Created with Fabric.js 1.7.22</desc>
|
|
||||||
<defs>
|
|
||||||
</defs>
|
|
||||||
<g transform="translate(128 128) scale(0.72 0.72)" style="">
|
|
||||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(-175.05 -175.05) scale(3.89 3.89)" >
|
|
||||||
<path d="M 0 87.201 h 18.478 c 1.44 0 2.607 -1.167 2.607 -2.607 V 35.343 c 0 -1.44 -1.167 -2.607 -2.607 -2.607 H 0 L 0 87.201 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
||||||
<path d="M 83.186 46.32 c 3.763 0 6.814 -3.051 6.814 -6.814 c 0 -3.763 -3.051 -6.814 -6.814 -6.814 H 61.591 c 3.758 -6.768 3.872 -27.328 -5.046 -29.797 c -1.689 -0.468 -3.365 0.823 -3.554 2.565 c -1.568 14.428 -10.395 32.362 -19.37 32.881 h -6.991 v 43.003 h 3.627 c 1.952 0 3.817 0.666 5.444 1.743 c 4.063 2.691 10.906 4.265 17.465 4.101 h 3.172 v 0.012 h 21.788 c 3.763 0 6.814 -3.051 6.814 -6.814 c 0 -3.763 -3.051 -6.814 -6.814 -6.814 h 3.037 c 3.763 0 6.814 -3.051 6.814 -6.814 c 0 -3.763 -3.051 -6.814 -6.814 -6.814 h 2.025 c 3.763 0 6.814 -3.051 6.814 -6.814 S 86.949 46.32 83.186 46.32 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,11 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
|
||||||
<desc>Created with Fabric.js 1.7.22</desc>
|
|
||||||
<defs>
|
|
||||||
</defs>
|
|
||||||
<g transform="translate(128 128) scale(0.72 0.72)" style="">
|
|
||||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(-175.05 -175.05) scale(3.89 3.89)" >
|
|
||||||
<path d="M 58.921 90 H 31.079 c -1.155 0 -2.092 -0.936 -2.092 -2.092 V 2.092 C 28.988 0.936 29.924 0 31.079 0 h 27.841 c 1.155 0 2.092 0.936 2.092 2.092 v 85.817 C 61.012 89.064 60.076 90 58.921 90 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
||||||
<path d="M 90 31.079 v 27.841 c 0 1.155 -0.936 2.092 -2.092 2.092 H 2.092 C 0.936 61.012 0 60.076 0 58.921 V 31.079 c 0 -1.155 0.936 -2.092 2.092 -2.092 h 85.817 C 89.064 28.988 90 29.924 90 31.079 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,10 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
|
|
||||||
<desc>Created with Fabric.js 1.7.22</desc>
|
|
||||||
<defs>
|
|
||||||
</defs>
|
|
||||||
<g transform="translate(128 128) scale(0.72 0.72)" style="">
|
|
||||||
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(-175.05 -175.05) scale(3.89 3.89)" >
|
|
||||||
<path d="M 87.12 73.212 L 48.774 34.866 c 3.723 -9.153 1.873 -20.042 -5.553 -27.468 c -7.008 -7.008 -17.094 -9.025 -25.9 -6.104 L 28.96 12.934 c 4.387 4.387 4.833 11.594 0.579 16.112 c -4.402 4.674 -11.761 4.757 -16.268 0.25 L 1.295 17.32 c -2.922 8.807 -0.904 18.892 6.104 25.9 c 7.426 7.426 18.315 9.276 27.468 5.553 L 73.212 87.12 c 3.84 3.84 10.067 3.84 13.908 0 l 0 0 C 90.96 83.279 90.96 77.052 87.12 73.212 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
109
src/ui/App.css
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
html,
|
||||||
|
body {
|
||||||
|
user-select: none;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 217px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid #cecece;
|
||||||
|
|
||||||
|
padding-right: 16px;
|
||||||
|
|
||||||
|
text-decoration-color: #000;
|
||||||
|
|
||||||
|
transition: border-bottom-color 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-bottom-color: #ffd326;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root, .App {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.App {
|
||||||
|
background-size: cover !important;
|
||||||
|
background-position: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TopButton {
|
||||||
|
height: 60%;
|
||||||
|
margin: 0px 10px;
|
||||||
|
filter: invert(95%) sepia(0%) saturate(18%) hue-rotate(153deg) brightness(88%) contrast(81%);
|
||||||
|
|
||||||
|
transition: filter 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TopButton:hover {
|
||||||
|
filter: invert(100%) sepia(0%) saturate(18%) hue-rotate(153deg) brightness(100%) contrast(100%);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TopButton img {
|
||||||
|
height: 80%;
|
||||||
|
vertical-align: super;
|
||||||
|
}
|
||||||
|
|
||||||
|
#DownloadProgress {
|
||||||
|
position: absolute;
|
||||||
|
transform: translate(0%, -50%);
|
||||||
|
top: 50%;
|
||||||
|
left: 5%;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MiniDownloads {
|
||||||
|
position: absolute;
|
||||||
|
top: 40%;
|
||||||
|
left: 12%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-down {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 50px solid transparent;
|
||||||
|
border-right: 50px solid transparent;
|
||||||
|
border-top: 50px solid transparent;
|
||||||
|
|
||||||
|
/* Colored section */
|
||||||
|
border-top: 50px solid #fff;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
top: 73%;
|
||||||
|
left: 15%;
|
||||||
|
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BottomSection {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0%);
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 160px;
|
||||||
|
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
box-shadow: inset 0px 5px 12px -3px rgb(50 50 50 / 75%);
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-height: 580px) {
|
||||||
|
.BottomSection {
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-height: 500px) {
|
||||||
|
.BottomSection {
|
||||||
|
height: 140px;
|
||||||
|
}
|
||||||
|
}
|
||||||
228
src/ui/App.tsx
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
import './App.css'
|
||||||
|
|
||||||
|
import DownloadHandler from '../utils/download'
|
||||||
|
|
||||||
|
// Major Components
|
||||||
|
import TopBar from './components/TopBar'
|
||||||
|
import ServerLaunchSection from './components/ServerLaunchSection'
|
||||||
|
import MainProgressBar from './components/common/MainProgressBar'
|
||||||
|
import Options from './components/menu/Options'
|
||||||
|
import MiniDialog from './components/MiniDialog'
|
||||||
|
import DownloadList from './components/common/DownloadList'
|
||||||
|
import Downloads from './components/menu/Downloads'
|
||||||
|
import NewsSection from './components/news/NewsSection'
|
||||||
|
import Game from './components/menu/Game'
|
||||||
|
|
||||||
|
import RightBar from './components/RightBar'
|
||||||
|
import { getConfigOption, setConfigOption } from '../utils/configuration'
|
||||||
|
import { invoke } from '@tauri-apps/api'
|
||||||
|
import { dataDir } from '@tauri-apps/api/path'
|
||||||
|
import { appWindow } from '@tauri-apps/api/window'
|
||||||
|
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
||||||
|
import { getTheme, loadTheme } from '../utils/themes'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
[key: string]: never;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
isDownloading: boolean;
|
||||||
|
optionsOpen: boolean;
|
||||||
|
miniDownloadsOpen: boolean;
|
||||||
|
downloadsOpen: boolean;
|
||||||
|
gameDownloadsOpen: boolean;
|
||||||
|
bgFile: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_BG = 'https://api.grasscutter.io/cultivation/bgfile'
|
||||||
|
|
||||||
|
const downloadHandler = new DownloadHandler()
|
||||||
|
|
||||||
|
class App extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
isDownloading: false,
|
||||||
|
optionsOpen: false,
|
||||||
|
miniDownloadsOpen: false,
|
||||||
|
downloadsOpen: false,
|
||||||
|
gameDownloadsOpen: false,
|
||||||
|
bgFile: DEFAULT_BG,
|
||||||
|
}
|
||||||
|
|
||||||
|
listen('lang_error', (payload) => {
|
||||||
|
console.log(payload)
|
||||||
|
})
|
||||||
|
|
||||||
|
listen('jar_extracted', ({ payload }) => {
|
||||||
|
setConfigOption('grasscutter_path', payload)
|
||||||
|
})
|
||||||
|
|
||||||
|
let min = false
|
||||||
|
|
||||||
|
// periodically check if we need to min/max based on whether the game is open
|
||||||
|
setInterval(async () => {
|
||||||
|
const gameOpen = await invoke('is_game_running')
|
||||||
|
|
||||||
|
if (gameOpen && !min) {
|
||||||
|
appWindow.minimize()
|
||||||
|
min = true
|
||||||
|
} else if (!gameOpen && min) {
|
||||||
|
appWindow.unminimize()
|
||||||
|
min = false
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const cert_generated = await getConfigOption('cert_generated')
|
||||||
|
const game_exe = await getConfigOption('game_install_path')
|
||||||
|
const game_path = game_exe?.substring(0, game_exe.replace(/\\/g, '/').lastIndexOf('/')) || ''
|
||||||
|
const root_path = game_path?.substring(0, game_path.replace(/\\/g, '/').lastIndexOf('/')) || ''
|
||||||
|
|
||||||
|
// Load a theme if it exists
|
||||||
|
const theme = await getConfigOption('theme')
|
||||||
|
if (theme && theme !== 'default') {
|
||||||
|
const themeObj = await getTheme(theme)
|
||||||
|
await loadTheme(themeObj, document)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get custom bg AFTER theme is loaded !! important !!
|
||||||
|
const custom_bg = await getConfigOption('customBackground')
|
||||||
|
|
||||||
|
if(!custom_bg || !/png|jpg|jpeg$/.test(custom_bg)) {
|
||||||
|
if(game_path) {
|
||||||
|
// Get the bg by invoking, then set the background to that bg.
|
||||||
|
const bgLoc: string = await invoke('get_bg_file', {
|
||||||
|
bgPath: root_path,
|
||||||
|
appdata: await dataDir()
|
||||||
|
})
|
||||||
|
|
||||||
|
bgLoc && this.setState({
|
||||||
|
bgFile: bgLoc
|
||||||
|
}, this.forceUpdate)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const isUrl = /^http(s)?:\/\//gm.test(custom_bg)
|
||||||
|
|
||||||
|
if (!isUrl) {
|
||||||
|
const isValid = await invoke('dir_exists', {
|
||||||
|
path: custom_bg
|
||||||
|
})
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
bgFile: isValid ? convertFileSrc(custom_bg) : DEFAULT_BG
|
||||||
|
}, this.forceUpdate)
|
||||||
|
} else {
|
||||||
|
// Check if URL returns a valid image.
|
||||||
|
const isValid = await invoke('valid_url', {
|
||||||
|
url: custom_bg
|
||||||
|
})
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
bgFile: isValid ? custom_bg : DEFAULT_BG
|
||||||
|
}, this.forceUpdate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cert_generated) {
|
||||||
|
// Generate the certificate
|
||||||
|
await invoke('generate_ca_files', {
|
||||||
|
path: await dataDir() + 'cultivation'
|
||||||
|
})
|
||||||
|
|
||||||
|
await setConfigOption('cert_generated', true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period check to only show progress bar when downloading files
|
||||||
|
setInterval(() => {
|
||||||
|
this.setState({
|
||||||
|
isDownloading: downloadHandler.getDownloads().filter(d => d.status !== 'finished')?.length > 0
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="App" style={
|
||||||
|
this.state.bgFile ? {
|
||||||
|
background: `url("${this.state.bgFile}") fixed`,
|
||||||
|
} : {}
|
||||||
|
}>
|
||||||
|
<TopBar
|
||||||
|
optFunc={() => {
|
||||||
|
this.setState({ optionsOpen: !this.state.optionsOpen })
|
||||||
|
}}
|
||||||
|
downFunc={() => this.setState({ downloadsOpen: !this.state.downloadsOpen })}
|
||||||
|
gameFunc={() => this.setState({ gameDownloadsOpen: !this.state.gameDownloadsOpen })}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<RightBar />
|
||||||
|
|
||||||
|
<NewsSection />
|
||||||
|
|
||||||
|
{
|
||||||
|
// Mini downloads section
|
||||||
|
this.state.miniDownloadsOpen ? (
|
||||||
|
<div className="MiniDownloads" id="miniDownloadContainer">
|
||||||
|
<MiniDialog
|
||||||
|
title="Downloads"
|
||||||
|
closeFn={() => {
|
||||||
|
this.setState({ miniDownloadsOpen: false })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DownloadList downloadManager={downloadHandler} />
|
||||||
|
</MiniDialog>
|
||||||
|
<div className="arrow-down"></div>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Download menu
|
||||||
|
this.state.downloadsOpen ? (
|
||||||
|
<Downloads
|
||||||
|
downloadManager={downloadHandler}
|
||||||
|
closeFn={() => this.setState({ downloadsOpen: false })}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Options menu
|
||||||
|
this.state.optionsOpen ? (
|
||||||
|
<Options
|
||||||
|
closeFn={() => this.setState({ optionsOpen: !this.state.optionsOpen })}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Game downloads menu
|
||||||
|
this.state.gameDownloadsOpen ? (
|
||||||
|
<Game
|
||||||
|
downloadManager={downloadHandler}
|
||||||
|
closeFn={() => this.setState({ gameDownloadsOpen: false })}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="BottomSection" id="bottomSectionContainer">
|
||||||
|
<ServerLaunchSection />
|
||||||
|
|
||||||
|
<div id="DownloadProgress"
|
||||||
|
onClick={() => this.setState({ miniDownloadsOpen: !this.state.miniDownloadsOpen })}
|
||||||
|
>
|
||||||
|
{ this.state.isDownloading ?
|
||||||
|
<MainProgressBar downloadManager={downloadHandler} />
|
||||||
|
: null }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
||||||
58
src/ui/Debug.tsx
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import './App.css'
|
||||||
|
|
||||||
|
import TopBar from './components/TopBar'
|
||||||
|
|
||||||
|
import {invoke} from '@tauri-apps/api/tauri'
|
||||||
|
import {dataDir} from '@tauri-apps/api/path'
|
||||||
|
import TextInput from './components/common/TextInput'
|
||||||
|
|
||||||
|
let proxyAddress = ''
|
||||||
|
|
||||||
|
async function setProxyAddress(address: string) {
|
||||||
|
proxyAddress = address
|
||||||
|
await invoke('set_proxy_addr', { addr: address })
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startProxy() {
|
||||||
|
await invoke('connect', { port: 2222, certificatePath: await dataDir() + '\\cultivation\\ca' })
|
||||||
|
await invoke('open_in_browser', { url: 'https://hoyoverse.com' })
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stopProxy() {
|
||||||
|
await invoke('disconnect')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateCertificates() {
|
||||||
|
await invoke('generate_ca_files', { path: await dataDir() + '\\cultivation' })
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateInfo() {
|
||||||
|
console.log({
|
||||||
|
certificatePath: await dataDir() + '\\cultivation\\ca',
|
||||||
|
isAdmin: await invoke('is_elevated'),
|
||||||
|
connectingTo: proxyAddress
|
||||||
|
})
|
||||||
|
alert('check your dev console and send that in #cultivation')
|
||||||
|
}
|
||||||
|
|
||||||
|
function none() {
|
||||||
|
alert('none')
|
||||||
|
}
|
||||||
|
|
||||||
|
class Debug extends React.Component<any, any>{
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
<TopBar optFunc={none} downFunc={none} gameFunc={none} />
|
||||||
|
<TextInput readOnly={false} initalValue={'change to set proxy address'} onChange={setProxyAddress} />
|
||||||
|
<button onClick={startProxy}>start proxy</button>
|
||||||
|
<button onClick={stopProxy}>stop proxy</button>
|
||||||
|
<button onClick={generateCertificates}>generate certificates</button>
|
||||||
|
<button onClick={generateInfo}>dump info</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Debug
|
||||||
35
src/ui/components/MiniDialog.css
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
.MiniDialog {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 99;
|
||||||
|
|
||||||
|
/* Len and width */
|
||||||
|
height: 30%;
|
||||||
|
width: 30%;
|
||||||
|
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.MiniDialogTop {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MiniDialogTop img {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MiniDialogTop:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MiniDialog .ProgressText {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
50
src/ui/components/MiniDialog.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import Close from '../../resources/icons/close.svg'
|
||||||
|
import './MiniDialog.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
children: React.ReactNode[] | React.ReactNode;
|
||||||
|
title?: string;
|
||||||
|
closeable?: boolean;
|
||||||
|
closeFn: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class MiniDialog extends React.Component<IProps, never> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.addEventListener('mousedown', (evt) => {
|
||||||
|
const tgt = evt.target as HTMLElement
|
||||||
|
const isInside = tgt.closest('.MiniDialog') !== null
|
||||||
|
|
||||||
|
if (!isInside) {
|
||||||
|
this.props.closeFn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.removeEventListener('mousedown', this.props.closeFn)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="MiniDialog" id="miniDialogContainer">
|
||||||
|
{
|
||||||
|
this.props.closeable !== undefined && this.props.closeable ?
|
||||||
|
<div className="MiniDialogTop" id="miniDialogContainerTop" onClick={this.props.closeFn}>
|
||||||
|
<span>{this.props?.title}</span>
|
||||||
|
<img src={Close} className="MiniDialogClose" id="miniDialogButtonClose" />
|
||||||
|
</div> : null
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="MiniDialogInner" id="miniDialogContent">
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/ui/components/RightBar.css
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
.RightBar {
|
||||||
|
position: absolute;
|
||||||
|
transform: translate(0%, 0%);
|
||||||
|
|
||||||
|
display:flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
height: 100vh;
|
||||||
|
width: 80px;
|
||||||
|
right: 0%;
|
||||||
|
|
||||||
|
z-index: 99;
|
||||||
|
|
||||||
|
background-color: rgba(77, 77, 77, 0.6);
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BarImg:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RightBarInner > div {
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RightBar img {
|
||||||
|
height: 40px;
|
||||||
|
filter: invert(100%) sepia(0%) saturate(11%) hue-rotate(227deg) brightness(103%) contrast(105%);
|
||||||
|
|
||||||
|
transition: filter 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RightBar img:hover {
|
||||||
|
filter: invert(75%) sepia(0%) saturate(100%) hue-rotate(0deg) brightness(100%) contrast(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-height: 580px) {
|
||||||
|
.RightBar {
|
||||||
|
height: calc(100vh - 180px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-height: 500px) {
|
||||||
|
.RightBar {
|
||||||
|
height: calc(100vh - 170px);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/ui/components/RightBar.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { invoke } from '@tauri-apps/api'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import Discord from '../../resources/icons/discord.svg'
|
||||||
|
import Github from '../../resources/icons/github.svg'
|
||||||
|
|
||||||
|
import './RightBar.css'
|
||||||
|
|
||||||
|
const DISCORD = 'https://discord.gg/T5vZU6UyeG'
|
||||||
|
const GITHUB = 'https://github.com/Grasscutters/Grasscutter'
|
||||||
|
|
||||||
|
export default class RightBar extends React.Component {
|
||||||
|
openInBrowser(url: string) {
|
||||||
|
invoke('open_in_browser', { url })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="RightBar" id="rightBarContainer">
|
||||||
|
<div className="RightBarInner" id="rightBarContent">
|
||||||
|
<div className="BarDiscord BarImg" id="rightBarButtonDiscord" onClick={() => this.openInBrowser(DISCORD)}>
|
||||||
|
<img src={Discord} />
|
||||||
|
</div>
|
||||||
|
<div className="BarGithub BarImg" id="rightBarButtonGithub" onClick={() => this.openInBrowser(GITHUB)}>
|
||||||
|
<img src={Github} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
118
src/ui/components/ServerLaunchSection.css
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#playButton {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
transform: translate(0%, -50%);
|
||||||
|
right: 10%;
|
||||||
|
top: 50%;
|
||||||
|
|
||||||
|
width: 32%;
|
||||||
|
height: 80%;
|
||||||
|
min-width: 357px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#playButton > div {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#playButton .BigButton {
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 5px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#serverControls {
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
text-shadow: 1px 1px 8px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BottomSection .CheckboxDisplay {
|
||||||
|
border-color: #c5c5c5;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BottomSection .CheckboxDisplay {
|
||||||
|
margin-right: 6px;
|
||||||
|
box-shadow: 0 0 5px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.BottomSection .Checkbox label {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: #222222 1px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BottomSection .Checkbox label span {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ServerConfig {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ServerConfig .Checkbox {
|
||||||
|
display: inline-grid;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ServerLaunchButtons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#officialPlay {
|
||||||
|
width: 60%
|
||||||
|
}
|
||||||
|
|
||||||
|
#serverLaunch {
|
||||||
|
width: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ServerIcon {
|
||||||
|
height: 20px;
|
||||||
|
filter: invert(28%) sepia(28%) saturate(1141%) hue-rotate(352deg) brightness(96%) contrast(88%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ServerConfig input {
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
height: 18px;
|
||||||
|
|
||||||
|
box-shadow: 0 0 5px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ServerConfig .TextInputWrapper {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ip {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#port {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1040px) {
|
||||||
|
#playButton {
|
||||||
|
right: 5%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 870px) {
|
||||||
|
#playButton {
|
||||||
|
min-width: 235px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#officialPlay {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
222
src/ui/components/ServerLaunchSection.tsx
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Checkbox from './common/Checkbox'
|
||||||
|
import BigButton from './common/BigButton'
|
||||||
|
import TextInput from './common/TextInput'
|
||||||
|
import HelpButton from './common/HelpButton'
|
||||||
|
import { getConfig, saveConfig, setConfigOption } from '../../utils/configuration'
|
||||||
|
import { translate } from '../../utils/language'
|
||||||
|
import { invoke } from '@tauri-apps/api/tauri'
|
||||||
|
|
||||||
|
import Server from '../../resources/icons/server.svg'
|
||||||
|
import './ServerLaunchSection.css'
|
||||||
|
import {dataDir} from '@tauri-apps/api/path'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
grasscutterEnabled: boolean;
|
||||||
|
buttonLabel: string;
|
||||||
|
checkboxLabel: string;
|
||||||
|
ip: string;
|
||||||
|
port: string;
|
||||||
|
|
||||||
|
ipPlaceholder: string;
|
||||||
|
portPlaceholder: string;
|
||||||
|
|
||||||
|
portHelpText: string;
|
||||||
|
|
||||||
|
httpsLabel: string;
|
||||||
|
httpsEnabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ServerLaunchSection extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
grasscutterEnabled: false,
|
||||||
|
buttonLabel: '',
|
||||||
|
checkboxLabel: '',
|
||||||
|
ip: '',
|
||||||
|
port: '',
|
||||||
|
ipPlaceholder: '',
|
||||||
|
portPlaceholder: '',
|
||||||
|
portHelpText: '',
|
||||||
|
httpsLabel: '',
|
||||||
|
httpsEnabled: false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toggleGrasscutter = this.toggleGrasscutter.bind(this)
|
||||||
|
this.playGame = this.playGame.bind(this)
|
||||||
|
this.setIp = this.setIp.bind(this)
|
||||||
|
this.setPort = this.setPort.bind(this)
|
||||||
|
this.toggleHttps = this.toggleHttps.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const config = await getConfig()
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
grasscutterEnabled: config.toggle_grasscutter || false,
|
||||||
|
buttonLabel: await translate('main.launch_button'),
|
||||||
|
checkboxLabel: await translate('main.gc_enable'),
|
||||||
|
ip: config.last_ip || '',
|
||||||
|
port: config.last_port || '',
|
||||||
|
ipPlaceholder: await translate('main.ip_placeholder'),
|
||||||
|
portPlaceholder: await translate('help.port_placeholder'),
|
||||||
|
portHelpText: await translate('help.port_help_text'),
|
||||||
|
httpsLabel: await translate('main.https_enable'),
|
||||||
|
httpsEnabled: config.https_enabled || false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async toggleGrasscutter() {
|
||||||
|
const config = await getConfig()
|
||||||
|
|
||||||
|
config.toggle_grasscutter = !config.toggle_grasscutter
|
||||||
|
|
||||||
|
// Set state as well
|
||||||
|
this.setState({
|
||||||
|
grasscutterEnabled: config.toggle_grasscutter
|
||||||
|
})
|
||||||
|
|
||||||
|
await saveConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
async playGame() {
|
||||||
|
const config = await getConfig()
|
||||||
|
|
||||||
|
if (!config.game_install_path) return alert('Game path not set!')
|
||||||
|
|
||||||
|
// Connect to proxy
|
||||||
|
if (config.toggle_grasscutter) {
|
||||||
|
let game_exe = config.game_install_path
|
||||||
|
|
||||||
|
if (game_exe.includes('\\')) {
|
||||||
|
game_exe = game_exe.substring(config.game_install_path.lastIndexOf('\\') + 1)
|
||||||
|
} else {
|
||||||
|
game_exe = game_exe.substring(config.game_install_path.lastIndexOf('/') + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save last connected server and port
|
||||||
|
await setConfigOption('last_ip', this.state.ip)
|
||||||
|
await setConfigOption('last_port', this.state.port)
|
||||||
|
|
||||||
|
// Set IP
|
||||||
|
await invoke('set_proxy_addr', { addr: (this.state.httpsEnabled ? 'https':'http') + '://' + this.state.ip + ':' + this.state.port })
|
||||||
|
await invoke('enable_process_watcher', {
|
||||||
|
process: game_exe
|
||||||
|
})
|
||||||
|
|
||||||
|
// Connect to proxy
|
||||||
|
await invoke('connect', { port: 8365, certificatePath: await dataDir() + '\\cultivation\\ca' })
|
||||||
|
|
||||||
|
// Open server as well if the options are set
|
||||||
|
if (config.grasscutter_with_game) {
|
||||||
|
let jarFolder = config.grasscutter_path
|
||||||
|
|
||||||
|
if (jarFolder.includes('/')) {
|
||||||
|
jarFolder = jarFolder.substring(0, config.grasscutter_path.lastIndexOf('/'))
|
||||||
|
} else {
|
||||||
|
jarFolder = jarFolder.substring(0, config.grasscutter_path.lastIndexOf('\\'))
|
||||||
|
}
|
||||||
|
|
||||||
|
await invoke('run_jar', {
|
||||||
|
path: config.grasscutter_path,
|
||||||
|
executeIn: jarFolder,
|
||||||
|
javaPath: config.java_path || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch the program
|
||||||
|
const gameExists = await invoke('dir_exists', {
|
||||||
|
path: config.game_install_path
|
||||||
|
})
|
||||||
|
|
||||||
|
if (gameExists) await invoke('run_program', { path: config.game_install_path })
|
||||||
|
else alert('Game not found! At: ' + config.game_install_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
async launchServer() {
|
||||||
|
const config = await getConfig()
|
||||||
|
|
||||||
|
if (!config.grasscutter_path) return alert('Grasscutter not installed or set!')
|
||||||
|
|
||||||
|
let jarFolder = config.grasscutter_path
|
||||||
|
|
||||||
|
if (jarFolder.includes('/')) {
|
||||||
|
jarFolder = jarFolder.substring(0, config.grasscutter_path.lastIndexOf('/'))
|
||||||
|
} else {
|
||||||
|
jarFolder = jarFolder.substring(0, config.grasscutter_path.lastIndexOf('\\'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch the jar
|
||||||
|
await invoke('run_jar', {
|
||||||
|
path: config.grasscutter_path,
|
||||||
|
executeIn: jarFolder,
|
||||||
|
javaPath: config.java_path || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setIp(text: string) {
|
||||||
|
this.setState({
|
||||||
|
ip: text
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setPort(text: string) {
|
||||||
|
this.setState({
|
||||||
|
port: text
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async toggleHttps() {
|
||||||
|
const config = await getConfig()
|
||||||
|
|
||||||
|
config.https_enabled = !config.https_enabled
|
||||||
|
|
||||||
|
// Set state as well
|
||||||
|
this.setState({
|
||||||
|
httpsEnabled: config.https_enabled
|
||||||
|
})
|
||||||
|
|
||||||
|
await saveConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div id="playButton">
|
||||||
|
<div id="serverControls">
|
||||||
|
<Checkbox id="enableGC" label={this.state.checkboxLabel} onChange={this.toggleGrasscutter} checked={this.state.grasscutterEnabled}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
this.state.grasscutterEnabled && (
|
||||||
|
<div>
|
||||||
|
<div className="ServerConfig" id="serverConfigContainer">
|
||||||
|
<TextInput id="ip" key="ip" placeholder={this.state.ipPlaceholder} onChange={this.setIp} initalValue={this.state.ip} />
|
||||||
|
<TextInput style={{
|
||||||
|
width: '10%',
|
||||||
|
}} id="port" key="port" placeholder={this.state.portPlaceholder} onChange={this.setPort} initalValue={this.state.port} />
|
||||||
|
<HelpButton contents={this.state.portHelpText} />
|
||||||
|
<Checkbox id="httpsEnable" label={this.state.httpsLabel} onChange={this.toggleHttps} checked={this.state.httpsEnabled} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<div className="ServerLaunchButtons" id="serverLaunchContainer">
|
||||||
|
<BigButton onClick={this.playGame} id="officialPlay">{this.state.buttonLabel}</BigButton>
|
||||||
|
<BigButton onClick={this.launchServer} id="serverLaunch">
|
||||||
|
<img className="ServerIcon" id="serverLaunchIcon" src={Server} />
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/ui/components/TopBar.css
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
.TopBar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
background-color: #141414;
|
||||||
|
z-index: 1;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TopBtns {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
margin: 0px 12px;
|
||||||
|
color: #c5c5c5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version {
|
||||||
|
margin: 0px 6px;
|
||||||
|
color: #434343;
|
||||||
|
}
|
||||||
73
src/ui/components/TopBar.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { app } from '@tauri-apps/api'
|
||||||
|
import { appWindow } from '@tauri-apps/api/window'
|
||||||
|
import closeIcon from '../../resources/icons/close.svg'
|
||||||
|
import minIcon from '../../resources/icons/min.svg'
|
||||||
|
import cogBtn from '../../resources/icons/cog.svg'
|
||||||
|
import downBtn from '../../resources/icons/download.svg'
|
||||||
|
import gameBtn from '../../resources/icons/game.svg'
|
||||||
|
|
||||||
|
import Tr from '../../utils/language'
|
||||||
|
|
||||||
|
import './TopBar.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
optFunc: () => void;
|
||||||
|
downFunc: () => void;
|
||||||
|
gameFunc: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TopBar extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = { version: '0.0.0' }
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const version = await app.getVersion()
|
||||||
|
this.setState({ version })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClose() {
|
||||||
|
appWindow.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMinimize() {
|
||||||
|
appWindow.minimize()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="TopBar" id="topBarContainer" data-tauri-drag-region>
|
||||||
|
<div id="title">
|
||||||
|
<span data-tauri-drag-region>
|
||||||
|
<Tr text="main.title" />
|
||||||
|
</span>
|
||||||
|
<span data-tauri-drag-region id="version">{this.state?.version}</span>
|
||||||
|
</div>
|
||||||
|
<div className="TopBtns" id="topBarButtonContainer">
|
||||||
|
<div id="closeBtn" onClick={this.handleClose} className='TopButton'>
|
||||||
|
<img src={closeIcon} alt="close" />
|
||||||
|
</div>
|
||||||
|
<div id="minBtn" onClick={this.handleMinimize} className='TopButton'>
|
||||||
|
<img src={minIcon} alt="minimize" />
|
||||||
|
</div>
|
||||||
|
<div id="settingsBtn" onClick={this.props.optFunc} className='TopButton'>
|
||||||
|
<img src={cogBtn} alt="settings" />
|
||||||
|
</div>
|
||||||
|
<div id="downloadsBtn" className='TopButton' onClick={this.props.downFunc}>
|
||||||
|
<img src={downBtn} alt="downloads" />
|
||||||
|
</div>
|
||||||
|
{/* <div id="gameBtn" className="TopButton" onClick={this.props.gameFunc}>
|
||||||
|
<img src={gameBtn} alt="game" />
|
||||||
|
</div> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/ui/components/common/BigButton.css
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
.BigButton {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
padding: 0 30px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: none;
|
||||||
|
background: linear-gradient(#ffd326, #ffc61e);
|
||||||
|
color: #704a1d;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BigButton:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: linear-gradient(#ffc61e, #ffd326);
|
||||||
|
}
|
||||||
|
|
||||||
|
.BigButton.disabled {
|
||||||
|
background: linear-gradient(#9c9c9c, #949494);
|
||||||
|
color: rgb(226, 226, 226);
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BigButton.disabled:hover {
|
||||||
|
background: linear-gradient(#949494, #9c9c9c);
|
||||||
|
}
|
||||||
45
src/ui/components/common/BigButton.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import './BigButton.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
onClick: () => any;
|
||||||
|
id: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class BigButton extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
disabled: this.props.disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleClick = this.handleClick.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props: IProps, state: IState) {
|
||||||
|
return {
|
||||||
|
disabled: props.disabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick() {
|
||||||
|
if (this.state.disabled) return
|
||||||
|
|
||||||
|
this.props.onClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className={'BigButton ' + (this.state.disabled ? 'disabled' : '')} onClick={this.handleClick} id={this.props.id}>
|
||||||
|
<div className="BigButtonText">{this.props.children}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/ui/components/common/Checkbox.css
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.Checkbox input[type="checkbox"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CheckboxDisplay {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
|
||||||
|
border: 2px solid #cecece;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CheckboxDisplay:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
border-color: #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CheckboxDisplay img {
|
||||||
|
height: 100%;
|
||||||
|
filter: invert(99%) sepia(0%) saturate(1188%) hue-rotate(186deg) brightness(97%) contrast(67%)
|
||||||
|
}
|
||||||
|
|
||||||
|
.Checkbox label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
54
src/ui/components/common/Checkbox.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import checkmark from '../../../resources/icons/check.svg'
|
||||||
|
|
||||||
|
import './Checkbox.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
label?: string,
|
||||||
|
checked: boolean,
|
||||||
|
onChange: () => void,
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
checked: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Checkbox extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
checked: props.checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props: IProps, state: IState) {
|
||||||
|
if (props.checked !== state.checked) {
|
||||||
|
return {
|
||||||
|
checked: props.checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { checked: props.checked }
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange = () => {
|
||||||
|
this.setState({ checked: !this.state.checked })
|
||||||
|
this.props.onChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="Checkbox">
|
||||||
|
<input type='checkbox' id={this.props.id} checked={this.state.checked} onChange={this.handleChange} />
|
||||||
|
<label htmlFor={this.props.id}>
|
||||||
|
<div className="CheckboxDisplay">
|
||||||
|
{this.state.checked ? <img src={checkmark} alt='Checkmark' /> : null}
|
||||||
|
</div>
|
||||||
|
<span>{this.props.label || ''}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/ui/components/common/DirInput.css
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
.DirInput {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DirInput input {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.FileSelectIcon {
|
||||||
|
height: 20px;
|
||||||
|
margin-left: 10px;
|
||||||
|
filter: invert(99%) sepia(0%) saturate(1188%) hue-rotate(186deg) brightness(97%) contrast(67%);
|
||||||
|
|
||||||
|
transition: filter 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.FileSelectIcon:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
filter: invert(73%) sepia(0%) saturate(380%) hue-rotate(224deg) brightness(94%) contrast(90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.FileSelectIcon img {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
108
src/ui/components/common/DirInput.tsx
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { open } from '@tauri-apps/api/dialog'
|
||||||
|
import { translate } from '../../../utils/language'
|
||||||
|
import TextInput from './TextInput'
|
||||||
|
import File from '../../../resources/icons/folder.svg'
|
||||||
|
|
||||||
|
import './DirInput.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
value?: string
|
||||||
|
clearable?: boolean
|
||||||
|
onChange?: (value: string) => void
|
||||||
|
extensions?: string[]
|
||||||
|
readonly?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
folder?: boolean
|
||||||
|
customClearBehaviour?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
value: string
|
||||||
|
placeholder: string
|
||||||
|
folder: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DirInput extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
value: props.value || '',
|
||||||
|
placeholder: this.props.placeholder || 'Select file or folder...',
|
||||||
|
folder: this.props.folder || false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleIconClick = this.handleIconClick.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props: IProps, state: IState) {
|
||||||
|
const newState = state
|
||||||
|
|
||||||
|
if (props.value && state.value === '') {
|
||||||
|
newState.value = props.value || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.placeholder) {
|
||||||
|
newState.placeholder = props.placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
return newState
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
if (!this.props.placeholder) {
|
||||||
|
const translation = await translate('components.select_file')
|
||||||
|
this.setState( {
|
||||||
|
placeholder: translation
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleIconClick() {
|
||||||
|
let path
|
||||||
|
|
||||||
|
if (this.state.folder) {
|
||||||
|
path = await open({
|
||||||
|
directory: true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
path = await open({
|
||||||
|
filters: [
|
||||||
|
{ name: 'Files', extensions: this.props.extensions || ['*'] }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(path)) path = path[0]
|
||||||
|
if (!path) return
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
value: path
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.props.onChange) this.props.onChange(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className='DirInput'>
|
||||||
|
<TextInput
|
||||||
|
value={this.state.value}
|
||||||
|
placeholder={this.state.placeholder}
|
||||||
|
clearable={this.props.clearable !== undefined ? this.props.clearable : true}
|
||||||
|
readOnly={this.props.readonly !== undefined ? this.props.readonly : true } onChange={(text: string) => {
|
||||||
|
this.setState({ value: text })
|
||||||
|
|
||||||
|
if (this.props.onChange) this.props.onChange(text)
|
||||||
|
this.forceUpdate()
|
||||||
|
}}
|
||||||
|
customClearBehaviour={this.props.customClearBehaviour}
|
||||||
|
/>
|
||||||
|
<div className="FileSelectIcon" onClick={this.handleIconClick}>
|
||||||
|
<img src={File} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/ui/components/common/DownloadList.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.DownloadList {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
32
src/ui/components/common/DownloadList.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import DownloadHandler from '../../../utils/download'
|
||||||
|
import DownloadSection from './DownloadSection'
|
||||||
|
|
||||||
|
import './DownloadList.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
downloadManager: DownloadHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DownloadList extends React.Component<IProps, never> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const list = this.props.downloadManager.getDownloads().map((download) => {
|
||||||
|
return (
|
||||||
|
<DownloadSection key={download.path} downloadName={download.path} downloadManager={this.props.downloadManager} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="DownloadList">
|
||||||
|
{
|
||||||
|
list.length > 0 ? list : 'No downloads present'
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/ui/components/common/DownloadSection.css
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
.DownloadSection span {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadSection {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
margin: 6px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadTitle {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadPath {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 250px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadStatus {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
35
src/ui/components/common/DownloadSection.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import DownloadHandler from '../../../utils/download'
|
||||||
|
import ProgressBar from './ProgressBar'
|
||||||
|
|
||||||
|
import './DownloadSection.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
downloadManager: DownloadHandler;
|
||||||
|
downloadName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DownloadSection extends React.Component<IProps, never> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilenameFromPath() {
|
||||||
|
const name = this.props.downloadName.replace(/\\/g, '/')
|
||||||
|
return name.split('/').pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="DownloadSection">
|
||||||
|
<div className="DownloadTitle">
|
||||||
|
<div className="DownloadPath">{this.getFilenameFromPath()}</div>
|
||||||
|
<div className="DownloadStatus"> - {this.props.downloadManager.getDownloadSize(this.props.downloadName)}</div>
|
||||||
|
</div>
|
||||||
|
<div className="DownloadSectionInner">
|
||||||
|
<ProgressBar path={this.props.downloadName} downloadManager={this.props.downloadManager} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/ui/components/common/HelpButton.css
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
.HelpSection {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.HelpButton {
|
||||||
|
height: 20px;
|
||||||
|
filter: drop-shadow(0px 0px 5px rgb(0 0 0 / 20%));
|
||||||
|
}
|
||||||
|
|
||||||
|
.HelpButton:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.HelpButton img {
|
||||||
|
height: 100%;
|
||||||
|
filter: invert(100%) sepia(2%) saturate(201%) hue-rotate(47deg) brightness(117%) contrast(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.HelpContents {
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.HelpContents .MiniDialog {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
bottom: 40px;
|
||||||
|
right: -450%;
|
||||||
|
width: 200px;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
54
src/ui/components/common/HelpButton.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import './HelpButton.css'
|
||||||
|
import Help from '../../../resources/icons/help.svg'
|
||||||
|
import MiniDialog from '../MiniDialog'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
children?: React.ReactNode[] | React.ReactNode;
|
||||||
|
contents?: string
|
||||||
|
id?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
opened: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class HelpButton extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
opened: false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setOpen = this.setOpen.bind(this)
|
||||||
|
this.setClosed = this.setClosed.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpen() {
|
||||||
|
this.setState({ opened: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
setClosed() {
|
||||||
|
this.setState({ opened: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="HelpSection">
|
||||||
|
<div className="HelpButton" onMouseEnter={this.setOpen} onMouseLeave={this.setClosed}>
|
||||||
|
<img src={Help} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="HelpContents" style={{
|
||||||
|
display: this.state.opened ? 'block' : 'none'
|
||||||
|
}}>
|
||||||
|
<MiniDialog closeFn={this.setClosed}>
|
||||||
|
{this.props.contents || this.props.children}
|
||||||
|
</MiniDialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/ui/components/common/MainProgressBar.tsx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import DownloadHandler from '../../../utils/download'
|
||||||
|
import Tr from '../../../utils/language'
|
||||||
|
import './ProgressBar.css'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
downloadManager: DownloadHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
average: number,
|
||||||
|
files: number,
|
||||||
|
extracting: number,
|
||||||
|
total: number,
|
||||||
|
speed: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component differes because it averages all downloads together
|
||||||
|
*/
|
||||||
|
export default class ProgressBar extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
const { average, files, extracting, totalSize } = this.props.downloadManager.getTotalAverage()
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
average,
|
||||||
|
files,
|
||||||
|
extracting,
|
||||||
|
total: totalSize,
|
||||||
|
speed: '0 B/s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// Periodically check the progress of passed file path
|
||||||
|
setInterval(() => {
|
||||||
|
const prog = this.props.downloadManager.getTotalAverage()
|
||||||
|
this.setState({
|
||||||
|
average: prog?.average || 0,
|
||||||
|
files: prog?.files,
|
||||||
|
extracting: prog?.extracting,
|
||||||
|
total: prog?.totalSize || 0,
|
||||||
|
speed: prog?.speed || '0 B/s',
|
||||||
|
})
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="MainProgressBarWrapper">
|
||||||
|
<div className="ProgressBar">
|
||||||
|
<div className="InnerProgress" style={{
|
||||||
|
width: `${(() => {
|
||||||
|
// Handles no files downloading
|
||||||
|
if (this.state.files === 0) {
|
||||||
|
return '100'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.total <= 0) {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.state.average
|
||||||
|
})()}%`,
|
||||||
|
}}></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="MainProgressText">
|
||||||
|
<Tr text="main.files_downloading" /> {this.state.files} ({this.state.speed})
|
||||||
|
<br />
|
||||||
|
<Tr text="main.files_extracting" /> {this.state.extracting}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
94
src/ui/components/common/ProgressBar.css
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
.ProgressBar, .InnerProgress {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProgressBarWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProgressBar {
|
||||||
|
height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgba(204, 204, 204, 0.5);
|
||||||
|
color: #c5c5c5;
|
||||||
|
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.InnerProgress {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MainProgressText,
|
||||||
|
.ProgressText {
|
||||||
|
color: #c5c5c5;
|
||||||
|
padding: 0px 10px;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MainProgressText {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MainProgressBarWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 1px 1px 14px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MainProgressBarWrapper .MainProgressText {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MainProgressBarWrapper .ProgressBar {
|
||||||
|
box-shadow: 0px 0px 5px 4px rgb(0 0 0 / 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.MainProgressBarWrapper:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProgressBarWrapper div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProgressBarWrapper .InnerProgress {
|
||||||
|
background-color: #ffc61e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProgressBarWrapper .ProgressBar {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadControls {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadControls div {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadControls div img {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.downloadStop:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
89
src/ui/components/common/ProgressBar.tsx
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { capitalize } from '../../../utils/string'
|
||||||
|
|
||||||
|
import Stop from '../../../resources/icons/close.svg'
|
||||||
|
import './ProgressBar.css'
|
||||||
|
import DownloadHandler from '../../../utils/download'
|
||||||
|
import { translate } from '../../../utils/language'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
path: string,
|
||||||
|
downloadManager: DownloadHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
progress: number,
|
||||||
|
status: string,
|
||||||
|
total: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ProgressBar extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
progress: 0,
|
||||||
|
status: '',
|
||||||
|
total: this.props.downloadManager.getDownloadProgress(this.props.path)?.total || 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDownload = this.stopDownload.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// Periodically check the progress of passed file path
|
||||||
|
const intv = setInterval(async () => {
|
||||||
|
const prog = this.props.downloadManager.getDownloadProgress(this.props.path)
|
||||||
|
this.setState({
|
||||||
|
progress: prog?.progress || 0,
|
||||||
|
status: await translate(`download_status.${prog?.status || 'stopped'}`) || 'stopped',
|
||||||
|
total: prog?.total || 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.state.status === 'finished' || this.state.status === 'error') {
|
||||||
|
// Ensure progress is 100%
|
||||||
|
clearInterval(intv)
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
stopDownload() {
|
||||||
|
this.props.downloadManager.stopDownload(this.props.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="ProgressBarWrapper">
|
||||||
|
<div style={{
|
||||||
|
width: '80%'
|
||||||
|
}}>
|
||||||
|
<div className="ProgressBar">
|
||||||
|
<div className="InnerProgress" style={{
|
||||||
|
width: `${(() => {
|
||||||
|
// Handles files with content-lengths of 0
|
||||||
|
if (this.state.status === 'finished') {
|
||||||
|
return '100'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.total <= 0) {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.state.progress / this.state.total * 100
|
||||||
|
})()}%`,
|
||||||
|
}}></div>
|
||||||
|
</div>
|
||||||
|
<div className="DownloadControls">
|
||||||
|
<div onClick={this.stopDownload} className="downloadStop">
|
||||||
|
<img src={Stop}></img>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ProgressText">
|
||||||
|
{capitalize(this.state.status) || 'Waiting'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/ui/components/common/TextInput.css
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
.TextInput {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid #cecece;
|
||||||
|
|
||||||
|
padding-right: 16px;
|
||||||
|
|
||||||
|
transition: border-bottom-color 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextInput:focus {
|
||||||
|
outline: none;
|
||||||
|
border-bottom-color: #ffd326;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextClear {
|
||||||
|
height: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
right: 16%;
|
||||||
|
|
||||||
|
filter: invert(99%) sepia(0%) saturate(1188%) hue-rotate(186deg) brightness(97%) contrast(67%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextClear:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
filter: invert(73%) sepia(0%) saturate(380%) hue-rotate(224deg) brightness(94%) contrast(90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextInputClear {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
70
src/ui/components/common/TextInput.tsx
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import './TextInput.css'
|
||||||
|
import Close from '../../../resources/icons/close.svg'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
value?: string;
|
||||||
|
initalValue?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
onChange?: (value: string) => void;
|
||||||
|
readOnly?: boolean;
|
||||||
|
id?: string;
|
||||||
|
clearable?: boolean;
|
||||||
|
customClearBehaviour?: () => void;
|
||||||
|
style?: {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TextInput extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
value: props.value || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
if (this.props.initalValue) {
|
||||||
|
this.setState({
|
||||||
|
value: this.props.initalValue
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props: IProps, state: IState) {
|
||||||
|
return { value: props.value || state.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="TextInputWrapper" style={this.props.style || {}}>
|
||||||
|
<input id={this.props?.id} readOnly={this.props.readOnly || false} placeholder={this.props.placeholder || ''} className="TextInput" value={this.state.value} onChange={(e) => {
|
||||||
|
this.setState({ value: e.target.value })
|
||||||
|
if (this.props.onChange) this.props.onChange(e.target.value)
|
||||||
|
}} />
|
||||||
|
{
|
||||||
|
this.props.clearable ?
|
||||||
|
<div className="TextClear" onClick={() => {
|
||||||
|
// Run custom behaviour first
|
||||||
|
if (this.props.customClearBehaviour) return this.props.customClearBehaviour()
|
||||||
|
|
||||||
|
this.setState({ value: '' })
|
||||||
|
|
||||||
|
if (this.props.onChange) this.props.onChange('')
|
||||||
|
|
||||||
|
this.forceUpdate()
|
||||||
|
}}>
|
||||||
|
<img src={Close} className="TextInputClear" />
|
||||||
|
</div> : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/ui/components/common/ThemeOptionValue.tsx
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TextInput from './TextInput'
|
||||||
|
import Checkbox from './Checkbox'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Valid types for the theme option value.
|
||||||
|
* - input: A text input.
|
||||||
|
* - dropdown: A select/dropdown input.
|
||||||
|
* - checkbox: A toggle.
|
||||||
|
* - button: A button.
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
type: string;
|
||||||
|
className?: string;
|
||||||
|
jsCallback?: string;
|
||||||
|
data: InputSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
toggled: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InputSettings {
|
||||||
|
/* Input. */
|
||||||
|
placeholder?: string;
|
||||||
|
initialValue?: string;
|
||||||
|
|
||||||
|
/* Dropdown. */
|
||||||
|
options?: string[];
|
||||||
|
|
||||||
|
/* Checkbox. */
|
||||||
|
toggled?: boolean
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
/* Button. */
|
||||||
|
text?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ThemeOptionValue extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
toggled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props: IProps, state: IState) {
|
||||||
|
return { toggled: props.data.toggled || state.toggled }
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const data = this.props.data
|
||||||
|
|
||||||
|
if(this.props.type == 'checkbox')
|
||||||
|
this.setState({ toggled: data.toggled || false })
|
||||||
|
}
|
||||||
|
|
||||||
|
async onChange() {
|
||||||
|
// Change toggled state if needed.
|
||||||
|
if(this.props.type == 'checkbox')
|
||||||
|
this.setState({
|
||||||
|
toggled: !this.state.toggled
|
||||||
|
})
|
||||||
|
|
||||||
|
if(!this.props.jsCallback)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const data = this.props.data
|
||||||
|
|
||||||
|
switch(this.props.type) {
|
||||||
|
case 'input':
|
||||||
|
return (
|
||||||
|
<div className={this.props.className}>
|
||||||
|
<TextInput placeholder={data.placeholder} initalValue={data.initialValue} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
case 'dropdown':
|
||||||
|
return (
|
||||||
|
<div className={this.props.className}>
|
||||||
|
<select>
|
||||||
|
{data.options ? data.options.map((option, index) => {
|
||||||
|
return <option key={index}>{option}</option>
|
||||||
|
}) : null}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
case 'button':
|
||||||
|
return (
|
||||||
|
<div className={this.props.className}>
|
||||||
|
<button>{data.text}</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<div className={this.props.className}>
|
||||||
|
<Checkbox checked={this.state?.toggled} onChange={this.onChange} id={this.props.className || 'a'} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/ui/components/menu/Divider.css
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
.Divider {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DividerLine {
|
||||||
|
width: 60%;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
13
src/ui/components/menu/Divider.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import './Divider.css'
|
||||||
|
|
||||||
|
export default class Divider extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="Divider">
|
||||||
|
<div className="DividerLine"></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/ui/components/menu/Downloads.css
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
.Downloads {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadMenuSection {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
margin-bottom: 12px;
|
||||||
|
width: 90%;
|
||||||
|
min-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadValue {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadValue .BigButton {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadValue .BigButtonText {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DownloadMenuSection .HelpButton img {
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
275
src/ui/components/menu/Downloads.tsx
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Menu from './Menu'
|
||||||
|
import Tr from '../../../utils/language'
|
||||||
|
import DownloadHandler from '../../../utils/download'
|
||||||
|
import { unzip } from '../../../utils/zipUtils'
|
||||||
|
import BigButton from '../common/BigButton'
|
||||||
|
import { dataDir } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
|
import './Downloads.css'
|
||||||
|
import Divider from './Divider'
|
||||||
|
import { getConfigOption, setConfigOption } from '../../../utils/configuration'
|
||||||
|
import { invoke } from '@tauri-apps/api'
|
||||||
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
import HelpButton from '../common/HelpButton'
|
||||||
|
|
||||||
|
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://github.com/Koko-boya/Grasscutter_Resources/archive/refs/heads/main.zip'
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
closeFn: () => void;
|
||||||
|
downloadManager: DownloadHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
grasscutter_downloading: boolean
|
||||||
|
resources_downloading: boolean
|
||||||
|
repo_downloading: boolean
|
||||||
|
grasscutter_set: boolean
|
||||||
|
resources_exist: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Downloads extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
grasscutter_downloading: this.props.downloadManager.downloadingJar(),
|
||||||
|
resources_downloading: this.props.downloadManager.downloadingResources(),
|
||||||
|
repo_downloading: this.props.downloadManager.downloadingRepo(),
|
||||||
|
grasscutter_set: false,
|
||||||
|
resources_exist: false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getGrasscutterFolder = this.getGrasscutterFolder.bind(this)
|
||||||
|
this.downloadGrasscutterStableRepo = this.downloadGrasscutterStableRepo.bind(this)
|
||||||
|
this.downloadGrasscutterDevRepo = this.downloadGrasscutterDevRepo.bind(this)
|
||||||
|
this.downloadGrasscutterStable = this.downloadGrasscutterStable.bind(this)
|
||||||
|
this.downloadGrasscutterLatest = this.downloadGrasscutterLatest.bind(this)
|
||||||
|
this.downloadResources = this.downloadResources.bind(this)
|
||||||
|
this.toggleButtons = this.toggleButtons.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const gc_path = await getConfigOption('grasscutter_path')
|
||||||
|
|
||||||
|
listen('jar_extracted', () => {
|
||||||
|
this.setState({ grasscutter_set: true }, this.forceUpdate)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!gc_path || gc_path === '') {
|
||||||
|
this.setState({
|
||||||
|
grasscutter_set: false,
|
||||||
|
resources_exist: false
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = gc_path.substring(0, gc_path.lastIndexOf('\\'))
|
||||||
|
|
||||||
|
if (gc_path) {
|
||||||
|
const resources_exist: boolean = await invoke('dir_exists', {
|
||||||
|
path: path + '\\resources'
|
||||||
|
}) as boolean && !(await invoke('dir_is_empty', {
|
||||||
|
path: path + '\\resources'
|
||||||
|
})) as boolean
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
grasscutter_set: gc_path !== '',
|
||||||
|
resources_exist
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getGrasscutterFolder() {
|
||||||
|
const path = await getConfigOption('grasscutter_path')
|
||||||
|
let folderPath
|
||||||
|
|
||||||
|
// Set to default if not set
|
||||||
|
if (!path || path === '') {
|
||||||
|
const appdata = await dataDir()
|
||||||
|
folderPath = appdata + 'cultivation\\grasscutter'
|
||||||
|
|
||||||
|
// Early return since its formatted properly
|
||||||
|
return folderPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.includes('/')) {
|
||||||
|
folderPath = path.substring(0, path.lastIndexOf('/'))
|
||||||
|
} else {
|
||||||
|
folderPath = path.substring(0, path.lastIndexOf('\\'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return folderPath
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadGrasscutterStableRepo() {
|
||||||
|
const folder = await this.getGrasscutterFolder()
|
||||||
|
this.props.downloadManager.addDownload(STABLE_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', () =>{
|
||||||
|
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.toggleButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadGrasscutterDevRepo() {
|
||||||
|
const folder = await this.getGrasscutterFolder()
|
||||||
|
this.props.downloadManager.addDownload(DEV_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', () =>{
|
||||||
|
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.toggleButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadGrasscutterStable() {
|
||||||
|
const folder = await this.getGrasscutterFolder()
|
||||||
|
this.props.downloadManager.addDownload(STABLE_DOWNLOAD, folder + '\\grasscutter.zip', () =>{
|
||||||
|
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Also add repo download
|
||||||
|
this.downloadGrasscutterStableRepo()
|
||||||
|
|
||||||
|
this.toggleButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadGrasscutterLatest() {
|
||||||
|
const folder = await this.getGrasscutterFolder()
|
||||||
|
this.props.downloadManager.addDownload(DEV_DOWNLOAD, folder + '\\grasscutter.zip', () =>{
|
||||||
|
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Also add repo download
|
||||||
|
this.downloadGrasscutterDevRepo()
|
||||||
|
|
||||||
|
this.toggleButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadResources() {
|
||||||
|
const folder = await this.getGrasscutterFolder()
|
||||||
|
this.props.downloadManager.addDownload(RESOURCES_DOWNLOAD, folder + '\\resources.zip', async () => {
|
||||||
|
// Delete the existing folder if it exists
|
||||||
|
if (await invoke('dir_exists', {
|
||||||
|
path: folder + '\\resources'
|
||||||
|
})) {
|
||||||
|
await invoke('dir_delete', {
|
||||||
|
path: folder + '\\resources'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await unzip(folder + '\\resources.zip', folder + '\\', () => {
|
||||||
|
// Rename folder to resources
|
||||||
|
invoke('rename', {
|
||||||
|
path: folder + '\\Resources',
|
||||||
|
newName: 'resources'
|
||||||
|
})
|
||||||
|
|
||||||
|
this.toggleButtons()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.toggleButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
async toggleButtons() {
|
||||||
|
const gc_path = await getConfigOption('grasscutter_path')
|
||||||
|
|
||||||
|
// Set states since we know we are downloading something if this is called
|
||||||
|
this.setState({
|
||||||
|
grasscutter_downloading: this.props.downloadManager.downloadingJar(),
|
||||||
|
resources_downloading: this.props.downloadManager.downloadingResources(),
|
||||||
|
repo_downloading: this.props.downloadManager.downloadingRepo(),
|
||||||
|
grasscutter_set: gc_path && gc_path !== '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Menu closeFn={this.props.closeFn} className="Downloads" heading="Downloads">
|
||||||
|
<div className='DownloadMenuSection' id="downloadMenuContainerGCStable">
|
||||||
|
<div className='DownloadLabel' id="downloadMenuLabelGCStable">
|
||||||
|
<Tr text={
|
||||||
|
this.state.grasscutter_set ? 'downloads.grasscutter_stable' : 'downloads.grasscutter_stable_update'
|
||||||
|
} />
|
||||||
|
<HelpButton>
|
||||||
|
<Tr text="help.gc_stable_jar" />
|
||||||
|
</HelpButton>
|
||||||
|
</div>
|
||||||
|
<div className='DownloadValue' id="downloadMenuButtonGCStable">
|
||||||
|
<BigButton disabled={this.state.grasscutter_downloading} onClick={this.downloadGrasscutterStable} id="grasscutterStableBtn" >
|
||||||
|
<Tr text="components.download" />
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='DownloadMenuSection' id="downloadMenuContainerGCDev">
|
||||||
|
<div className='DownloadLabel' id="downloadMenuLabelGCDev">
|
||||||
|
<Tr text={
|
||||||
|
this.state.grasscutter_set ? 'downloads.grasscutter_latest' : 'downloads.grasscutter_latest_update'
|
||||||
|
} />
|
||||||
|
<HelpButton>
|
||||||
|
<Tr text="help.gc_dev_jar" />
|
||||||
|
</HelpButton>
|
||||||
|
</div>
|
||||||
|
<div className='DownloadValue' id="downloadMenuButtonGCDev">
|
||||||
|
<BigButton disabled={this.state.grasscutter_downloading} onClick={this.downloadGrasscutterLatest} id="grasscutterLatestBtn" >
|
||||||
|
<Tr text="components.download" />
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<div className='DownloadMenuSection' id="downloadMenuContainerGCStableData">
|
||||||
|
<div className='DownloadLabel' id="downloadMenuLabelGCStableData">
|
||||||
|
<Tr text={
|
||||||
|
this.state.grasscutter_set ? 'downloads.grasscutter_stable_data' : 'downloads.grasscutter_stable_data_update'
|
||||||
|
} />
|
||||||
|
<HelpButton>
|
||||||
|
<Tr text="help.gc_stable_data" />
|
||||||
|
</HelpButton>
|
||||||
|
</div>
|
||||||
|
<div className='DownloadValue' id="downloadMenuButtonGCStableData">
|
||||||
|
<BigButton disabled={this.state.repo_downloading} onClick={this.downloadGrasscutterStableRepo} id="grasscutterStableRepo" >
|
||||||
|
<Tr text="components.download" />
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='DownloadMenuSection' id="downloadMenuContainerGCDevData">
|
||||||
|
<div className='DownloadLabel' id="downloadMenuLabelGCDevData">
|
||||||
|
<Tr text={
|
||||||
|
this.state.grasscutter_set ? 'downloads.grasscutter_latest_data' : 'downloads.grasscutter_latest_data_update'
|
||||||
|
} />
|
||||||
|
<HelpButton>
|
||||||
|
<Tr text="help.gc_dev_data" />
|
||||||
|
</HelpButton>
|
||||||
|
</div>
|
||||||
|
<div className='DownloadValue' id="downloadMenuButtonGCDevData">
|
||||||
|
<BigButton disabled={this.state.repo_downloading} onClick={this.downloadGrasscutterStableRepo} id="grasscutterDevRepo" >
|
||||||
|
<Tr text="components.download" />
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<div className='DownloadMenuSection' id="downloadMenuContainerResources">
|
||||||
|
<div className='DownloadLabel' id="downloadMenuLabelResources">
|
||||||
|
<Tr text="downloads.resources" />
|
||||||
|
<HelpButton>
|
||||||
|
<Tr text="help.resources" />
|
||||||
|
</HelpButton>
|
||||||
|
</div>
|
||||||
|
<div className='DownloadValue' id="downloadMenuButtonResources">
|
||||||
|
<BigButton disabled={this.state.resources_downloading || !this.state.grasscutter_set || this.state.resources_exist} onClick={this.downloadResources} id="resourcesBtn" >
|
||||||
|
<Tr text="components.download" />
|
||||||
|
</BigButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/ui/components/menu/Game.css
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
.GameDownloadMenu {
|
||||||
|
width: 40%;
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameDownload {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameDownload .MiniDialog {
|
||||||
|
height: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameDownload .BigButton {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameDownload .HelpButton img {
|
||||||
|
filter: invert(0%) sepia(91%) saturate(7464%) hue-rotate(101deg) brightness(0%) contrast(107%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameDownloadDir {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameDownloadDir .DirInput .TextInputWrapper,
|
||||||
|
.GameDownloadDir .DirInput {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GameDownloadDir .DirInput .TextInputWrapper input {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
83
src/ui/components/menu/Game.tsx
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Menu from './Menu'
|
||||||
|
import Tr, { translate } from '../../../utils/language'
|
||||||
|
import DownloadHandler from '../../../utils/download'
|
||||||
|
|
||||||
|
import './Game.css'
|
||||||
|
import DirInput from '../common/DirInput'
|
||||||
|
import BigButton from '../common/BigButton'
|
||||||
|
import HelpButton from '../common/HelpButton'
|
||||||
|
import { unzip } from '../../../utils/zipUtils'
|
||||||
|
|
||||||
|
const GAME_DOWNLOAD = ''
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
closeFn: () => void;
|
||||||
|
downloadManager: DownloadHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
gameDownloading: boolean;
|
||||||
|
gameDownloadFolder: string;
|
||||||
|
dirPlaceholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Downloads extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
gameDownloading: false,
|
||||||
|
gameDownloadFolder: '',
|
||||||
|
dirPlaceholder: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
this.downloadGame = this.downloadGame.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
this.setState({
|
||||||
|
dirPlaceholder: await translate('components.select_folder')
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(this.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadGame() {
|
||||||
|
const folder = this.state.gameDownloadFolder
|
||||||
|
this.props.downloadManager.addDownload(GAME_DOWNLOAD, folder + '\\game.zip', () =>{
|
||||||
|
unzip(folder + '\\game.zip', folder + '\\', () => {
|
||||||
|
this.setState({
|
||||||
|
gameDownloading: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
gameDownloading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Menu heading='Download Game' closeFn={this.props.closeFn} className="GameDownloadMenu">
|
||||||
|
<div className="GameDownload">
|
||||||
|
{
|
||||||
|
this.state.gameDownloadFolder !== '' && !this.state.gameDownloading ?
|
||||||
|
<BigButton id="downloadGameBtn" onClick={this.downloadGame}>Download Game</BigButton>
|
||||||
|
: <BigButton id="disabledGameBtn" onClick={() => null} disabled>Download Game</BigButton>
|
||||||
|
}
|
||||||
|
<HelpButton>
|
||||||
|
<Tr text="main.game_help_text" />
|
||||||
|
</HelpButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="GameDownloadDir">
|
||||||
|
<DirInput folder placeholder={this.state.dirPlaceholder} clearable={false} readonly={true} onChange={(value: string) => this.setState({
|
||||||
|
gameDownloadFolder: value
|
||||||
|
})}/>
|
||||||
|
</div>
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/ui/components/menu/Menu.css
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
.Menu {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 99;
|
||||||
|
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
height: 70%;
|
||||||
|
width: 60%;
|
||||||
|
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuInner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuHeading {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuTop {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuExit {
|
||||||
|
height: 30px;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuExit:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuExit img {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||