mirror of
https://github.com/Grasscutters/GrassClipper.git
synced 2024-08-14 13:11:48 +08:00
Compare commits
102 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7368963399 | ||
|
b2873efcc5 | ||
|
5e782857b8 | ||
|
224a8b9041 | ||
|
957440ec38 | ||
|
b0638e7b76 | ||
|
f09eb6ceb1 | ||
|
89dd29a528 | ||
|
45015ae509 | ||
|
2484d0bc6b | ||
|
c2383577d1 | ||
|
66b6330c73 | ||
|
e6854d454f | ||
|
9897b3fe49 | ||
|
2cc581aff4 | ||
|
ae0578b8f5 | ||
|
06d95b3165 | ||
|
17254dcc5b | ||
|
3dce59e869 | ||
|
797f760094 | ||
|
f4f98d1847 | ||
|
ed59684ac9 | ||
|
c72e00f784 | ||
|
f2cdab068a | ||
|
60569bf0b1 | ||
|
98762a310e | ||
|
2ded1f69ae | ||
|
fecd82fe75 | ||
|
b9a77ab8f1 | ||
|
376171b2cf | ||
|
5f81ced09f | ||
|
4a32d1fb41 | ||
|
71235a59c3 | ||
|
a73c3ed5cd | ||
|
8951974633 | ||
|
7094277199 | ||
|
9a09182973 | ||
|
67dc692270 | ||
|
055abef5ce | ||
|
37d1761813 | ||
|
b03de8a055 | ||
|
a9a7cc2e45 | ||
|
6ccbaa1f24 | ||
|
24bc47a72c | ||
|
98657a8270 | ||
|
5e80d59ed7 | ||
|
b6adec4079 | ||
|
f3534a3fff | ||
|
4c2e303c6e | ||
|
4971d7a4b0 | ||
|
d8b753f6e8 | ||
|
34ad43cdcb | ||
|
a4cf3ee7d4 | ||
|
1dba3f682c | ||
|
8c8bd4476c | ||
|
b4760fae9a | ||
|
35d2d4de77 | ||
|
90fd5e6204 | ||
|
5d8f8fe09d | ||
|
af225781e3 | ||
|
73b1a93039 | ||
|
acb7d9ef91 | ||
|
19fcfa446c | ||
|
61ebbaf72e | ||
|
5843f0d589 | ||
|
412be98a05 | ||
|
72a9d77dd5 | ||
|
a5303e7192 | ||
|
f4b506435d | ||
|
06fd68e72b | ||
|
dc7c766499 | ||
|
a69e36d7bb | ||
|
7c405a31fd | ||
|
00d8d57e66 | ||
|
5ff0654413 | ||
|
b33551d9b2 | ||
|
5cf37bd8d2 | ||
|
351d6daa34 | ||
|
af7d241c63 | ||
|
f268a37dc7 | ||
|
06f4efef8e | ||
|
ba1ef063f9 | ||
|
35608adf68 | ||
|
7c3e1b87ec | ||
|
bbb20e0704 | ||
|
36aa7b73e3 | ||
|
d562957f23 | ||
|
ccbad14029 | ||
|
e8fe7e316f | ||
|
25d3792930 | ||
|
d7509bd205 | ||
|
89c9d310ef | ||
|
55ccb6dc69 | ||
|
92b2d1be9a | ||
|
de54cc60a1 | ||
|
e0d3ed4948 | ||
|
a55db33f42 | ||
|
73a3d173e8 | ||
|
6c0d8c2a19 | ||
|
223790b0bd | ||
|
5cc2091764 | ||
|
55e3a8f6f2 |
@ -12,6 +12,7 @@
|
|||||||
"no-undef": 0,
|
"no-undef": 0,
|
||||||
"no-unused-vars": 0,
|
"no-unused-vars": 0,
|
||||||
"no-case-declarations": 0,
|
"no-case-declarations": 0,
|
||||||
|
"no-control-regex": 0,
|
||||||
|
|
||||||
"indent": [
|
"indent": [
|
||||||
"error",
|
"error",
|
||||||
|
41
README.md
41
README.md
@ -1,7 +1,15 @@
|
|||||||
# GrassClipper
|
# Please for the love of god do not install GrassClipper into a path in OneDrive
|
||||||
Grasscutter launcher for easily switching between Official and Private servers
|
|
||||||
|
|
||||||
[Download Here!](https://github.com/Grasscutters/GrassClipper/releases/)
|
# ! NOTICE !
|
||||||
|
The previously mentioned **new launcher**: [Cultivation](https://github.com/Grasscutters/Cultivation) has been "released"!\
|
||||||
|
If you are experiencing problems with GrassClipper, we encourage you to try and checkout the new launcher.
|
||||||
|
|
||||||
|
# GrassClipper
|
||||||
|
EN | [PL](README_PL.md) | [ID](README_id.md)
|
||||||
|
|
||||||
|
Experimental Grasscutter launcher for easily switching between Official and Private servers
|
||||||
|
|
||||||
|
[Download Here!](https://github.com/Grasscutters/GrassClipper/releases/) (Supports Windows 8+)
|
||||||
|
|
||||||
*\*Note: some translations are outdated, so if random English text appears or an option seems misleading, this is why. If you notice an issue like this, feel free to make a pull request!*
|
*\*Note: some translations are outdated, so if random English text appears or an option seems misleading, this is why. If you notice an issue like this, feel free to make a pull request!*
|
||||||
|
|
||||||
@ -11,6 +19,7 @@ Grasscutter launcher for easily switching between Official and Private servers
|
|||||||
* [Setup (for development)](#setup-for-development)
|
* [Setup (for development)](#setup-for-development)
|
||||||
* [TODO](#todo)
|
* [TODO](#todo)
|
||||||
* [Common Problems](#having-problems)
|
* [Common Problems](#having-problems)
|
||||||
|
* [Proxy Installation not Opening/Failing](#manual-proxy-installation)
|
||||||
* [White Screen Fix](#white-screen-fix)
|
* [White Screen Fix](#white-screen-fix)
|
||||||
* [Error 502](#error-502)
|
* [Error 502](#error-502)
|
||||||
* [Error 4206](#error-4206)
|
* [Error 4206](#error-4206)
|
||||||
@ -45,10 +54,10 @@ Grasscutter launcher for easily switching between Official and Private servers
|
|||||||
* [x] Fun fancy CSS styling n stuff (CoD: MW 2019-style vertical menu for choosing between official and private servers? [See this](https://charlieintel.com/wp-content/uploads/2020/11/MW-new-menu.png))
|
* [x] Fun fancy CSS styling n stuff (CoD: MW 2019-style vertical menu for choosing between official and private servers? [See this](https://charlieintel.com/wp-content/uploads/2020/11/MW-new-menu.png))
|
||||||
* [x] Kill switch script (optional)
|
* [x] Kill switch script (optional)
|
||||||
* [x] Automatically run `install.cmd` when opening for the first time
|
* [x] Automatically run `install.cmd` when opening for the first time
|
||||||
* [ ] Grasscutter auto-downloader
|
* [x] Grasscutter auto-downloader
|
||||||
* [ ] Detect when in a folder that is inaccessible to the program (eg. `C:/Program Files`) and warn
|
* [ ] Detect when in a folder that is inaccessible to the program (eg. `C:/Program Files`) and warn
|
||||||
* [ ] Custom images for private server sections (anyone is welcome to submit a pull request to add some!)
|
* [ ] Custom images for private server sections (anyone is welcome to submit a pull request to add some!)
|
||||||
* [ ] Optional username/password creation for servers before entering (not implemented in Grasscutter yet)
|
* [x] Optional username/password creation for servers before entering (not implemented in Grasscutter yet)
|
||||||
* [ ] Platform detection and bash scripts
|
* [ ] Platform detection and bash scripts
|
||||||
* [ ] Integrated banner creator
|
* [ ] Integrated banner creator
|
||||||
* Proxy service
|
* Proxy service
|
||||||
@ -60,6 +69,15 @@ Grasscutter launcher for easily switching between Official and Private servers
|
|||||||
|
|
||||||
Below are some scenarios you may encounter and their solutions.
|
Below are some scenarios you may encounter and their solutions.
|
||||||
|
|
||||||
|
# Manual Proxy Installation
|
||||||
|
|
||||||
|
If you having trouble installing the proxy server, you can also install it manually. To do so:
|
||||||
|
1. Create a folder if it does not exist named `ext` in the GrassClipper folder.
|
||||||
|
2. Download and extract the contents of [this file](https://snapshots.mitmproxy.org/7.0.4/mitmproxy-7.0.4-windows.zip) into the `ext` folder
|
||||||
|
3. Double click `mitmdump.exe` and allow it to run for a few seconds to generate the certificate
|
||||||
|
4. Run this command as Administrator: `certutil -addstore root "%USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer"`
|
||||||
|
5. Use GrassClipper like normal!
|
||||||
|
|
||||||
## White Screen Fix
|
## White Screen Fix
|
||||||
|
|
||||||
Encountering a white screen? [Ensure WebView2 is installed](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download)
|
Encountering a white screen? [Ensure WebView2 is installed](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download)
|
||||||
@ -69,6 +87,8 @@ You may also want to run this command as administrator:
|
|||||||
|
|
||||||
If you have Chinese characters in your file path, this may crash it too! I am working on a fix.
|
If you have Chinese characters in your file path, this may crash it too! I am working on a fix.
|
||||||
|
|
||||||
|
You can also try running in Windows 8 compatitbility mode.
|
||||||
|
|
||||||
If all else fails, you can run GrassClipper in `chrome` or `browser` mode. To do so:
|
If all else fails, you can run GrassClipper in `chrome` or `browser` mode. To do so:
|
||||||
* Create a shortcut to `GrassClipper.exe`
|
* Create a shortcut to `GrassClipper.exe`
|
||||||
* Right click the shortcut, click `properties`
|
* Right click the shortcut, click `properties`
|
||||||
@ -80,6 +100,8 @@ If all else fails, you can run GrassClipper in `chrome` or `browser` mode. To do
|
|||||||
|
|
||||||
## Error 502
|
## Error 502
|
||||||
|
|
||||||
|
***You may be using the wrong port, ensure your port in GrassClipper is either 443 or nothing (not 0, but literally nothing)***
|
||||||
|
|
||||||
1. If you are running a local server, ensure the local server is running. Otherwise, ensure the server you are connecting to is actually running.
|
1. If you are running a local server, ensure the local server is running. Otherwise, ensure the server you are connecting to is actually running.
|
||||||
|
|
||||||
2. If you are able, [use the development branch of Grasscutter](https://github.com/Grasscutters/Grasscutter/tree/development). It is known to work better with GrassClipper.
|
2. If you are able, [use the development branch of Grasscutter](https://github.com/Grasscutters/Grasscutter/tree/development). It is known to work better with GrassClipper.
|
||||||
@ -113,14 +135,19 @@ Thank you to everyone who has provided translations! <3
|
|||||||
|
|
||||||
* ZH - nuoxianCN, Scirese & MrAru
|
* ZH - nuoxianCN, Scirese & MrAru
|
||||||
* ZH-TW - Kimi & KormiMeiko
|
* ZH-TW - Kimi & KormiMeiko
|
||||||
* PT-BR - na.na
|
* PT-BR - na.na & actuallyeunha
|
||||||
* VIE - labalityowo
|
* VIE - labalityowo & lunaticwhat
|
||||||
* ID - Iqrar99 & nautilust
|
* ID - Iqrar99 & nautilust
|
||||||
* FR - linsorak & memetrollsXD
|
* FR - linsorak & memetrollsXD
|
||||||
* ES - memetrollsXD
|
* ES - memetrollsXD
|
||||||
* ND - memetrollsXD
|
* ND - memetrollsXD
|
||||||
* RU - fitiskin
|
* RU - fitiskin
|
||||||
* TR - lilmayofuksu
|
* TR - lilmayofuksu
|
||||||
|
* JP - conochy
|
||||||
|
* HD - Arikatsu
|
||||||
|
* PL - zakhil-dev
|
||||||
|
* TH - ongsalt
|
||||||
|
* KO - tsukiroku
|
||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
|
|
||||||
|
152
README_PL.md
Normal file
152
README_PL.md
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# GrassClipper
|
||||||
|
[EN](README.md) | PL | [ID](README_id.md)
|
||||||
|
|
||||||
|
Experymentalny launcher Grasscutter'a stworzony dla łatwego przełączania się pomiędzy serwerami oficjalnymi, a prywatnymi
|
||||||
|
|
||||||
|
[Pobierz tutaj!](https://github.com/Grasscutters/GrassClipper/releases/) (Wspiera Windows'a 8+)
|
||||||
|
|
||||||
|
*\*Uwaga: niektóre tłumaczenia są nie aktualne, więc jeżeli widzisz tekst po angielsku, lub jakiś tekst wprowadza w błąd, to to jest powodem. W przypadku zauważenia takiego błędu, śmiało otwórz pull request'a!*
|
||||||
|
|
||||||
|
# Spis treści
|
||||||
|
|
||||||
|
* [Instalacja (dla użytkownika)](#instalacja-dla-użytkownika)
|
||||||
|
* [Instalacja (dla developera)](#instalacja-dla-developera)
|
||||||
|
* [Do zrobienia](#do-zrobienia)
|
||||||
|
* [Częste problmy](#napotkałeś-problem?)
|
||||||
|
* [Instalacja proxy nie uruchamia się / nie powodzi się](#ręczna-instalacja-proxy)
|
||||||
|
* [Naprawa białego ekranu](#naprawa-białego-ekranu)
|
||||||
|
* [Błąd 502](#błąd-502)
|
||||||
|
* [Błąd 4206](#błąd-4206)
|
||||||
|
* [Nieskończone okna CMD](#nieskończone-okna-CMD)
|
||||||
|
* [Niedziałający Discord/Youtube](#discord-nie-pozwala-wysyłać-mi-wiadomości-lub-wczytywać-obrazków/YouTube-dziwnie-się-zachowuje)
|
||||||
|
* [Brak internetu](#nie-mam-dostępu-do-internetu-po-zamknięciu-wszystkiego/restarcie-komputera!)
|
||||||
|
* [Dostępne tłumaczenia oraz ich autorzy](#dostępne-tłumaczenia-oraz-ich-autorzy)
|
||||||
|
* [Zrzuty ekranu](#zrzuty-ekranu)
|
||||||
|
|
||||||
|
# Instalacja (dla użytkownika)
|
||||||
|
|
||||||
|
1. Pobierz plik zip
|
||||||
|
2. Wypakuj gdzieś plik zip
|
||||||
|
3. Uruchom `GrassClipper.exe`, zainstaluj serwer proxy oraz ustaw folder z grą!
|
||||||
|
|
||||||
|
# Instalacja (dla developera)
|
||||||
|
|
||||||
|
0. Sklonuj repozytorium
|
||||||
|
1. Upewnij się, że masz zainstalowanego [NodeJS'a](https://nodejs.org/en/download/).
|
||||||
|
2. Zainstaluj narzędzie `neu` CLI: `npm install -g @neutralinojs/neu`
|
||||||
|
3. Zainstaluj zależności: `setup_win.cmd`
|
||||||
|
4. Skompiluj i uruchom:
|
||||||
|
* Testowanie: `npm run dev`
|
||||||
|
* Produkcja: `npm run build`
|
||||||
|
|
||||||
|
# Do zrobienia
|
||||||
|
|
||||||
|
* Interfejst/wewnętrzne
|
||||||
|
* [x] UI
|
||||||
|
* [x] Opcje Oficjalny i Prywatny
|
||||||
|
* [x] Wprowadzanie IP serwera
|
||||||
|
* [x] Stylowanie CSS - Pionowe menu do wybierania pomiędzy oficjalnym, a prywatnym serwerem? (Stylizowane na CoD: MW 2019) [Zobacz tutaj](https://charlieintel.com/wp-content/uploads/2020/11/MW-new-menu.png))
|
||||||
|
* [x] Skrypt Kill Switch (opcjonalne)
|
||||||
|
* [x] Automatyczne uruchamianie `install.cmd`, jeżeli uruchamamy program po raz pierwszy
|
||||||
|
* [x] Auto-pobieranie Grasscutter'a
|
||||||
|
* [ ] Wykrywanie gdy program jest uruchomiony w folderze, do którego nie ma dostępu (np. `C:/Program Files`) i wysyłanie ostrzeżenia.
|
||||||
|
* [ ] Nowe obrazki dla sekcji serwera prywatnego (Pull request'y od wszystkich są mile widziane!)
|
||||||
|
* [x] Opcjonalne tworzenie loginu/hasła dla serwera przed połączeniem (nie zaimplementowane jeszcze w Grasscutter)
|
||||||
|
* [ ] Wykrywanie systemu i skrypty bash
|
||||||
|
* [ ] Zintegrowany kreator bannerów
|
||||||
|
* Usługa proxy
|
||||||
|
* [x] Lokalny serwer proxy
|
||||||
|
* [x] Przechwytywanie i modyfikowanie zapytań GI, np. przy użyciu Fiddler'a, przepuszczanie wszystkigo innego.
|
||||||
|
* [ ] Naprawienie problemów z Discordem i YouTube'm gdy proxy jest włączone (może naprawione)
|
||||||
|
|
||||||
|
# Napotkałeś problem?
|
||||||
|
|
||||||
|
Poniżej znajdują się najczęściej pojawiające się problemy oraz ich rozwiązania.
|
||||||
|
|
||||||
|
## Ręczna instalacja proxy
|
||||||
|
|
||||||
|
Jeżeli napotkałeś problemy z automatyczną instalacją proxy, możesz zainstalować je ręcznie. <br>
|
||||||
|
W tym celu:
|
||||||
|
1. Jeżeli nie istnieje stwórz folder `ext` w folderze GrassClipper'a.
|
||||||
|
2. Pobierz i wypakuj zawartość [tego pliku](https://snapshots.mitmproxy.org/7.0.4/mitmproxy-7.0.4-windows.zip) do folderu `ext`
|
||||||
|
3. Uruchom `mitmdump.exe` i poczekaj kilka chwil, żeby wygenerował certyfikat.
|
||||||
|
4. Wywołaj to polecenie jako Administrator: `certutil -addstore root "%USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer"`
|
||||||
|
5. GrassClipper powinien działać poprawnie!
|
||||||
|
|
||||||
|
## Naprawa białego ekranu
|
||||||
|
|
||||||
|
Napotkałeś biały ekran? Upewnij się czy [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download) jest zainstalowany.
|
||||||
|
|
||||||
|
Wywołanie tego polecenia jako Administrator również może pomóc:
|
||||||
|
`CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy"`
|
||||||
|
|
||||||
|
Jeżeli w twojej ścieżce do pliku występują chińskie symbole, to mogą one być tego przyczyną. Pracujemy nad poprawką.
|
||||||
|
|
||||||
|
Możesz spróbować uruchomić aplikacje w trybie zgodności z Windows'em 8
|
||||||
|
|
||||||
|
Jeżeli nic z tego nie pomoże, możesz uruchomić GrassClipper'a w trybie `chrome` lub `browser`. W tym celu:
|
||||||
|
* Stwórz skrót do `GrassClipper.exe`
|
||||||
|
* Kliknij na niego prawym przyciskiem, wybierz `Właściwości`
|
||||||
|
* W polu `Element docelowy`, na samym końcu, dodaj ` --mode=chrome` lub ` --mode=browser`
|
||||||
|
* `chrome` działa tylko wtedy gdy masz zainstalowanego Chrome'a, otworzy okienko Chrome'a
|
||||||
|
* `brower` otworzy GrassClippera w twojej domyślnej przeglądarce
|
||||||
|
* Kliknij `Ok`
|
||||||
|
* Od teraz uruchamiaj GrassClippera nowo stworzonym skrótem.
|
||||||
|
|
||||||
|
## Błąd 502
|
||||||
|
|
||||||
|
1. Jeżeli dołączas na serwer lokalny to upewnij się czy jest włączony. W przeciwnym wypadku, upewnij się, czy serwer do którego się łączysz działa.
|
||||||
|
|
||||||
|
2. Jeżeli to możliwe, [użyj wersji developerskiej Grasscutter'a](https://github.com/Grasscutters/Grasscutter/tree/development). Z tego co wiadomo to działa lepiej z GrassClipper'em.
|
||||||
|
|
||||||
|
Jeżeli dalej dostajesz błąd 502 przy próbie logowania do własnego serwera, otwórz plik `config.json` w folderze Grasscutter'a i dodaj w nim w sekcji `DispatchServer`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"PublicPort": TWÓJ_PORT
|
||||||
|
```
|
||||||
|
|
||||||
|
`TWÓJ_PORT` jest tym samym portem co w polu `Port`. Jest to prawdopodobnie wartość 443.
|
||||||
|
|
||||||
|
## Błąd 4206
|
||||||
|
|
||||||
|
Upewnij się, że posiadasz odpowiedni plik `keystore.p12` dla twojej wersji. Sprawdź, czy hasło jest poprawnie ustawione w pliku `config.json` (puste dla wersji `stabilnej`, "123456" dla wersji `developerskiej`).
|
||||||
|
|
||||||
|
## Nieskończone okna CMD
|
||||||
|
|
||||||
|
Jeżeli jakikolwiek skrypt uruchamia nieskończoność okien CMD (np. instalator proxy albo starter serwera prywatnego), upewnij się, że UAC (User Access Control) jest ustawiony na dowolną opcje która wymaga potwierdzenia. Sprawdź czy twoje konto może uruchamiać programy jako Administrator.
|
||||||
|
|
||||||
|
## Discord nie pozwala wysyłać mi wiadomości lub wczytywać obrazków/YouTube dziwnie się zachowuje
|
||||||
|
|
||||||
|
Discord/Youtube (i na pewno pare innych) nie przepadają za serwerem proxy. Musisz go wyłączyć zamykając mitmdump, albo wyłączając proxy w ustawieniach Windowsa.
|
||||||
|
|
||||||
|
## Nie mam dostępu do internetu po zamknięciu wszystkiego/restarcie komputera!
|
||||||
|
|
||||||
|
Launcher najprawdopodobniej nie został poprawnie zamknięty, przez co nie był w stanie przywrócić oryginalnych ustawień proxy. Wyłącz proxy w ustawieniach Windows'a.
|
||||||
|
|
||||||
|
# Dostępne tłumaczenia oraz ich autorzy
|
||||||
|
|
||||||
|
Dziękujemy dla wszystkich, którzy pomagają w tłumaczeniu! <3
|
||||||
|
|
||||||
|
* ZH - nuoxianCN, Scirese & MrAru
|
||||||
|
* ZH-TW - Kimi & KormiMeiko
|
||||||
|
* PT-BR - na.na
|
||||||
|
* VIE - labalityowo
|
||||||
|
* ID - Iqrar99 & nautilust
|
||||||
|
* FR - linsorak & memetrollsXD
|
||||||
|
* ES - memetrollsXD
|
||||||
|
* ND - memetrollsXD
|
||||||
|
* RU - fitiskin
|
||||||
|
* TR - lilmayofuksu
|
||||||
|
* JP - conochy
|
||||||
|
* HD - Arikatsu
|
||||||
|
* PL - zakhil-dev
|
||||||
|
|
||||||
|
# Zrzuty ekranu
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
152
README_id.md
Normal file
152
README_id.md
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# GrassClipper
|
||||||
|
[EN](README.md) | [PL](README_PL.md) | ID
|
||||||
|
|
||||||
|
Peluncur eksperimental Grasscutter untuk memudahkan penggantian antara server resmi (Official) dan server pribadi
|
||||||
|
|
||||||
|
[Unduh Disini!](https://github.com/Grasscutters/GrassClipper/releases/) (Mendukung Windows 8 keatas)
|
||||||
|
|
||||||
|
*\*Catatan: Beberapa terjemahan mungkin ada yang sudah usang, kalau ada bahasa Inggris yang muncul secara acak pada teks atau opsi pilihan mungkin ini penyebabnya. Jika kamu melihat masalah seperti ini, jangan ragu untuk membuat pull request!*
|
||||||
|
|
||||||
|
# Daftar Isi
|
||||||
|
|
||||||
|
* [Setup (untuk pengguna)](#setup-untuk-pengguna)
|
||||||
|
* [Setup (untuk pengembang)](#setup-untuk-pengembang)
|
||||||
|
* [Daftar yang Harus Dilakukan](#daftar-yang-harus-dilakukan)
|
||||||
|
* [Masalah Umum](#punya-masalah)
|
||||||
|
* [Pemasangan Proxy Tidak Terbuka/Gagal](#pemasangan-manual-proxy)
|
||||||
|
* [Perbaikan Layar Putih](#perbaikan-layar-putih)
|
||||||
|
* [Kesalahan 502](#kesalahan-502)
|
||||||
|
* [Kesalahan 4206](#kesalahan-4206)
|
||||||
|
* [Jendela CMD Terbuka Terus-menerus](#jendela-cmd-terbuka-terus-menerus)
|
||||||
|
* [Discord/Youtube Tidak Berfungsi dengan Baik](#discord-tidak-bisa-mengirim-pesan-atau-memuat-gambar-atau-youtube-tidak-tampil-dengan-baik)
|
||||||
|
* [Tidak Ada Koneksi Internet](#komputerku-tidak-ada-akses-internet-setelah-menutup-peluncur-atau-restart)
|
||||||
|
* [Bahasa dan Kredit Terjemahan](#bahasa-yang-tersedia-dan-kredit-penerjemah)
|
||||||
|
* [Tangkapan Layar](#tangkapan-layar)
|
||||||
|
|
||||||
|
# Setup (untuk Pengguna)
|
||||||
|
|
||||||
|
1. Unduh file zip nya
|
||||||
|
2. Ekstrak file zip nya di sembarang tempat atau tempat yang sudah ditentukan
|
||||||
|
3. Jalankan `GrassClipper.exe`, pasang server proxy nya, dan atur folder game nya!
|
||||||
|
|
||||||
|
# Setup (untuk Pengembang)
|
||||||
|
|
||||||
|
0. Clone/unduh repositori ini
|
||||||
|
1. Pastikan kamu punya [NodeJS](https://nodejs.org/en/download/) yang sudah terpasang.
|
||||||
|
2. Pasang alat CLI `neu`: `npm install -g @neutralinojs/neu`
|
||||||
|
3. Pasang dependensinya: `setup_win.cmd`
|
||||||
|
4. Kompilasi dan jalankan:
|
||||||
|
* Untuk pengujian: `npm run dev`
|
||||||
|
* Untuk produksi: `npm run build`
|
||||||
|
|
||||||
|
# Daftar yang Harus Dilakukan
|
||||||
|
|
||||||
|
* Antarmuka/internal
|
||||||
|
* [x] UI
|
||||||
|
* [x] Opsi server resmi (Official) dan pribadi
|
||||||
|
* [x] IP server masukan
|
||||||
|
* [x] Penataan gaya CSS yang wah! (Seperti gaya menu vertikal ala CoD: MW 2019 untuk memilih antara server resmi (official) dan pribadi? [Lihat disini](https://charlieintel.com/wp-content/uploads/2020/11/MW-new-menu.png))
|
||||||
|
* [x] Skrip saklar mati (opsional)
|
||||||
|
* [x] Otomatis menjalankan `install.cmd` ketika membuka GrassClipper untuk pertama kalinya
|
||||||
|
* [x] Pengunduh otomatis Grasscutter
|
||||||
|
* [ ] Deteksi saat berada di folder yang tidak dapat diakses oleh program (contohnya `C:/Program Files`) dan ingatkan
|
||||||
|
* [ ] Gambar kustom untuk bagian server pribadi (siapapun dipersilahkan mengirimkan pull request untuk menambahkan gambar lainnya!)
|
||||||
|
* [x] Nama pengguna/kata sandi opsional sebelum memasuki server (belum terimplementasi di Grasscutter)
|
||||||
|
* [ ] Deteksi platform dan skrip bash
|
||||||
|
* [ ] Pembuat spanduk terintegrasi
|
||||||
|
* Layanan Proxy
|
||||||
|
* [x] Server lokal proxy
|
||||||
|
* [x] Cegat dan ubah permintaan GI seperti dengan Fiddler, izinkan yang lain melewati
|
||||||
|
* [ ] Perbaiki masalah Discord dan YouTube saat proxy diaktifkan (mungkin diperbaiki)
|
||||||
|
|
||||||
|
# Punya masalah?
|
||||||
|
|
||||||
|
Dibawah ini mungkin beberapa skenario yang kamu hadapi dan beserta solusinya.
|
||||||
|
|
||||||
|
# Pemasangan Manual Proxy
|
||||||
|
|
||||||
|
Jika kamu punya masalah saat memasang server proxy, kamu juga dapat memasangnya secara manual. Cara memasangnya:
|
||||||
|
1. Buat sebuah folder yang bernama `ext` di folder GrassClipper jika folder tersebut tidak ada.
|
||||||
|
2. Unduh dan ekstrak isi konten dari [file ini](https://snapshots.mitmproxy.org/7.0.4/mitmproxy-7.0.4-windows.zip) ke dalam folder `ext`
|
||||||
|
3. Klik dua kali `mitmdump.exe` dan izinkan untuk menjalankan beberapa detik agar bisa membuat sertifikat
|
||||||
|
4. Jalankan perintah ini sebagai Administrator: `certutil -addstore root "%USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer"`
|
||||||
|
5. Gunakan GrassClipper seperti biasa!
|
||||||
|
|
||||||
|
## Perbaikan Layar Putih
|
||||||
|
|
||||||
|
Mengalami layar putih? [Pastikan WebView2 terpasang](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download)
|
||||||
|
|
||||||
|
Kamu mungkin perlu menjalankan perintah ini sebagai Administrator:
|
||||||
|
`CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy"`
|
||||||
|
|
||||||
|
Jika kamu mempunyai karakter Cina di jalur file mu, mungkin ini dapat menyebabkan crash! Saya sedang mengerjakan perbaikannya.
|
||||||
|
|
||||||
|
Kamu mungkin bisa juga menjalankan ini di mode kompatibilitas Windows 8.
|
||||||
|
|
||||||
|
Jika semuanya gagal, kamu bisa menjalankan GrassClipper di mode `chrome` atau `browser`. Cara melakukannya:
|
||||||
|
* Buat sebuah shortcut ke `GrassClipper.exe`
|
||||||
|
* Klik kanan shortcut tersebut, lalu klik `Properties`
|
||||||
|
* Di dalam kotak `Target`, pada bagian akhirnya, tambahkan ` --mode=chrome` atau ` --mode=browser`
|
||||||
|
* `chrome` hanya bisa bekerja jika kamu punya Chrome yang terpasang dan akan membuat jendela Chrome
|
||||||
|
* Untuk `browser` seperti yang kamu tebak, akan membuka GrassClipper di default browser mu
|
||||||
|
* Klik `Ok`
|
||||||
|
* Jalankan GrassClipper dengan menggunakan shortcut ini mulai dari sekarang!
|
||||||
|
|
||||||
|
## Kesalahan 502
|
||||||
|
|
||||||
|
1. Jika kamu menjalankan ini di server lokal, pastikan server lokal tersebut berjalan dengan baik. Sebaliknya, pastikan server yang kamu hubungkan juga berjalan dengan baik.
|
||||||
|
|
||||||
|
2. Kalau bisa, [gunakan versi pengembangan Grasscutter](https://github.com/Grasscutters/Grasscutter/tree/development). Biasanya versi ini bekerja dengan baik di GrassClipper.
|
||||||
|
|
||||||
|
Jika kamu masih mendapatkan kesalahan 502 ketika mencoba masuk ke servermu sendiri, buka file konfigurasi Grasscutter dan tambahkan pada bagian `DispatchServer`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"PublicPort": PORT_MU
|
||||||
|
```
|
||||||
|
dimana `PORT_MU` itu sama dengan port yang kamu gunakan sebagai nilai `Port`. Biasanya diisi dengan nilai 443.
|
||||||
|
|
||||||
|
## Kesalahan 4206
|
||||||
|
|
||||||
|
Pastikan kamu punya file `keystore.p12` dari versi yang kamu pilih (`stabil` atau `pengembangan`). Dan juga pastikan kata sandinya diatur dengan benar di file `config.json` pada Grasscutters (kosong untuk `stabil`, "123456" untuk `pengembangan`).
|
||||||
|
|
||||||
|
## Jendela CMD Terbuka Terus-menerus
|
||||||
|
|
||||||
|
Jika kamu mendapatkan jendela CMD yang terbuka secara terus-menerus dari beberapa skrip (seperti pemasangan proxy atau saat menjalankan server pribadi), pastikan kamu punya UAC (User Access Control) yang diatur pada opsi yang memunculkan dialog permintaan izin menjalankan. Pastikan juga akun penggunamu (user account) bisa dibuka dengan perizinan Admin.
|
||||||
|
|
||||||
|
## Discord Tidak Bisa Mengirim Pesan atau Memuat Gambar atau Youtube Tidak Tampil dengan Baik
|
||||||
|
|
||||||
|
Discord/YouTube (dan beberapa aplikasi lainnya) sepertinya tidak menyukai server proxy mu. Kamu mungkin perlu menonaktifkannya dengan menutup mitmdump atau dengan menonaktifkan proxy mu di pengaturan Windows proxy.
|
||||||
|
|
||||||
|
## Komputerku Tidak Ada Akses Internet Setelah Menutup Peluncur atau Restart!
|
||||||
|
|
||||||
|
Sepertinya peluncur tidak menutup dengan benar dan tidak bisa membersihkan pengaturan proxy seperti semula. Nonaktifkan proxy mu di pengaturan Windows proxy.
|
||||||
|
|
||||||
|
# Bahasa yang Tersedia dan Kredit Penerjemah
|
||||||
|
|
||||||
|
Terima kasih kepada semua orang yang telah menyediakan terjemahan! <3
|
||||||
|
|
||||||
|
* ZH - nuoxianCN, Scirese & MrAru
|
||||||
|
* ZH-TW - Kimi & KormiMeiko
|
||||||
|
* PT-BR - na.na
|
||||||
|
* VIE - labalityowo & lunaticwhat
|
||||||
|
* ID - Iqrar99 & nautilust
|
||||||
|
* FR - linsorak & memetrollsXD
|
||||||
|
* ES - memetrollsXD
|
||||||
|
* ND - memetrollsXD
|
||||||
|
* RU - fitiskin
|
||||||
|
* TR - lilmayofuksu
|
||||||
|
* JP - conochy
|
||||||
|
* HD - Arikatsu
|
||||||
|
* PL - zakhil-dev
|
||||||
|
|
||||||
|
# Tangkapan Layar
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
"grasscutterFileSet": "Set \"Grasscutter\" .jar file",
|
"grasscutterFileSet": "Set \"Grasscutter\" .jar file",
|
||||||
"folderNotSet": "Not set",
|
"folderNotSet": "Not set",
|
||||||
|
|
||||||
"ipPlaceholder": "IP Address",
|
"ipPlaceholder": "Server Address...",
|
||||||
"portPlaceholder": "Port",
|
"portPlaceholder": "Port",
|
||||||
"noFavorites": "No favorites set",
|
"noFavorites": "No favorites set",
|
||||||
|
|
||||||
@ -28,6 +28,7 @@
|
|||||||
"enableServerLauncherSubtitle": "Enable to server launcher tile for launching a local Grasscutter instance.",
|
"enableServerLauncherSubtitle": "Enable to server launcher tile for launching a local Grasscutter instance.",
|
||||||
"httpsOption": "Use HTTPS",
|
"httpsOption": "Use HTTPS",
|
||||||
"httpsSubtitle": "Choose between using HTTPS or HTTP.",
|
"httpsSubtitle": "Choose between using HTTPS or HTTP.",
|
||||||
|
"debugOption": "Debugging",
|
||||||
|
|
||||||
"introSen1": "Looks like this is your first time opening GrassClipper!",
|
"introSen1": "Looks like this is your first time opening GrassClipper!",
|
||||||
"introSen2": "First of all, welcome, happy to see you here! :)",
|
"introSen2": "First of all, welcome, happy to see you here! :)",
|
||||||
@ -38,7 +39,7 @@
|
|||||||
"proxyInstallBtn": "Install",
|
"proxyInstallBtn": "Install",
|
||||||
"proxyInstallDeny": "No thanks",
|
"proxyInstallDeny": "No thanks",
|
||||||
|
|
||||||
"gameFolderDialog": "Select game folder",
|
"gameFolderDialog": "Select game exe",
|
||||||
"grasscutterFileDialog": "Select Grasscutter server jar file",
|
"grasscutterFileDialog": "Select Grasscutter server jar file",
|
||||||
|
|
||||||
"loggingInTo": "Logging in to: ",
|
"loggingInTo": "Logging in to: ",
|
||||||
@ -74,10 +75,20 @@
|
|||||||
"devSubtitle": "Install Grasscutter development branch. This build sometimes has bugs, and is frequently updated. Use at your own risk.",
|
"devSubtitle": "Install Grasscutter development branch. This build sometimes has bugs, and is frequently updated. Use at your own risk.",
|
||||||
"downloadResources": "Download Grasscutter Resources",
|
"downloadResources": "Download Grasscutter Resources",
|
||||||
"resourceSubtitle": "Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally.",
|
"resourceSubtitle": "Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally.",
|
||||||
|
"downloadData": "Download Grasscutter Data",
|
||||||
|
"dataSubtitle": "Downloads Grasscutter data files, such as keys, spawns, and other vital files.",
|
||||||
|
|
||||||
"gcScriptRunning": "Running...",
|
"gcScriptRunning": "Running...",
|
||||||
"stableInstall": "Download",
|
"stableInstall": "Download",
|
||||||
"devInstall": "Download",
|
"devInstall": "Download",
|
||||||
|
|
||||||
"updateNotifText": "A new update is available! Newest version: "
|
"updateNotifText": "A new update is available! Newest version: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "The file path set contains foreign characters, this may cause problems!",
|
||||||
|
|
||||||
|
"dialogOk": "OK",
|
||||||
|
"dialogNo": "NO",
|
||||||
|
"serverEnableDialogTitle": "You found the Grasscutter server launcher!",
|
||||||
|
"serverEnableDialogText": "If you do not have an existing Grasscutter installation to set, would you like to download a build?"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
85
languages/hd.json
Normal file
85
languages/hd.json
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"fullLangName": "Hindi",
|
||||||
|
"appName": "ग्रासक्लिपर",
|
||||||
|
|
||||||
|
"playOfficial": "खेलो असली गेम",
|
||||||
|
"playPrivate": "खेलो ग्रासकटर पर",
|
||||||
|
"launchLocalServer": "शुरू करे लोकल सर्वर",
|
||||||
|
|
||||||
|
"gameExeSet": "गेम का निष्पादन करे",
|
||||||
|
"grasscutterFileSet": "लगाए \"ग्रासकटर \" .jar फ़ाइल",
|
||||||
|
"folderNotSet": "नहीं लगा है",
|
||||||
|
|
||||||
|
"ipPlaceholder": "आय पी एड्रेस",
|
||||||
|
"portPlaceholder": "पोर्ट",
|
||||||
|
"noFavorites": "कोई पसन्दीदार नहीं लगे",
|
||||||
|
|
||||||
|
"settingsTitle": "सेटिंग्स",
|
||||||
|
"scriptsSectionTitle": "स्क्रिप्ट्स",
|
||||||
|
"killswitchOption": "किल स्विच",
|
||||||
|
"killswitchSubtitle": "सिर्फ उनके लिए जो सोचते हैं की यह सब असली अकाउंट को बन कर देग। यह गेम और *इंटरनेट कनेक्शन* मर देता है अगर कुछ प्रॉक्सी को होता है। ",
|
||||||
|
"proxyOption": "प्रॉक्सी",
|
||||||
|
"proxySubtitle": "प्रॉक्सी सर्वर इनस्टॉल करे प्रॉक्सी स्क्रिप्ट्स से",
|
||||||
|
"updateOption": "अपडेट ",
|
||||||
|
"updateSubtitle": "अपने आप अपडेट होने का फीचर अभी बंद है। GitHub देखे नए रिलीज़ के लिए। ",
|
||||||
|
"languageOption": "भाषा ",
|
||||||
|
"languageSubtitle": "अपनी भाषा चुने!",
|
||||||
|
"enableServerLauncherOption": "सर्वर लांचर शुरू करे",
|
||||||
|
"enableServerLauncherSubtitle": "सक्षम करे सर्वर लांचर टाइल ताकि ये एक लोकल ग्रासकटर इंस्टैंस को शुरू कर सके। ",
|
||||||
|
"httpsOption": "HTTPS का उपयोग करे",
|
||||||
|
"httpsSubtitle": "चयन करे HTTPS या HTTP",
|
||||||
|
|
||||||
|
"introSen1": "लग रहा है यह तुम्हारा पहली बार खोलना हुआ है ग्रास्सक्लीप्पेर!",
|
||||||
|
"introSen2": "पहली बात, स्वागत है, अच्छा लगा आपको देख के यहाँ! :)",
|
||||||
|
"introSen3": "प्रॉक्सी इंस्टालर शुरू करे?",
|
||||||
|
"introSen4": "(ज़रुरत है इसकी सर्वर से कनेक्ट करने के लिए)",
|
||||||
|
|
||||||
|
"updateBtn": "अपडेट ",
|
||||||
|
"proxyInstallBtn": "इनस्टॉल ",
|
||||||
|
"proxyInstallDeny": "कोई ज़रुरत नहीं",
|
||||||
|
|
||||||
|
"gameFolderDialog": "गेम फोल्डर सेट करे",
|
||||||
|
"grasscutterFileDialog": "ग्रासकटर jar फाइल सेलेक्ट करे",
|
||||||
|
|
||||||
|
"loggingInTo": "लोग हो रहे हैं इसमें: ",
|
||||||
|
"registeringFor": "रजिस्टर करे इसके लिए: ",
|
||||||
|
"authUsername": "यूजरनाम: ",
|
||||||
|
"authPassword": "पासवर्ड: ",
|
||||||
|
"authConfirmPassword": "पासवर्ड पक्का करे: ",
|
||||||
|
"authLoginBtn": "लॉगिन",
|
||||||
|
"authRegisterBtn": "रजिस्टर",
|
||||||
|
"authLoginTitle": "लॉगिन",
|
||||||
|
"authRegisterTitle": "रजिस्टर",
|
||||||
|
"launchWithoutAuth": "शुरू करे बिना ऑथेंटिकेशन के",
|
||||||
|
|
||||||
|
"alertInvalid": "गलत यूजरनाम या पासवर्ड",
|
||||||
|
"alertNoPass": "कोई पासवर्ड नहीं लगा, कृपया पासवर्ड चेंज करे",
|
||||||
|
"alertUnknown": "अनजान एरर। सर्वर के मालिक से बात करे",
|
||||||
|
"alertAuthNoLogin": "ऑथेंटिकेशन बंद है, लॉगिन की कोई ज़रुरत नहीं!",
|
||||||
|
"alertLoginSuccess": "लॉगिन पूरा हुआ! टोकन क्लिपबोर्ड पर कॉपी हो गया है। यह टोकन पेस्ट करे यूजरनाम की जगह पर गेम के अंदर ताकि लॉगिन हो सके। ",
|
||||||
|
|
||||||
|
"alertUserTaken": "यूजरनाम ले लिया गया है",
|
||||||
|
"alertPassMismatch": "पासवर्ड और पासवर्ड कन्फर्मेशन मैच नहीं कर रहे",
|
||||||
|
"alertAuthNoRegister": "ऑथेंटिकेशन बंद है, रजिस्ट्रेशन की कोई ज़रुरत नहीं!",
|
||||||
|
"alertRegisterSuccess": "रजिस्ट्रेशन समाप्त हुआ!",
|
||||||
|
|
||||||
|
"downloadTitle": "डौन्लोडस",
|
||||||
|
"grassclipperTitle": "ग्रासक्लिपर",
|
||||||
|
"grasscutterTitle": "ग्रासकटर",
|
||||||
|
"installerTitle": "इंस्टालर",
|
||||||
|
"installerSubtitle": "ये प्रॉक्सी और कुछ और टूल्स इनस्टॉल करता है। ज़रुरत है इसकी ग्रासकटर सर्वर्स के लिए",
|
||||||
|
"downloadStable": "डाउनलोड ग्रासकटर स्टेबल बिल्ड",
|
||||||
|
"stableSubtitle": "इनस्टॉल ग्रासकटर स्टेबल ब्रांच। यह बिल्ड में काम फीचर्स है पर काम बग्स भी है।",
|
||||||
|
"downloadDev": "डाउनलोड ग्रासकटर डेवलपमेंट बिल्ड",
|
||||||
|
"devSubtitle": "इनस्टॉल ग्रासकटर डेवलपमेंट ब्रांच। इस बिल्ड में काफी बार बग्स होते हैं पर जल्दी जल्दी अपडेट होता है। अपने बूते पे इस्तेमाल करे।",
|
||||||
|
"downloadResources": "डाउनलोड ग्रसससटर रिसोर्सेज",
|
||||||
|
"resourceSubtitle": "आपभी सेट हुए ग्रासकटर फोल्डर में ग्रासकटर के रिसोर्सेज डाउनलोड करता है। यह हो जाना चाहिए अगर आपने कही और से रिसोर्सेज नहीं लिये।",
|
||||||
|
|
||||||
|
"gcScriptRunning": "चल रहा है...",
|
||||||
|
"stableInstall": "डाउनलोड",
|
||||||
|
"devInstall": "डाउनलोड",
|
||||||
|
|
||||||
|
"updateNotifText": "नया अपडेट आया है! नया वर्शन: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "इस फाइल पथ में चीनी चरक्टेर्स हैं, यह समस्या दे सकता है!"
|
||||||
|
}
|
@ -71,13 +71,20 @@
|
|||||||
"downloadStable": "Unduh Versi Stabil Grasscutter",
|
"downloadStable": "Unduh Versi Stabil Grasscutter",
|
||||||
"stableSubtitle": "Pasang versi stabil Grasscutter. Versi ini biasanya tidak punya banyak bug, tetapi juga fiturnya lebih sedikit.",
|
"stableSubtitle": "Pasang versi stabil Grasscutter. Versi ini biasanya tidak punya banyak bug, tetapi juga fiturnya lebih sedikit.",
|
||||||
"downloadDev": "Unduh Versi Pengembangan Grasscutter",
|
"downloadDev": "Unduh Versi Pengembangan Grasscutter",
|
||||||
"downloadSubtitle": "Pasang versi pengembangan Grasscutter. Versi ini biasanya mempunyai banyak bug dan sering diperbarui. Gunakan dengan resikomu sendiri.",
|
"devSubtitle": "Pasang versi pengembangan Grasscutter. Versi ini biasanya mempunyai banyak bug dan sering diperbarui. Gunakan dengan resikomu sendiri.",
|
||||||
"downloadResources": "Unduh Sumber Daya Grasscutter",
|
"downloadResources": "Unduh Sumber Daya Grasscutter",
|
||||||
"devSubtitle": "Unduh sumber daya Grasscutter ke dalam folder Grasscutter yang sudah diatur. Ini harus dilakukan kecuali kamu berencana untuk mendapatkan sumber daya secara eksternal.",
|
"resourceSubtitle": "Unduh sumber daya Grasscutter ke dalam folder Grasscutter yang sudah diatur. Ini harus dilakukan kecuali kamu berencana untuk mendapatkan sumber daya secara eksternal.",
|
||||||
|
|
||||||
"gcScriptRunning": "Menjalankan...",
|
"gcScriptRunning": "Menjalankan...",
|
||||||
"stableInstall": "Unduh",
|
"stableInstall": "Unduh",
|
||||||
"devInstall": "Unduh",
|
"devInstall": "Unduh",
|
||||||
|
|
||||||
"updateNotifText": "Pembaruan baru tersedia! Versi terbaru: "
|
"updateNotifText": "Pembaruan baru tersedia! Versi terbaru: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "Jalur file yang diatur berisi karakter Cina, ini dapat menyebabkan masalah!",
|
||||||
|
|
||||||
|
"dialogOk": "OK",
|
||||||
|
"dialogNo": "TIDAK",
|
||||||
|
"serverEnableDialogTitle": "Kamu menemukan peluncur server Grasscutter!",
|
||||||
|
"serverEnableDialogText": "Jika kamu tidak memiliki pemasangan Grasscutter untuk diatur, apakah kamu mau mengunduh build nya?"
|
||||||
}
|
}
|
||||||
|
85
languages/jp.json
Normal file
85
languages/jp.json
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"fullLangName": "日本語",
|
||||||
|
"appName": "GrassClipper",
|
||||||
|
|
||||||
|
"playOfficial": "起動 (Official)",
|
||||||
|
"playPrivate": "起動 (Grasscutter)",
|
||||||
|
"launchLocalServer": "ローカルサーバーを起動",
|
||||||
|
|
||||||
|
"gameExeSet": "GenshinImpact.exe の場所を指定",
|
||||||
|
"grasscutterFileSet": "grasscutter.jar の場所を指定",
|
||||||
|
"folderNotSet": "原神のフォルダーが指定されていません。",
|
||||||
|
|
||||||
|
"ipPlaceholder": "IP アドレス",
|
||||||
|
"portPlaceholder": "ポート",
|
||||||
|
"noFavorites": "お気に入りはまだ登録されていません",
|
||||||
|
|
||||||
|
"settingsTitle": "設定",
|
||||||
|
"scriptsSectionTitle": "スクリプト",
|
||||||
|
"killswitchOption": "強制終了",
|
||||||
|
"killswitchSubtitle": "緊急時のみ。プロキシにエラーが発生した場合に、ゲームを終了し、インターネットを遮断します。",
|
||||||
|
"proxyOption": "プロキシ",
|
||||||
|
"proxySubtitle": "プロキシサーバーをインストールします。",
|
||||||
|
"updateOption": "更新",
|
||||||
|
"updateSubtitle": "自動更新は現在無効化されています。GitHub で最新バージョンを確認してください。",
|
||||||
|
"languageOption": "言語",
|
||||||
|
"languageSubtitle": "言語を選択してください。",
|
||||||
|
"enableServerLauncherOption": "サーバーランチャーを有効化します",
|
||||||
|
"enableServerLauncherSubtitle": "Grasscutter を起動するための、ランチャータイルを有効化します。",
|
||||||
|
"httpsOption": "HTTPS を使用",
|
||||||
|
"httpsSubtitle": "HTTP と HTTPS のどちらを使用するか選択します。このオプションは、プライベートサーバーでプレイするときにのみ適用されます。",
|
||||||
|
|
||||||
|
"introSen1": "GrassClipper へようこそ!",
|
||||||
|
"introSen2": "GrassClipper をご利用いただきありがとうございます。",
|
||||||
|
"introSen3": "プロキシサーバーをインストールしますか?",
|
||||||
|
"introSen4": "(インターネットへの接続が必要)",
|
||||||
|
|
||||||
|
"updateBtn": "更新",
|
||||||
|
"proxyInstallBtn": "インストールする",
|
||||||
|
"proxyInstallDeny": "インストールしない",
|
||||||
|
|
||||||
|
"gameFolderDialog": "原神のゲームフォルダーを指定",
|
||||||
|
"grasscutterFileDialog": "grasscutter.jar の場所を指定",
|
||||||
|
|
||||||
|
"loggingInTo": "ログイン先: ",
|
||||||
|
"registeringFor": "登録先: ",
|
||||||
|
"authUsername": "ユーザー名: ",
|
||||||
|
"authPassword": "パスワード: ",
|
||||||
|
"authConfirmPassword": "パスワード(確認): ",
|
||||||
|
"authLoginBtn": "ログイン",
|
||||||
|
"authRegisterBtn": "登録",
|
||||||
|
"authLoginTitle": "ログイン",
|
||||||
|
"authRegisterTitle": "登録",
|
||||||
|
"launchWithoutAuth": "認証せず起動",
|
||||||
|
|
||||||
|
"alertInvalid": "ユーザー名またはパスワードが誤っています。",
|
||||||
|
"alertNoPass": "パスワードが設定されていません。パスワードを設定してください。",
|
||||||
|
"alertUnknown": "不明なエラーが発生しました。サーバーの管理者に連絡してください。",
|
||||||
|
"alertAuthNoLogin": "認証が無効になっています。ログインする必要はありません。",
|
||||||
|
"alertLoginSuccess": "ログインに成功しました。トークンをクリップボードにコピーしたので、ゲームのユーザー名欄に貼り付けてログインしてください。",
|
||||||
|
|
||||||
|
"alertUserTaken": "そのユーザー名はすでに使用されています。",
|
||||||
|
"alertPassMismatch": "パスワードが一致していません。",
|
||||||
|
"alertAuthNoRegister": "認証が無効になっています。ログインする必要はありません。",
|
||||||
|
"alertRegisterSuccess": "登録成功",
|
||||||
|
|
||||||
|
"downloadTitle": "ダウンロード",
|
||||||
|
"grassclipperTitle": "GrassClipper",
|
||||||
|
"grasscutterTitle": "Grasscutter",
|
||||||
|
"installerTitle": "インストーラー",
|
||||||
|
"installerSubtitle": "Grasscutter に必要な、プロキシなどのツールをインストールします。",
|
||||||
|
"downloadStable": "Grasscutter の安定版をインストール",
|
||||||
|
"stableSubtitle": "Grasscutter の安定版をインストールします。バグは少ないですが、新機能も少ないです。",
|
||||||
|
"downloadDev": "Grasscutter の開発版をインストール",
|
||||||
|
"devSubtitle": "Grasscutter の開発版をインストールします。バグが多い恐れがあります。また、頻繁に更新されます。",
|
||||||
|
"downloadResources": "Grasscutter のリソースをダウンロード",
|
||||||
|
"resourceSubtitle": "Grasscutter のリソースをダウンロードします。ほかのところから入手しない場合は、これをダウンロードする必要があります。",
|
||||||
|
|
||||||
|
"gcScriptRunning": "実行中...",
|
||||||
|
"stableInstall": "ダウンロード",
|
||||||
|
"devInstall": "ダウンロード",
|
||||||
|
|
||||||
|
"updateNotifText": "新しいバージョンが利用できます。Version: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "ファイルパスに漢字やひらがななどの全角文字が含まれているため、正常に動作しない場合があります。"
|
||||||
|
}
|
93
languages/ko.json
Normal file
93
languages/ko.json
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
{
|
||||||
|
"fullLangName": "한국어",
|
||||||
|
"appName": "GrassClipper",
|
||||||
|
|
||||||
|
"playOfficial": "플레이 (공식)",
|
||||||
|
"playPrivate": "플레이 (Grasscutter)",
|
||||||
|
"launchLocalServer": "로컬에서 실행",
|
||||||
|
|
||||||
|
"gameExeSet": "게임 실행파일 설정",
|
||||||
|
"grasscutterFileSet": "\"Grasscutter\" .jar 파일 설정",
|
||||||
|
"folderNotSet": "폴더가 지정되지 않았습니다.",
|
||||||
|
|
||||||
|
"ipPlaceholder": "서버 주소",
|
||||||
|
"portPlaceholder": "포트",
|
||||||
|
"noFavorites": "즐겨찾기를 설정하지 않았습니다.",
|
||||||
|
|
||||||
|
"settingsTitle": "설정",
|
||||||
|
"scriptsSectionTitle": "스크립트",
|
||||||
|
"killswitchOption": "프로세스 중지",
|
||||||
|
"killswitchSubtitle": "프록시에 문제가 발생할 경우, 게임과 인터넷을 중지합니다.",
|
||||||
|
"proxyOption": "프록시",
|
||||||
|
"proxySubtitle": "스크립트를 통해 프록시 서버 설치",
|
||||||
|
"updateOption": "업데이트",
|
||||||
|
"updateSubtitle": "자동 업데이트가 일시적으로 비활성화되어 있습니다. Github에서 최신 버전을 확인하세요.",
|
||||||
|
"languageOption": "언어",
|
||||||
|
"languageSubtitle": "언어를 선택해주세요.",
|
||||||
|
"enableServerLauncherOption": "서버 실행 버튼 활성화",
|
||||||
|
"enableServerLauncherSubtitle": "로컬 Grasscutter 인스턴스를 실행하기 위해, 서버 실행기 타일을 활성화합니다.",
|
||||||
|
"httpsOption": "HTTPS 사용",
|
||||||
|
"httpsSubtitle": "HTTPS 또는 HTTP 중 하나를 선택하세요.",
|
||||||
|
"debugOption": "디버깅",
|
||||||
|
|
||||||
|
"introSen1": "GrassClipper에 오신 것을 환영합니다!",
|
||||||
|
"introSen2": "GrassClipper를 사용해주셔서 감사드립니다.",
|
||||||
|
"introSen3": "프록시 설치 관리자를 실행하시겠습니까?",
|
||||||
|
"introSen4": "(서버에 연결하는 데 필요)",
|
||||||
|
|
||||||
|
"updateBtn": "업데이트",
|
||||||
|
"proxyInstallBtn": "설치",
|
||||||
|
"proxyInstallDeny": "사양하겠습니다.",
|
||||||
|
|
||||||
|
"gameFolderDialog": "게임 실행 파일을 설정하세요.",
|
||||||
|
"grasscutterFileDialog": "Grasscutter jar을 설정하세요.",
|
||||||
|
|
||||||
|
"loggingInTo": "로그인: ",
|
||||||
|
"registeringFor": "등록: ",
|
||||||
|
"authUsername": "이름: ",
|
||||||
|
"authPassword": "비밀번호: ",
|
||||||
|
"authConfirmPassword": "비밀번호 확인: ",
|
||||||
|
"authLoginBtn": "로그인",
|
||||||
|
"authRegisterBtn": "가입",
|
||||||
|
"authLoginTitle": "로그인",
|
||||||
|
"authRegisterTitle": "가입",
|
||||||
|
"launchWithoutAuth": "인증 없이 실행",
|
||||||
|
|
||||||
|
"alertInvalid": "잘못된 사용자 이름 또는 비밀번호입니다.",
|
||||||
|
"alertNoPass": "비밀번호를 설정하지 않았습니다. 비밀번호를 설정하세요.",
|
||||||
|
"alertUnknown": "알 수 없는 오류, 서버 소유자에게 문의하세요.",
|
||||||
|
"alertAuthNoLogin": "인증이 비활성화되어있으므로, 로그인이 필요하지 않습니다!",
|
||||||
|
"alertLoginSuccess": "로그인 성공! 토큰이 클립보드에 복사되었습니다. 토큰을 게임의 사용자 이름 필드에 붙여 로그인합니다.",
|
||||||
|
|
||||||
|
"alertUserTaken": "해당 사용자 이름은 이미 사용 중입니다.",
|
||||||
|
"alertPassMismatch": "암호 확인이 일치하지 않습니다.",
|
||||||
|
"alertAuthNoRegister": "인증이 비활성화되어있으므로, 가입이 필요하지 않습니다!",
|
||||||
|
"alertRegisterSuccess": "가입 성공!",
|
||||||
|
|
||||||
|
"downloadTitle": "다운로드",
|
||||||
|
"grassclipperTitle": "GrassClipper",
|
||||||
|
"grasscutterTitle": "Grasscutter",
|
||||||
|
"installerTitle": "설치 관리자",
|
||||||
|
"installerSubtitle": "프록시 및 기타 도구를 설치합니다. (Grasscutter 서버에 필요)",
|
||||||
|
"downloadStable": "안정적인 Grasscutter 빌드 다운로드",
|
||||||
|
"stableSubtitle": "안정적인 Grasscutter를 설치합니다. (버그는 거의 없지만, 새로운 기능 또한 적습니다.)",
|
||||||
|
"downloadDev": "개발 버전 Grasscutter 다운로드",
|
||||||
|
"devSubtitle": "개발 버전의 Grasscutter를 설치합니다. (버그가 있을 수 있으며, 자주 업데이트됩니다. 버그로 인한 피해는 책임지지 않습니다.)",
|
||||||
|
"downloadResources": "Grasscutter 리소스 다운로드",
|
||||||
|
"resourceSubtitle": "Grasscutter 리소스를 현재 설정된 Grasscutter 폴더에 다운로드합니다. 외부에서 리소스를 가져올 예정이 아니라면, 이 작업을 수행해야 합니다.",
|
||||||
|
"downloadData": "Grasscutter 데이터 다운로드",
|
||||||
|
"dataSubtitle": "중요한 Grasscutter 데이터 파일을 다운로드합니다.",
|
||||||
|
|
||||||
|
"gcScriptRunning": "실행중...",
|
||||||
|
"stableInstall": "다운로드 (stable)",
|
||||||
|
"devInstall": "다운로드 (dev)",
|
||||||
|
|
||||||
|
"updateNotifText": "새 업데이트를 사용할 수 있습니다: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "파일 경로에 유효하지 않은 문자가 포함되어 있으므로, 문제가 발생할 수 있습니다!",
|
||||||
|
|
||||||
|
"dialogOk": "예",
|
||||||
|
"dialogNo": "아니오",
|
||||||
|
"serverEnableDialogTitle": "Grasscutter 서버 실행기를 찾았습니다!",
|
||||||
|
"serverEnableDialogText": "설정할 기존의 Grasscutter가 없는 경우, 빌드를 다운로드하시겠습니까?"
|
||||||
|
}
|
91
languages/pl.json
Normal file
91
languages/pl.json
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"fullLangName": "Polski",
|
||||||
|
"appName": "GrassClipper",
|
||||||
|
|
||||||
|
"playOfficial": "Serwer oficjalny",
|
||||||
|
"playPrivate": "Serwer prywatny",
|
||||||
|
"launchLocalServer": "Uruchom serwer prywatny",
|
||||||
|
|
||||||
|
"gameExeSet": "Ustaw plik gry",
|
||||||
|
"grasscutterFileSet": "Ustaw plik \"Grasscutter\" .jar ",
|
||||||
|
"folderNotSet": "Nie ustawiono",
|
||||||
|
|
||||||
|
"ipPlaceholder": "Adres serwera",
|
||||||
|
"portPlaceholder": "Port",
|
||||||
|
"noFavorites": "Nie dodano żadnych ulubionych",
|
||||||
|
|
||||||
|
"settingsTitle": "Ustawienia",
|
||||||
|
"scriptsSectionTitle": "Skrypty",
|
||||||
|
"killswitchOption": "Kill Switch",
|
||||||
|
"killswitchSubtitle": "Tylko dla tych, którzy boją się o dostanie bana. Wyłącza gre *oraz twój internet* jeżeli coś stanie się z proxy.",
|
||||||
|
"proxyOption": "Proxy",
|
||||||
|
"proxySubtitle": "Zainstaluj serwer proxy poprzez skrypt instalacyjny",
|
||||||
|
"updateOption": "Aktualizacja",
|
||||||
|
"updateSubtitle": "Auto-aktualizacje są niedostępne. Sprawdź GitHub'a projektu po nowe wersje.",
|
||||||
|
"languageOption": "Język",
|
||||||
|
"languageSubtitle": "Wybierz swój język!",
|
||||||
|
"enableServerLauncherOption": "Włącz Launcher Serwera",
|
||||||
|
"enableServerLauncherSubtitle": "Enable to server launcher tile for launching a local Grasscutter instance.",
|
||||||
|
"httpsOption": "Używaj HTTPS",
|
||||||
|
"httpsSubtitle": "Wybierz pomiędzy używaniem HTTPS, a HTTP.",
|
||||||
|
|
||||||
|
"introSen1": "Wygląda na to, że po raz pierwszy uruchomiłeś GrassClipper'a!",
|
||||||
|
"introSen2": "Po pierwsze, miło Cię tu widzieć! :)",
|
||||||
|
"introSen3": "Czy chcesz uruchomić instalator proxy?",
|
||||||
|
"introSen4": "(proxy wymagane jest do łączenia się z serwerem prywatnym)",
|
||||||
|
|
||||||
|
"updateBtn": "Aktualizuj",
|
||||||
|
"proxyInstallBtn": "Instaluj",
|
||||||
|
"proxyInstallDeny": "Nie, dziękuję",
|
||||||
|
|
||||||
|
"gameFolderDialog": "Ustaw folder gry",
|
||||||
|
"grasscutterFileDialog": "Wybierz plik serwera Grasscutter",
|
||||||
|
|
||||||
|
"loggingInTo": "Logowanie do: ",
|
||||||
|
"registeringFor": "Rejestracja do: ",
|
||||||
|
"authUsername": "Nazwa użytkownika: ",
|
||||||
|
"authPassword": "Hasło: ",
|
||||||
|
"authConfirmPassword": "Potwierdź hasło: ",
|
||||||
|
"authLoginBtn": "Zaloguj",
|
||||||
|
"authRegisterBtn": "Zarejestruj",
|
||||||
|
"authLoginTitle": "Logowanie",
|
||||||
|
"authRegisterTitle": "Rejestracja",
|
||||||
|
"launchWithoutAuth": "Uruchom bez autentykacji",
|
||||||
|
|
||||||
|
"alertInvalid": "Błędna nazwa użytkownika lub hasło",
|
||||||
|
"alertNoPass": "Nie ustawiono hasła, proszę ustawić hasło",
|
||||||
|
"alertUnknown": "Nieznany błąd, skontaktuj się z właścicielem serwera",
|
||||||
|
"alertAuthNoLogin": "Autentykacja jest wyłączona, nie ma potrzeby logowania się!",
|
||||||
|
"alertLoginSuccess": "Pomyślnie zalogowano! Twój Token został skopiowany do schowka. Wklej go w polu nazwy użytkownika w grze aby się zalogować.",
|
||||||
|
|
||||||
|
"alertUserTaken": "Ta nazwa jest już zajęta",
|
||||||
|
"alertPassMismatch": "Hasła nie zgadzają się",
|
||||||
|
"alertAuthNoRegister": "Autentykacja jest wyłączona, nie ma potrzeby rejestrowania się!",
|
||||||
|
"alertRegisterSuccess": "Pomyślnie zarejestrowano!",
|
||||||
|
|
||||||
|
"downloadTitle": "Pobieranie",
|
||||||
|
"grassclipperTitle": "GrassClipper",
|
||||||
|
"grasscutterTitle": "Grasscutter",
|
||||||
|
"installerTitle": "Instalator",
|
||||||
|
"installerSubtitle": "Instaluje proxy oraz inne niezbędne narzędzia do grania na serwerach Grasscutter'a.",
|
||||||
|
"downloadStable": "Pobierz stabilną wersję Grasscutter'a",
|
||||||
|
"stableSubtitle": "Zainstaluj stabilną wersję Grasscutter'a. Ma ona mało błędów, ale też mniej funkcji.",
|
||||||
|
"downloadDev": "Pobierz wersję developerską Grasscutter'a",
|
||||||
|
"devSubtitle": "Zainstaluj wersję developerską Grasscutter'a. Może posiadać sporo błędów, ma najnowsze funkcje, używaj na własne ryzyko.",
|
||||||
|
"downloadResources": "Pobierz Zasoby Grasscutter'a",
|
||||||
|
"resourceSubtitle": "Pobiera zasoby Grasscuterra do aktualnie wybranego folderu. Nie powinno się tego uruchamiać gdy zasoby chcesz pobierać z zewnątrz.",
|
||||||
|
|
||||||
|
"gcScriptRunning": "Pracuje...",
|
||||||
|
"stableInstall": "Pobierz wersje stabilną",
|
||||||
|
"devInstall": "Pobierz wersje deweloperską",
|
||||||
|
|
||||||
|
"updateNotifText": "Nowa wersja jest dostępna! Najnowsza wersja: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "Ścieżka pliku zawierająca chińskie symbole może powodować błędy.",
|
||||||
|
|
||||||
|
"dialogOk": "Tak",
|
||||||
|
"dialogNo": "Nie",
|
||||||
|
"serverEnableDialogTitle": "Znalazłeś Launcher Serwera",
|
||||||
|
"serverEnableDialogText": "Jeżeli nie posiadasz instalacji Grasscutter'a, możesz ją teraz pobrać. Uruchomić pobieranie?"
|
||||||
|
|
||||||
|
}
|
@ -35,5 +35,53 @@
|
|||||||
"proxyInstallDeny": "Não obrigado",
|
"proxyInstallDeny": "Não obrigado",
|
||||||
|
|
||||||
"gameFolderDialog": "Selecione a game pasta",
|
"gameFolderDialog": "Selecione a game pasta",
|
||||||
"grasscutterFileDialog": "Selecione o arquivo jar do Grasscutter"
|
"grasscutterFileDialog": "Selecione o arquivo jar do Grasscutter",
|
||||||
|
|
||||||
|
"loggingInTo": "Logando como: ",
|
||||||
|
"registeringFor": "Registrando como: ",
|
||||||
|
"authUsername": "Usuário: ",
|
||||||
|
"authPassword": "Senha: ",
|
||||||
|
"authConfirmPassword": "Confirme a senha: ",
|
||||||
|
"authLoginBtn": "Login",
|
||||||
|
"authRegisterBtn": "Registrar",
|
||||||
|
"authLoginTitle": "Login",
|
||||||
|
"authRegisterTitle": "Registrar",
|
||||||
|
"launchWithoutAuth": "Iniciar sem autenticação",
|
||||||
|
|
||||||
|
"alertInvalid": "Usuário ou senha invalidos",
|
||||||
|
"alertNoPass": "Nenhuma senha cadastrada, por favor troque a senha",
|
||||||
|
"alertUnknown": "Erro desconhecido, contate o dono do servidor",
|
||||||
|
"alertAuthNoLogin": "Autenticação desabilitada, não ha necessidade de logar!",
|
||||||
|
"alertLoginSuccess": "Sucesso no login! Token copiado. Cole esse token no lugar do usuário no jogo para logar.",
|
||||||
|
|
||||||
|
"alertUserTaken": "Usuário em uso",
|
||||||
|
"alertPassMismatch": "Senha e confirmação não estão iguais",
|
||||||
|
"alertAuthNoRegister": "Autenticação desabilitada, não há necessidade de registrar!",
|
||||||
|
"alertRegisterSuccess": "Registrado com sucesso!",
|
||||||
|
|
||||||
|
"downloadTitle": "Downloads",
|
||||||
|
"grassclipperTitle": "GrassClipper",
|
||||||
|
"grasscutterTitle": "Grasscutter",
|
||||||
|
"installerTitle": "Instalador",
|
||||||
|
"installerSubtitle": "Instala o proxy e outras ferramentas. Necessário para servidores Grasscutter",
|
||||||
|
"downloadStable": "Baixar a build Grasscutter Stable",
|
||||||
|
"stableSubtitle": "Instalar Grasscutter stable. Essa build geralmente tem menos bugs, mas menos recursos",
|
||||||
|
"downloadDev": "Baixar a build Grasscutter Development",
|
||||||
|
"devSubtitle": "Instalar Grasscutter Development. Essa build geralmente tem bugs e é frequentemente atualizada. Use por sua conta e risco.",
|
||||||
|
"downloadResources": "Baixar Grasscutter Resources",
|
||||||
|
"resourceSubtitle": "Baixar Grasscutter Resources na pasta atual setada do Grasscutter. Isso deve ser feito a não ser que você planeje colocar os resources externamente.",
|
||||||
|
|
||||||
|
"gcScriptRunning": "Rodando...",
|
||||||
|
"stableInstall": "Baixar",
|
||||||
|
"devInstall": "Baixar",
|
||||||
|
|
||||||
|
"updateNotifText": "Uma nova atualização esta disponivel! Nova versão: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "O caminho setado contem caracteres chineses, isso pode causar problemas!",
|
||||||
|
|
||||||
|
"dialogOk": "OK",
|
||||||
|
"dialogNo": "Não",
|
||||||
|
"serverEnableDialogTitle": "Você achou o launcher do server do Grasscutter!",
|
||||||
|
"serverEnableDialogText": "Caso você ainda não tenha uma instalação do grasscutter para setar, quer baixar uma build?"
|
||||||
|
|
||||||
}
|
}
|
95
languages/th.json
Normal file
95
languages/th.json
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"fullLangName": "ภาษาไทย",
|
||||||
|
"appName": "GrassClipper",
|
||||||
|
|
||||||
|
"playOfficial": "เริ่มเกม (Official)",
|
||||||
|
"playPrivate": "เริ่มเกม (Grasscutter)",
|
||||||
|
"launchLocalServer": "เริ่ม Local Server",
|
||||||
|
|
||||||
|
"gameExeSet": "เลือกไฟล์เกม",
|
||||||
|
"grasscutterFileSet": "เลือกไฟล์ \"Grasscutter\" .jar ",
|
||||||
|
"folderNotSet": "ยังไม่ได้ตั้ง",
|
||||||
|
|
||||||
|
"ipPlaceholder": "ที่อยู่เซิร์ฟเวอร์...",
|
||||||
|
"portPlaceholder": "พอร์ต",
|
||||||
|
"noFavorites": "ยังไม่ได้ตั้ง",
|
||||||
|
|
||||||
|
"settingsTitle": "การตั้งค่า",
|
||||||
|
"scriptsSectionTitle": "สคริปต์",
|
||||||
|
"killswitchOption": "Kill Switch",
|
||||||
|
"killswitchSubtitle": "เอาไว้สำหรับพวกที่กลัวโดนแบนมากๆ เมื่อพร็อกซี่มีปัญหาจะบังคับปิดเกมและตัดอินเตอร์เน็ตทันที",
|
||||||
|
"proxyOption": "พร็อกซี่",
|
||||||
|
"proxySubtitle": "ติดตั้งพร็อกซี่ด้วยสคริปต์ติดตั้ง",
|
||||||
|
"updateOption": "อัพเดท",
|
||||||
|
"updateSubtitle": "การอัพเดทอัตโนมัติไม่พร้อมใช้งานในขณะนี้ ไปที่ Github สำหรับเวอร์ชั่นใหม่",
|
||||||
|
"languageOption": "ภาษา",
|
||||||
|
"languageSubtitle": "เลือกภาษาของคุณ",
|
||||||
|
"enableServerLauncherOption": "เพิ่มปุ่มเริ่มเซิร์ฟเวอร์",
|
||||||
|
"enableServerLauncherSubtitle": "เพิ่มปุ่มเริ่มเซิร์ฟเวอร์ไปยังหน้าแลนเชอร์ใช้สำหรับเริ่มการทำงานของเซิร์ฟเวอร์ Grasscutter ที่ติดตั้งไว้",
|
||||||
|
"httpsOption": "ใช้ HTTPS",
|
||||||
|
"httpsSubtitle": "เลือกระหว่าง HTTPS กับ HTTP.",
|
||||||
|
"debugOption": "การดีบัก",
|
||||||
|
|
||||||
|
"introSen1": "ดูเหมือนว่านี่เป็นครั้งแรกที่คุณเปิด GrassClipper!",
|
||||||
|
"introSen2": "อย่างแรกเลย ยินดีต้อนรับ เรายินดีที่ได้พบคุณที่นีี่! :)",
|
||||||
|
"introSen3": "คุณต้องการที่จะรันตัวติดตั้งพร็อกซี่หรือไม่ ",
|
||||||
|
"introSen4": "(จำเป็นต้องเชื่อมต่อไปยังเซิร์ฟเวอร์)",
|
||||||
|
|
||||||
|
"updateBtn": "อัพเดท",
|
||||||
|
"proxyInstallBtn": "ติดตั้ง",
|
||||||
|
"proxyInstallDeny": "ไม่ ขอบคุณ",
|
||||||
|
|
||||||
|
"gameFolderDialog": "เลือกไฟล์ .exe เกม",
|
||||||
|
"grasscutterFileDialog": "เลือกไฟล์ .jar Grasscutter ",
|
||||||
|
|
||||||
|
"loggingInTo": "เข้าสู่ระบบไปยัง: ",
|
||||||
|
"registeringFor": "ลงทะเบียนำหรับ: ",
|
||||||
|
"authUsername": "ชื่อผู้ใช้: ",
|
||||||
|
"authPassword": "รหัสผ่าน: ",
|
||||||
|
"authConfirmPassword": "ยืนยันรหัสผ่าน: ",
|
||||||
|
"authLoginBtn": "เข้าสู่ระบบ",
|
||||||
|
"authRegisterBtn": "ลงทะเบียน",
|
||||||
|
"authLoginTitle": "เข้าสู่ระบบ",
|
||||||
|
"authRegisterTitle": "ลงทะเบียน",
|
||||||
|
"launchWithoutAuth": "เริ่มเกมโดยไม่ต้องยืนยันตัวตน",
|
||||||
|
|
||||||
|
"alertInvalid": "ชื่อผู้ใช้หรือรหัสผ่านผิดพลาด",
|
||||||
|
"alertNoPass": "ไม้ได้ตั้งรหัสผ่าน กรุณาตั้ง",
|
||||||
|
"alertUnknown": "เกิดข้อผิดพลาดไม่ทราบสาเหตุ โปรดติดต่อผู้ดูแล",
|
||||||
|
"alertAuthNoLogin": "การยืนยันตัวตนถูกปิดใช้งาน ไม่จำเป็นต้องเข้าสู่ระบบ",
|
||||||
|
"alertLoginSuccess": "เข้าสู่ระบบสำเร็จ โทเคนถูกคัดลอกไปยังคลิปบอร์ด นำโทเคนนี้ไปกรอกใส่ช่องชื่อผู้ใช้เพื่อเข้าสู่ระบบ",
|
||||||
|
|
||||||
|
"alertUserTaken": "ชื่อผู้ใช้นี้ถูกใช้งานแล้ว",
|
||||||
|
"alertPassMismatch": "รหัสผ่านกับยืนยันรหัสผ่านไม่ตรงกัน",
|
||||||
|
"alertAuthNoRegister": "การยืนยันตัวตนถูกปิดใช้งาน ไม่จำเป็นต้องลงทะเบียน",
|
||||||
|
"alertRegisterSuccess": "ลงทะเบียนสำเร็จ!",
|
||||||
|
|
||||||
|
"downloadTitle": "ดาวน์โหลด",
|
||||||
|
"grassclipperTitle": "GrassClipper",
|
||||||
|
"grasscutterTitle": "Grasscutter",
|
||||||
|
"installerTitle": "ตัวติดตั้ง",
|
||||||
|
"installerSubtitle": "ติดตั้งพร็อกซี่และเครื่องมืออื่นๆที่จำเป็นสำหรับเซิร์ฟเวอร์ Grasscutter",
|
||||||
|
"downloadStable": "ดาวน์โหลด Grasscutter รุ่นเสถียร",
|
||||||
|
"stableSubtitle": "ดาวน์โหลด Grasscutter จากแบรนช์เสถียร โดยปกติแล้วรุ่นนี้จะมีบั๊กน้อยกว่าฟีเจอร์ก็น้อยกว่าเช่นกัน",
|
||||||
|
"downloadDev": "ดาวน์โหลด Grasscutter รุ่นนักพัฒนา",
|
||||||
|
"devSubtitle": "ดาวน์โหลด Grasscutter จากแบรนช์นักพัฒนา รุ่นนี้มีการอัพเดทบ่อย บางครั้งอาจมีบั๊ก ใช้เป็นความเสี่ยงของคุณ",
|
||||||
|
"downloadResources": "ดาวน์โหลดไฟล์ทรัพยากร Grasscutter ",
|
||||||
|
"resourceSubtitle": "ดาวน์โหลดไฟล์ทรัพยากรของ Grasscutter ไปยังโฟลเดอร์ของ Grasscutter ที่ตั้งไว้ คุณควรดำเนินการนี้เว้นแต่ว่าตุณวางแผนจะใช้ไฟล์จากภายนอก",
|
||||||
|
"downloadData": "ดาวน์โหลดไฟล์ข้อมูล Grasscutter",
|
||||||
|
"dataSubtitle": "ดาวน์โหลดไฟล์ข้อมูลของ Grasscutter อย่างเช่น keys, spawns หรือไฟล์สำคัญอย่างอื่น",
|
||||||
|
|
||||||
|
"gcScriptRunning": "กำลังรัน...",
|
||||||
|
"stableInstall": "ดาวน์โหลด",
|
||||||
|
"devInstall": "ดาวน์โหลด",
|
||||||
|
|
||||||
|
"updateNotifText": "มีการอัพเดทพร้อมใช้งาน เวอร์ชั่นล่าสุด: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "เส้นทางของไฟล์มีภาษาอื่นนอกจากภาษาอังกฤษอยู่ นี่อาจก่อให้เกิดปัญหาได้",
|
||||||
|
|
||||||
|
"dialogOk": "ตกลง",
|
||||||
|
"dialogNo": "ไม่",
|
||||||
|
"serverEnableDialogTitle": "คุณพบแลนเชอร์ของเซิร์ฟเวอร์ Grasscutter",
|
||||||
|
"serverEnableDialogText": "หากคุณยังไม่ได้ติดตั้งเซิร์ฟเวอร์ Grasscutter คุณต้องการจะดาวน์โหลดหรือไม่"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,45 +3,45 @@
|
|||||||
"appName": "GrassClipper",
|
"appName": "GrassClipper",
|
||||||
|
|
||||||
"playOfficial": "Máy chủ chính thức",
|
"playOfficial": "Máy chủ chính thức",
|
||||||
"playPrivate": "Máy chủ thứ 3",
|
"playPrivate": "Máy chủ riêng",
|
||||||
"launchLocalServer": "Khởi động Grasscutter",
|
"launchLocalServer": "Khởi động máy chủ cục bộ",
|
||||||
|
|
||||||
"gameExeSet": "Chọn file \"GenshinImpact.exe\"",
|
"gameExeSet": "Chọn tệp \"GenshinImpact.exe\"",
|
||||||
"grasscutterFileSet": "Chọn file \"Grasscutter.jar\"",
|
"grasscutterFileSet": "Chọn tệp \"Grasscutter.jar\"",
|
||||||
"folderNotSet": "Chưa chọn file",
|
"folderNotSet": "Chưa chọn tệp",
|
||||||
|
|
||||||
"ipPlaceholder": "Địa chỉ",
|
"ipPlaceholder": "Địa chỉ máy chủ",
|
||||||
"portPlaceholder": "Port",
|
"portPlaceholder": "Cổng",
|
||||||
"noFavorites": "Không có máy chủ yêu thích",
|
"noFavorites": "Không có máy chủ yêu thích",
|
||||||
|
|
||||||
"settingsTitle": "Cài đặt",
|
"settingsTitle": "Cài đặt",
|
||||||
"scriptsSectionTitle": "Scripts",
|
"scriptsSectionTitle": "Scripts",
|
||||||
"killswitchOption": "Công tắc đóng",
|
"killswitchOption": "Thoát khẩn cấp",
|
||||||
"killswitchSubtitle": "Dành cho những ai sợ bị ban. Tắt game *và mạng* nếu proxy có vấn đề.",
|
"killswitchSubtitle": "Để phòng tránh bị ban, thoát game *và ngắt internet* của bạn ngay lập tức nếu có vấn đề xảy ra.",
|
||||||
"proxyOption": "Proxy",
|
"proxyOption": "Proxy",
|
||||||
"proxySubtitle": "Dùng để kết nối vào máy chủ thứ 3",
|
"proxySubtitle": "Dùng để kết nối vào máy chủ riêng",
|
||||||
"updateOption": "Cập nhật",
|
"updateOption": "Cập nhật",
|
||||||
"updateSubtitle": "Tạm thời chưa dùng được. Kiểm tra Github để biết thêm chi tiết",
|
"updateSubtitle": "Tính năng tự động cập nhập tạm thời chưa khả dụng. Kiểm tra Github để biết thêm chi tiết",
|
||||||
"languageOption": "Ngôn ngữ",
|
"languageOption": "Ngôn ngữ",
|
||||||
"languageSubtitle": " ",
|
"languageSubtitle": "Thay đổi ngôn ngữ",
|
||||||
"enableServerLauncherOption": "Grasscutter",
|
"enableServerLauncherOption": "Grasscutter",
|
||||||
"enableServerLauncherSubtitle": "Thêm lựa chọn bật máy chủ grasscutter",
|
"enableServerLauncherSubtitle": "Thêm lựa chọn bật máy chủ grasscutter",
|
||||||
"httpsOption": "Dùng HTTPS",
|
"httpsOption": "Dùng HTTPS",
|
||||||
"httpsSubtitle": " ",
|
"httpsSubtitle": "Thay đổi giao thức giữa HTTPS và HTTP",
|
||||||
|
|
||||||
"introSen1": "Hình như đây là lần đầu tiên bạn dùng ứng dụng này!",
|
"introSen1": "Hình như đây là lần đầu tiên bạn dùng ứng dụng này!",
|
||||||
"introSen2": "Trước hết, chào bạn, cảm ơn bạn đã sử dụng! :)",
|
"introSen2": "Trước tiên xin chào và cảm ơn bạn đã sử dụng! :)",
|
||||||
"introSen3": "Bạn có muốn tải proxy không?",
|
"introSen3": "Bạn có muốn cài đặt ngay proxy không?",
|
||||||
"introSen4": "(dùng để vào máy chủ riêng)",
|
"introSen4": "(cần thiết để vào máy chủ riêng)",
|
||||||
|
|
||||||
"updateBtn": "Cập nhật",
|
"updateBtn": "Cập nhật",
|
||||||
"proxyInstallBtn": "Tải",
|
"proxyInstallBtn": "Cài đặt",
|
||||||
"proxyInstallDeny": "Không",
|
"proxyInstallDeny": "Huỷ bỏ",
|
||||||
|
|
||||||
"gameFolderDialog": "Chọn GenshinImpact.exe",
|
"gameFolderDialog": "Chọn tệp GenshinImpact.exe",
|
||||||
"grasscutterFileDialog": "Chọn Grasscutter.jar",
|
"grasscutterFileDialog": "Chọn tệp Grasscutter.jar",
|
||||||
"loggingInTo": "Đang đăng nhập với tên: ",
|
"loggingInTo": "Đang đăng nhập với tên: ",
|
||||||
"registeringFor": "Đăng ký tài khoản: ",
|
"registeringFor": "Đang đăng ký tài khoản: ",
|
||||||
"authUsername": "Tài khoản: ",
|
"authUsername": "Tài khoản: ",
|
||||||
"authPassword": "Mật khẩu: ",
|
"authPassword": "Mật khẩu: ",
|
||||||
"authConfirmPassword": "Xác nhận lại mật khẩu: ",
|
"authConfirmPassword": "Xác nhận lại mật khẩu: ",
|
||||||
@ -49,16 +49,42 @@
|
|||||||
"authRegisterBtn": "Đăng ký",
|
"authRegisterBtn": "Đăng ký",
|
||||||
"authLoginTitle": "Đăng nhập",
|
"authLoginTitle": "Đăng nhập",
|
||||||
"authRegisterTitle": "Đăng ký",
|
"authRegisterTitle": "Đăng ký",
|
||||||
"launchWithoutAuth": "Sử dụng mà không cần đăng nhập",
|
"launchWithoutAuth": "Khởi chạy không cần hệ thống xác thực",
|
||||||
|
|
||||||
"alertInvalid": "Tài khoản hoặc mật khẩu không đúng",
|
"alertInvalid": "Tài khoản hoặc mật khẩu không đúng",
|
||||||
"alertNoPass": "Tài khoản này chưa có mật khẩu.",
|
"alertNoPass": "Chưa có mật khẩu. Vui lòng thiết lập mật khẩu",
|
||||||
"alertUnknown": "Lỗi không xác định, báo cáo với người host",
|
"alertUnknown": "Lỗi không xác định, báo cáo với người quản lý máy chủ",
|
||||||
"alertAuthNoLogin": "Hệ thống đăng nhập đã bị tắt, không cần đăng nhập",
|
"alertAuthNoLogin": "Đã vô hiệu hoá hệ thống xác thực, không cần đăng nhập.",
|
||||||
"alertLoginSuccess": "Đã đăng nhập và tự động sao chép token. Dán token vào phần tài khoản trong game để đăng nhập.",
|
"alertLoginSuccess": "Đăng nhập thành công! Token đã được sao chép vào bộ nhớ tạm. Dán token vào phần tài khoản trong game để đăng nhập.",
|
||||||
|
|
||||||
"alertUserTaken": "Tên tài khoản đã tồn tại",
|
"alertUserTaken": "Tên tài khoản đã tồn tại",
|
||||||
"alertPassMismatch": "Mật khẩu xác thực không đúng với mật khẩu ban đầu",
|
"alertPassMismatch": "Mật khẩu xác thực không trùng khớp",
|
||||||
"alertAuthNoRegister": "Hệ thống đăng nhập đã bị tắt, không cần đăng ký",
|
"alertAuthNoRegister": "Đã vô hiệu hoá hệ thống xác thực, không cần đăng ký.",
|
||||||
"alertRegisterSuccess": "Đăng ký thành công!"
|
"alertRegisterSuccess": "Đăng ký thành công!",
|
||||||
|
|
||||||
|
"downloadTitle": "Tải về",
|
||||||
|
"grassclipperTitle": "GrassClipper",
|
||||||
|
"grasscutterTitle": "Grasscutter",
|
||||||
|
"installerTitle": "Phần cài đặt",
|
||||||
|
"installerSubtitle": "Cài đặt proxy và những phần khác. Cần thiết cho những máy chủ Grasscutter.",
|
||||||
|
"downloadStable": "Tải về Grasscutter phiên bản Stable",
|
||||||
|
"stableSubtitle": "Cài đặt Grasscutter phiên bản Stable. Đây là phiên bản ổn định, tuy nhiên sẽ có ít tính năng.",
|
||||||
|
"downloadDev": "Tải về Grasscutter phiên bản Development",
|
||||||
|
"devSubtitle": "Cài đặt Grasscutter phiên bản Development. Đây là phiên bản mới hơn, thường xuyên cập nhập hơn nhưng có thể sẽ xuất hiện lõi trong quá trình sử dụng.",
|
||||||
|
"downloadResources": "Tài về tài nguyên cho Grasscutter",
|
||||||
|
"resourceSubtitle": "Tải về phần tài nguyên cần thiết cho Grasscutter. Sử dụng tính năng này để tài về phần tài nguyên tự động nếu bạn không muốn tải về thủ công.",
|
||||||
|
|
||||||
|
"gcScriptRunning": "Đang chạy...",
|
||||||
|
"stableInstall": "Tải về",
|
||||||
|
"devInstall": "Tải về",
|
||||||
|
|
||||||
|
"updateNotifText": "Phiên bản mới nhất đang khả dụng: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "Đường dẫn tới tệp tin chứa ký tự phức tạp, có thể gây lỗi!",
|
||||||
|
|
||||||
|
"dialogOk": "OK",
|
||||||
|
"dialogNo": "Không",
|
||||||
|
"serverEnableDialogTitle": "Đã tìm thấy trình khởi chạy Grasscutter!",
|
||||||
|
"serverEnableDialogText": "Không tìm thấy phần cài đặt Grasscutter hiện tại, bạn có muốn tải về?"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -79,5 +79,13 @@
|
|||||||
"stableInstall": "安裝",
|
"stableInstall": "安裝",
|
||||||
"devInstall": "安装",
|
"devInstall": "安装",
|
||||||
|
|
||||||
"updateNotifText": "有新的GrassClipper更新可用! 最新版本: "
|
"updateNotifText": "有新的GrassClipper更新可用! 最新版本: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "此路徑含有中文字體,這可能會導致問題的發生。",
|
||||||
|
|
||||||
|
"dialogOk": "好的",
|
||||||
|
"dialogNo": "不要",
|
||||||
|
"serverEnableDialogTitle": "您找到了Grasscutter本地伺服器啟動器!",
|
||||||
|
"serverEnableDialogText": "如果你現在還沒有把Grasscutter安裝在電腦上面的話,要不要直接從網路上下載?"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"fullLangName": "Simplified Chinese",
|
"fullLangName": "简体中文",
|
||||||
"appName": "GrassClipper 启动器",
|
"appName": "GrassClipper 启动器",
|
||||||
|
|
||||||
"playOfficial": "启动官方服务器",
|
"playOfficial": "启动官方服务器",
|
||||||
@ -60,5 +60,25 @@
|
|||||||
"alertUserTaken": "用户名已被占用",
|
"alertUserTaken": "用户名已被占用",
|
||||||
"alertPassMismatch": "密码与确认密码不匹配",
|
"alertPassMismatch": "密码与确认密码不匹配",
|
||||||
"alertAuthNoRegister": "未启用认证,无需注册!",
|
"alertAuthNoRegister": "未启用认证,无需注册!",
|
||||||
"alertRegisterSuccess": "注册成功!"
|
"alertRegisterSuccess": "注册成功!",
|
||||||
|
|
||||||
|
"downloadTitle": "下载",
|
||||||
|
"grassclipperTitle": "GrassClipper",
|
||||||
|
"grasscutterTitle": "Grasscutter",
|
||||||
|
"installerTitle": "安装",
|
||||||
|
"installerSubtitle": "安装Grasscutter所需的代理和其他工具。",
|
||||||
|
"downloadStable": "下载Grasscutter稳定版",
|
||||||
|
"stableSubtitle": "安装稳定版的Grasscutter。此版本更加稳定,但是功能相对较少。",
|
||||||
|
"downloadDev": "下载Grasscutter开发版",
|
||||||
|
"devSubtitle": "安装开发版的Grasscutter. 这个版本更新更加频繁,但是有时会有些bug。使用风险自负.",
|
||||||
|
"downloadResources": "下载Grasscutter资源",
|
||||||
|
"resourceSubtitle": "将所需资源下载至当前设置的Grasscutter文件夹。 除非你自己放置了资源,否则你应该执行此操作.",
|
||||||
|
|
||||||
|
"gcScriptRunning": "运行中...",
|
||||||
|
"stableInstall": "下载",
|
||||||
|
"devInstall": "下载",
|
||||||
|
|
||||||
|
"updateNotifText": "有新版本可用!当前最新的版本是: ",
|
||||||
|
|
||||||
|
"foreignCharacterAlert": "当前文件路径含有中文字符,可能会导致一些问题。"
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"applicationId": "js.grassclipper.app",
|
"applicationId": "js.grassclipper.app",
|
||||||
"version": "0.9.1",
|
"version": "0.9.9",
|
||||||
"resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu"
|
"resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu"
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"applicationId": "js.grassclipper.app",
|
"applicationId": "js.grassclipper.app",
|
||||||
"version": "0.9.1",
|
"version": "0.9.9",
|
||||||
"defaultMode": "window",
|
"defaultMode": "window",
|
||||||
"port": 0,
|
"port": 0,
|
||||||
"documentRoot": "/resources/",
|
"documentRoot": "/resources/",
|
||||||
|
1585
package-lock.json
generated
Normal file
1585
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "grassclipper",
|
"name": "grassclipper",
|
||||||
"version": "0.9.1",
|
"version": "0.9.9",
|
||||||
"repository": "https://github.com/Grasscutters/GrassClipper.git",
|
"repository": "https://github.com/Grasscutters/GrassClipper.git",
|
||||||
"author": "SpikeHD <spikegdofficial@gmail.com>",
|
"author": "SpikeHD <spikegdofficial@gmail.com>",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -85,7 +85,8 @@ class MlgmXyysd_Anime_Game_Proxy:
|
|||||||
"uspider.yuanshen.com",
|
"uspider.yuanshen.com",
|
||||||
"sdk-static.mihoyo.com",
|
"sdk-static.mihoyo.com",
|
||||||
"abtest-api-data-sg.hoyoverse.com",
|
"abtest-api-data-sg.hoyoverse.com",
|
||||||
"log-upload-os.hoyoverse.com"
|
"log-upload-os.hoyoverse.com",
|
||||||
|
"webapi-os.account.hoyoverse.com"
|
||||||
]
|
]
|
||||||
|
|
||||||
if flow.request.host in LIST_DOMAINS:
|
if flow.request.host in LIST_DOMAINS:
|
||||||
|
@ -2,20 +2,38 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" type="text/css" href="style/index.css" />
|
<link rel="stylesheet" type="text/css" href="style/index.css" />
|
||||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
<script src="js/axios.min.js"></script>
|
||||||
<script src="js/neutralino.js"></script>
|
<script src="js/neutralino.js"></script>
|
||||||
|
<script src="js/init.js"></script>
|
||||||
<script src="js/windowDrag.js"></script>
|
<script src="js/windowDrag.js"></script>
|
||||||
<script src="js/hoverEvt.js"></script>
|
<script src="js/hoverEvt.js"></script>
|
||||||
<script src="js/helpers.js"></script>
|
<script src="js/helpers.js"></script>
|
||||||
<script src="js/index.js"></script>
|
<script src="js/index.js"></script>
|
||||||
|
<script src="js/debug.js"></script>
|
||||||
<script src="js/gcdownloader.js"></script>
|
<script src="js/gcdownloader.js"></script>
|
||||||
<script src="js/onLoad.js"></script>
|
<script src="js/onLoad.js"></script>
|
||||||
|
<script src="js/alerts.js"></script>
|
||||||
<script src="js/options.js"></script>
|
<script src="js/options.js"></script>
|
||||||
<script src="js/login.js"></script>
|
<script src="js/login.js"></script>
|
||||||
<script src="js/authAlert.js"></script>
|
<script src="js/authAlert.js"></script>
|
||||||
<script src="js/translation.js"></script>
|
<script src="js/translation.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Alert Box -->
|
||||||
|
<div id="alert">
|
||||||
|
<span id="alertText">This is a test alert</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Misc dialog -->
|
||||||
|
<div id="miscDialog" style="display: none">
|
||||||
|
<span id="dialogTitle">Dialog!</span>
|
||||||
|
<span id="dialogContent">This is dialog content!</span>
|
||||||
|
<div id="dialogBtns">
|
||||||
|
<button class="altBtn" id="dialogButtonAffirm">OK</button>
|
||||||
|
<button class="altBtn" id="dialogButtonNeg">NO</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- First time setup -->
|
<!-- First time setup -->
|
||||||
<div id="firstTimeNotice" style="display: none">
|
<div id="firstTimeNotice" style="display: none">
|
||||||
<span>
|
<span>
|
||||||
@ -159,12 +177,21 @@
|
|||||||
<div class="downloadRow">
|
<div class="downloadRow">
|
||||||
<div class="downloadSection">
|
<div class="downloadSection">
|
||||||
<span class="downloadLabel" id="downloadResources">Download Grasscutter Resources</span>
|
<span class="downloadLabel" id="downloadResources">Download Grasscutter Resources</span>
|
||||||
<button class="smolBtn" onclick="downloadGC('development')" id="resourceInstall">Download</button>
|
<button class="smolBtn" onclick="downloadResources()" id="resourceInstall">Download</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="downloadSubtitle" id="resourceSubtitle">
|
<span class="downloadSubtitle" id="resourceSubtitle">
|
||||||
Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally.
|
Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="downloadRow">
|
||||||
|
<div class="downloadSection">
|
||||||
|
<span class="downloadLabel" id="downloadData">Download Data Files</span>
|
||||||
|
<button class="smolBtn" onclick="downloadDataFiles()" id="dataInstall">Download</button>
|
||||||
|
</div>
|
||||||
|
<span class="downloadSubtitle" id="dataSubtitle">
|
||||||
|
Downloads Grasscutter data files, such as keys, spawns, and other vital files.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -236,6 +263,13 @@
|
|||||||
Choose between using HTTPS or HTTP.
|
Choose between using HTTPS or HTTP.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="settingsRow">
|
||||||
|
<div class="settingSection">
|
||||||
|
<span class="settingLabel", id="debugTitle">Debugging</span>
|
||||||
|
<input type="checkbox" id="debugOption" onchange="toggleDebugging()" />
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -243,7 +277,7 @@
|
|||||||
<div id="controlBar">
|
<div id="controlBar">
|
||||||
<span id="titleSection">
|
<span id="titleSection">
|
||||||
GrassClipper
|
GrassClipper
|
||||||
<span id="version">0.4.5</span>
|
<span id="version">0.0.0</span>
|
||||||
</span>
|
</span>
|
||||||
<div id="refreshBtn" onclick="window.location.reload()">
|
<div id="refreshBtn" onclick="window.location.reload()">
|
||||||
<img src="icons/refresh.svg" />
|
<img src="icons/refresh.svg" />
|
||||||
|
23
resources/js/alerts.js
Normal file
23
resources/js/alerts.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
function displayAlert(message, clear = 4000) {
|
||||||
|
const alert = document.getElementById('alert')
|
||||||
|
const alertText = document.getElementById('alertText')
|
||||||
|
|
||||||
|
alert.classList.add('show')
|
||||||
|
|
||||||
|
alertText.innerText = message
|
||||||
|
|
||||||
|
debug.log('Displaying message: ' + message)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
hideAlert()
|
||||||
|
}, clear)
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideAlert() {
|
||||||
|
const alert = document.getElementById('alert')
|
||||||
|
const alertText = document.getElementById('alertText')
|
||||||
|
|
||||||
|
debug.log('Hiding alert')
|
||||||
|
|
||||||
|
alert.classList.remove('show')
|
||||||
|
}
|
@ -1,14 +1,16 @@
|
|||||||
let alertTimeout, alertCooldown = 3000
|
let alertTimeout, alertCooldown = 3000
|
||||||
|
|
||||||
async function displayLoginAlert(message, type, cooldown = null) {
|
async function displayLoginAlert(message, type, cooldown = null) {
|
||||||
displayAlert(message, type, cooldown, 'login')
|
displayAuthAlert(message, type, cooldown, 'login')
|
||||||
|
debug.log('Login alert: ' + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function displayRegisterAlert(message, type, cooldown = null) {
|
async function displayRegisterAlert(message, type, cooldown = null) {
|
||||||
displayAlert(message, type, cooldown, 'register')
|
displayAuthAlert(message, type, cooldown, 'register')
|
||||||
|
debug.log('Register alert: ' + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayAlert(message, type, cooldown, name) {
|
function displayAuthAlert(message, type, cooldown, name) {
|
||||||
const elm = document.getElementById(`${name}Alert`)
|
const elm = document.getElementById(`${name}Alert`)
|
||||||
const text = document.getElementById(`${name}AlertText`)
|
const text = document.getElementById(`${name}AlertText`)
|
||||||
|
|
||||||
@ -41,5 +43,7 @@ function displayAlert(message, type, cooldown, name) {
|
|||||||
// Disappear after cooldown
|
// Disappear after cooldown
|
||||||
alertTimeout = setTimeout(() => {
|
alertTimeout = setTimeout(() => {
|
||||||
elm.style.display = 'none'
|
elm.style.display = 'none'
|
||||||
|
|
||||||
|
debug.log('Hiding auth alert')
|
||||||
}, cooldown || alertCooldown)
|
}, cooldown || alertCooldown)
|
||||||
}
|
}
|
3
resources/js/axios.min.js
vendored
Normal file
3
resources/js/axios.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
17
resources/js/debug.js
Normal file
17
resources/js/debug.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const debug = {
|
||||||
|
log: async (...args) => {
|
||||||
|
const cfg = await getCfg()
|
||||||
|
|
||||||
|
if (cfg.debug) console.log('[DEBUG] ', ...args)
|
||||||
|
},
|
||||||
|
warn: async (...args) => {
|
||||||
|
const cfg = await getCfg()
|
||||||
|
|
||||||
|
if (cfg.debug) console.log('[WARNING] ', ...args)
|
||||||
|
},
|
||||||
|
error: async (...args) => {
|
||||||
|
const cfg = await getCfg()
|
||||||
|
|
||||||
|
if (cfg.debug) console.log('[ERROR] ', ...args)
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,8 @@
|
|||||||
async function clearGCInstallation() {
|
|
||||||
Neutralino.os.execCommand('del /s /q "./gc"')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setDownloadButtonsToLoading() {
|
async function setDownloadButtonsToLoading() {
|
||||||
const stableBtn = document.querySelector('#stableInstall')
|
const stableBtn = document.querySelector('#stableInstall')
|
||||||
const devBtn = document.querySelector('#devInstall')
|
const devBtn = document.querySelector('#devInstall')
|
||||||
|
|
||||||
stableBtn.innerText = localeObj.gcScriptRunning || 'Running...'
|
stableBtn.innerText = localeObj.gcScriptRunning || 'Running...'
|
||||||
|
|
||||||
devBtn.innerText = localeObj.gcScriptRunning || 'Running...'
|
devBtn.innerText = localeObj.gcScriptRunning || 'Running...'
|
||||||
|
|
||||||
// Set btns to disabled
|
// Set btns to disabled
|
||||||
@ -16,6 +11,8 @@ async function setDownloadButtonsToLoading() {
|
|||||||
|
|
||||||
devBtn.disabled = true
|
devBtn.disabled = true
|
||||||
devBtn.classList.add('disabled')
|
devBtn.classList.add('disabled')
|
||||||
|
|
||||||
|
debug.log('Set download buttons to loading')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resetDownloadButtons() {
|
async function resetDownloadButtons() {
|
||||||
@ -31,72 +28,122 @@ async function resetDownloadButtons() {
|
|||||||
|
|
||||||
devBtn.disabled = false
|
devBtn.disabled = false
|
||||||
devBtn.classList.remove('disabled')
|
devBtn.classList.remove('disabled')
|
||||||
|
|
||||||
|
debug.log('Reset download buttons')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadGC(branch) {
|
async function downloadDataFiles(branch) {
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
// If we are pulling from a new branch, delete the old installation
|
if (!branch) {
|
||||||
if (config.grasscutterBranch !== branch) await clearGCInstallation()
|
debug.warn('Branch not specified')
|
||||||
|
branch = config.grasscutterBranch || 'development'
|
||||||
|
}
|
||||||
|
|
||||||
// Set current installation in config
|
debug.log('Using branch: ' + branch)
|
||||||
config.grasscutterBranch = branch
|
|
||||||
|
|
||||||
// Set gc path for people with launcher enabled
|
|
||||||
config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar`
|
|
||||||
|
|
||||||
// Enable server launcher
|
|
||||||
config.serverLaunchPanel = true
|
|
||||||
|
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
|
||||||
|
|
||||||
setDownloadButtonsToLoading()
|
setDownloadButtonsToLoading()
|
||||||
|
|
||||||
// Keystore for branch (since they can differ)
|
|
||||||
const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12`
|
|
||||||
|
|
||||||
// External service that allows un-authed artifact downloading
|
|
||||||
const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip`
|
|
||||||
|
|
||||||
// For data files
|
// For data files
|
||||||
const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`)
|
const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`)
|
||||||
const dataList = dataFiles.data
|
const dataList = dataFiles.data
|
||||||
.map(file => ({ path: file.path, filename: file.name }))
|
.map(file => ({ path: file.path, filename: file.name }))
|
||||||
.map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename }))
|
.map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename }))
|
||||||
|
|
||||||
|
debug.log('Downloaded data files')
|
||||||
|
|
||||||
// For key files
|
// For key files
|
||||||
const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`)
|
const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`)
|
||||||
const keyList = keyFiles.data
|
const keyList = keyFiles.data
|
||||||
.map(file => ({ path: file.path, filename: file.name }))
|
.map(file => ({ path: file.path, filename: file.name }))
|
||||||
.map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename }))
|
.map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename }))
|
||||||
|
|
||||||
|
debug.log('Downloaded key files')
|
||||||
|
|
||||||
const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\')
|
const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\')
|
||||||
|
|
||||||
// Ensure data and key folders exist
|
debug.log('Server folder fixed: ' + serverFolderFixed)
|
||||||
|
|
||||||
await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`)
|
await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`)
|
||||||
await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`)
|
await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`)
|
||||||
|
|
||||||
|
debug.log('Created data and keys folders')
|
||||||
|
|
||||||
// Download data files
|
// Download data files
|
||||||
for (const o of dataList) {
|
for (const o of dataList) {
|
||||||
const folder = 'data'
|
const folder = 'data'
|
||||||
await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`)
|
const e = await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`)
|
||||||
|
debug.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download key files
|
// Download key files
|
||||||
for (const o of keyList) {
|
for (const o of keyList) {
|
||||||
const folder = 'keys'
|
const folder = 'keys'
|
||||||
await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`)
|
const e = await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`)
|
||||||
|
debug.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix buttons
|
||||||
|
resetDownloadButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function downloadGC(branch) {
|
||||||
|
const config = await getCfg()
|
||||||
|
|
||||||
|
// Set current installation in config
|
||||||
|
config.grasscutterBranch = branch
|
||||||
|
|
||||||
|
debug.log('Branch set to: ' + branch)
|
||||||
|
|
||||||
|
// Set gc path for people with launcher enabled
|
||||||
|
config.serverFolder = `${NL_CWD}\\gc-${branch}\\grasscutter.jar`
|
||||||
|
|
||||||
|
debug.log('Server folder automatically set to: ' + config.serverFolder)
|
||||||
|
|
||||||
|
// Enable server launcher
|
||||||
|
config.serverLaunchPanel = true
|
||||||
|
|
||||||
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
|
|
||||||
|
// Download data files
|
||||||
|
downloadDataFiles(branch)
|
||||||
|
|
||||||
|
// External service that allows un-authed artifact downloading
|
||||||
|
let artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip`
|
||||||
|
|
||||||
|
await axios.get(artiUrl).catch(e => {
|
||||||
|
// Fallback link if artifacts are not being uploaded
|
||||||
|
debug.warn('Artifacts not available for latest, falling back...')
|
||||||
|
artiUrl = 'https://nightly.link/Grasscutters/Grasscutter/actions/runs/2284467925/Grasscutter.zip'
|
||||||
|
})
|
||||||
|
|
||||||
|
debug.log('Artifact URL: ' + artiUrl)
|
||||||
|
|
||||||
|
// Keystore for branch (since they can differ)
|
||||||
|
const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12`
|
||||||
|
|
||||||
// Run installer
|
// Run installer
|
||||||
createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`)
|
createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`)
|
||||||
|
|
||||||
// Fix buttons
|
debug.log('Created installer window')
|
||||||
resetDownloadButtons()
|
|
||||||
|
|
||||||
// Display folder after saving config
|
// Display folder after saving config
|
||||||
displayServerFolder()
|
displayServerFolder()
|
||||||
enableServerButton()
|
enableServerButton()
|
||||||
displayServerLaunchSection()
|
displayServerLaunchSection()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function downloadResources() {
|
||||||
|
const config = await getCfg()
|
||||||
|
let serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\')
|
||||||
|
|
||||||
|
// Remove trailing slash, it's important here
|
||||||
|
serverFolderFixed = serverFolderFixed.endsWith('\\') ? serverFolderFixed.slice(0, -1) : serverFolderFixed
|
||||||
|
|
||||||
|
debug.log('Server folder fixed: ' + serverFolderFixed)
|
||||||
|
|
||||||
|
// Dont bother with data or keys, just want straight resources
|
||||||
|
createCmdWindow(`.\\scripts\\resources_download.cmd "${serverFolderFixed}"`)
|
||||||
|
|
||||||
|
debug.log('Created resources window')
|
||||||
|
}
|
@ -12,6 +12,7 @@ async function getCfg() {
|
|||||||
serverLaunchPanel: false,
|
serverLaunchPanel: false,
|
||||||
language: 'en',
|
language: 'en',
|
||||||
useHttps: true,
|
useHttps: true,
|
||||||
|
debug: true,
|
||||||
grasscutterBranch: '',
|
grasscutterBranch: '',
|
||||||
}
|
}
|
||||||
const cfgStr = await Neutralino.storage.getData('config').catch(e => {
|
const cfgStr = await Neutralino.storage.getData('config').catch(e => {
|
||||||
@ -20,6 +21,8 @@ async function getCfg() {
|
|||||||
|
|
||||||
// Show the first time notice if there is no config
|
// Show the first time notice if there is no config
|
||||||
document.querySelector('#firstTimeNotice').style.display = 'block'
|
document.querySelector('#firstTimeNotice').style.display = 'block'
|
||||||
|
|
||||||
|
debug.warn('First time opening')
|
||||||
})
|
})
|
||||||
|
|
||||||
const config = cfgStr ? JSON.parse(cfgStr) : defaultConf
|
const config = cfgStr ? JSON.parse(cfgStr) : defaultConf
|
||||||
@ -36,8 +39,12 @@ async function getFavIps() {
|
|||||||
const ipStr = await Neutralino.storage.getData('favorites').catch(e => {
|
const ipStr = await Neutralino.storage.getData('favorites').catch(e => {
|
||||||
// The data isn't set, so this is our first time opening
|
// The data isn't set, so this is our first time opening
|
||||||
Neutralino.storage.setData('favorites', JSON.stringify([]))
|
Neutralino.storage.setData('favorites', JSON.stringify([]))
|
||||||
|
|
||||||
|
debug.warn('No favorites set')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
debug.log('Favorites:', ipStr)
|
||||||
|
|
||||||
const ipArr = ipStr ? JSON.parse(ipStr) : []
|
const ipArr = ipStr ? JSON.parse(ipStr) : []
|
||||||
|
|
||||||
return ipArr
|
return ipArr
|
||||||
@ -50,20 +57,27 @@ async function proxyIsInstalled() {
|
|||||||
if (curDirList.find(f => f.entry === 'ext')) {
|
if (curDirList.find(f => f.entry === 'ext')) {
|
||||||
const extFiles = await filesystem.readDirectory(NL_CWD + '/ext')
|
const extFiles = await filesystem.readDirectory(NL_CWD + '/ext')
|
||||||
|
|
||||||
|
debug.log('ext/ folder exists')
|
||||||
|
|
||||||
if (extFiles.find(f => f.entry === 'mitmdump.exe')) {
|
if (extFiles.find(f => f.entry === 'mitmdump.exe')) {
|
||||||
|
debug.log('mitmdump exists')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug.log('No proxy installed')
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkForUpdates() {
|
async function checkForUpdates() {
|
||||||
const url = 'https://api.github.com/repos/Grasscutters/GrassClipper/releases/latest'
|
const url = 'https://api.github.com/repos/Grasscutters/GrassClipper/releases/latest'
|
||||||
|
|
||||||
const { data } = await axios.get(url)
|
const { data } = await axios.get(url).catch(e => debug.error('Error getting latest release'))
|
||||||
const latest = data.tag_name
|
const latest = data.tag_name
|
||||||
|
|
||||||
|
debug.log('Latest release:', latest)
|
||||||
|
|
||||||
return latest
|
return latest
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,8 +86,12 @@ async function displayUpdate() {
|
|||||||
const versionDisplay = document.querySelector('#newestVersion')
|
const versionDisplay = document.querySelector('#newestVersion')
|
||||||
const notif = document.querySelector('#downloadNotif')
|
const notif = document.querySelector('#downloadNotif')
|
||||||
|
|
||||||
|
debug.log('Comparing versions: ' + latest + ' vs v' + NL_APPVERSION)
|
||||||
|
|
||||||
if (latest === `v${NL_APPVERSION}`) return
|
if (latest === `v${NL_APPVERSION}`) return
|
||||||
|
|
||||||
|
debug.log('New version available')
|
||||||
|
|
||||||
versionDisplay.innerText = latest
|
versionDisplay.innerText = latest
|
||||||
|
|
||||||
notif.classList.add('displayed')
|
notif.classList.add('displayed')
|
||||||
@ -86,28 +104,87 @@ async function displayUpdate() {
|
|||||||
async function openLatestDownload() {
|
async function openLatestDownload() {
|
||||||
const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/'
|
const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/'
|
||||||
|
|
||||||
|
debug.log('Opening download link: ', downloadLink)
|
||||||
|
|
||||||
Neutralino.os.open(downloadLink)
|
Neutralino.os.open(downloadLink)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openGameFolder() {
|
async function openGameFolder() {
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
const folder = config.gameexe.match(/.*\\/g, '')[0]
|
const folder = config.gameexe?.match(/.*\\|.*\//g, '')
|
||||||
|
|
||||||
openInExplorer(folder)
|
debug.log('Opening game folder: ', folder)
|
||||||
|
|
||||||
|
if (folder?.length > 0) openInExplorer(folder[0].replace(/\//g, '\\'))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openGrasscutterFolder() {
|
async function openGrasscutterFolder() {
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0]
|
const folder = config.serverFolder?.match(/.*\\|.*\//g, '')
|
||||||
|
|
||||||
openInExplorer(folder)
|
debug.log('Opening grasscutter folder: ', folder)
|
||||||
|
|
||||||
|
if (folder?.length > 0) openInExplorer(folder[0].replace(/\//g, '\\'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.jimzhao.us/2015/09/javascript-detect-chinese-character.html
|
||||||
|
function hasForeignChars(str) {
|
||||||
|
let re1 = /[^a-z0-9_.,-\\/: ]/g
|
||||||
|
str = str.replace(/\s/g, '')
|
||||||
|
|
||||||
|
debug.log('Checking for foreign chars in path: ', str)
|
||||||
|
debug.log('Path includes foreign chars? ', re1.test(str))
|
||||||
|
|
||||||
|
return re1.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
function openDialog(title, message, negBtn = false, affirmBtn = closeDialog) {
|
||||||
|
const dialog = document.getElementById('miscDialog')
|
||||||
|
const titleElm = document.getElementById('dialogTitle')
|
||||||
|
const contents = document.getElementById('dialogContent')
|
||||||
|
const noBtn = document.getElementById('dialogButtonNeg')
|
||||||
|
const yesBtn = document.getElementById('dialogButtonAffirm')
|
||||||
|
|
||||||
|
debug.log('Opening dialog: ', title, message)
|
||||||
|
|
||||||
|
if (!negBtn) {
|
||||||
|
noBtn.style.display = 'none'
|
||||||
|
debug.log('No "no" button')
|
||||||
|
} else {
|
||||||
|
noBtn.style.removeProperty('display')
|
||||||
|
noBtn.onclick = () => closeDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
yesBtn.innerText = localeObj.dialogYes || 'OK'
|
||||||
|
noBtn.innerText = localeObj.dialogNo || 'NO'
|
||||||
|
|
||||||
|
yesBtn.onclick = () => {
|
||||||
|
debug.log('Affirmative button clicked')
|
||||||
|
affirmBtn()
|
||||||
|
closeDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set title and message
|
||||||
|
titleElm.innerText = title
|
||||||
|
contents.innerText = message
|
||||||
|
|
||||||
|
// Show the dialog
|
||||||
|
dialog.style.display = 'block'
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDialog() {
|
||||||
|
const dialog = document.getElementById('miscDialog')
|
||||||
|
|
||||||
|
debug.log('Closing dialog')
|
||||||
|
|
||||||
|
dialog.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimize the window
|
* Minimize the window
|
||||||
*/
|
*/
|
||||||
function minimizeWin() {
|
function minimizeWin() {
|
||||||
console.log('min')
|
debug.log('Minimizing window')
|
||||||
Neutralino.window.minimize()
|
Neutralino.window.minimize()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +192,7 @@ function minimizeWin() {
|
|||||||
* Close the window
|
* Close the window
|
||||||
*/
|
*/
|
||||||
function closeWin() {
|
function closeWin() {
|
||||||
console.log('close')
|
debug.log('Closing window')
|
||||||
Neutralino.app.exit()
|
Neutralino.app.exit()
|
||||||
|
|
||||||
window.close()
|
window.close()
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
Neutralino.init()
|
NL_CWD = NL_CWD.replace(/\//g, '\\')
|
||||||
|
|
||||||
let localeObj
|
let localeObj
|
||||||
const filesystem = Neutralino.filesystem
|
const filesystem = Neutralino.filesystem
|
||||||
const createCmdWindow = async (command) => {
|
const createCmdWindow = async (command) => {
|
||||||
|
debug.log('Running command in new window: ' + command)
|
||||||
Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true })
|
Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const openInExplorer = async (path) => {
|
const openInExplorer = async (path) => {
|
||||||
console.log(`explorer.exe "${path}"`)
|
debug.log('Opening path in explorer: ' + path)
|
||||||
createCmdWindow(`explorer.exe "${path}"`)
|
createCmdWindow(`explorer.exe "${path}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,6 +19,8 @@ async function enableButtons() {
|
|||||||
const offBtn = document.querySelector('#playOfficial')
|
const offBtn = document.querySelector('#playOfficial')
|
||||||
const privBtn = document.querySelector('#playPrivate')
|
const privBtn = document.querySelector('#playPrivate')
|
||||||
|
|
||||||
|
debug.log('Enabling buttons')
|
||||||
|
|
||||||
offBtn.classList.remove('disabled')
|
offBtn.classList.remove('disabled')
|
||||||
offBtn.disabled = false
|
offBtn.disabled = false
|
||||||
|
|
||||||
@ -34,6 +37,8 @@ async function enableButtons() {
|
|||||||
async function enableServerButton() {
|
async function enableServerButton() {
|
||||||
const serverBtn = document.querySelector('#serverLaunch')
|
const serverBtn = document.querySelector('#serverLaunch')
|
||||||
|
|
||||||
|
debug.log('Enabling server button')
|
||||||
|
|
||||||
serverBtn.classList.remove('disabled')
|
serverBtn.classList.remove('disabled')
|
||||||
serverBtn.disabled = false
|
serverBtn.disabled = false
|
||||||
}
|
}
|
||||||
@ -43,7 +48,9 @@ async function enableServerButton() {
|
|||||||
*/
|
*/
|
||||||
async function handleGameNotSet() {
|
async function handleGameNotSet() {
|
||||||
// Set buttons to greyed out and disable
|
// Set buttons to greyed out and disable
|
||||||
document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet
|
document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet || 'Not set'
|
||||||
|
|
||||||
|
debug.log('Handling game not set')
|
||||||
|
|
||||||
// Set official server background to default
|
// Set official server background to default
|
||||||
document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")'
|
document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")'
|
||||||
@ -62,7 +69,9 @@ async function handleGameNotSet() {
|
|||||||
|
|
||||||
async function handleServerNotSet() {
|
async function handleServerNotSet() {
|
||||||
// Set buttons to greyed out and disable
|
// Set buttons to greyed out and disable
|
||||||
document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet
|
document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet || 'Not set'
|
||||||
|
|
||||||
|
debug.log('Handling server not set')
|
||||||
|
|
||||||
// Set official server background to default
|
// Set official server background to default
|
||||||
// document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")`
|
// document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")`
|
||||||
@ -80,6 +89,8 @@ async function displayGameFolder() {
|
|||||||
const elm = document.querySelector('#gamePath')
|
const elm = document.querySelector('#gamePath')
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Displaying game exe')
|
||||||
|
|
||||||
elm.innerHTML = config.gameexe
|
elm.innerHTML = config.gameexe
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +101,8 @@ async function displayServerFolder() {
|
|||||||
const elm = document.querySelector('#serverPath')
|
const elm = document.querySelector('#serverPath')
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Displaying server folder')
|
||||||
|
|
||||||
elm.innerHTML = config.serverFolder
|
elm.innerHTML = config.serverFolder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,9 +121,13 @@ async function setBackgroundImage() {
|
|||||||
// Set default image, it will change if the bg folder exists
|
// Set default image, it will change if the bg folder exists
|
||||||
document.querySelector('#firstPanel').style.backgroundImage = 'url("https://webstatic.hoyoverse.com/upload/event/2020/11/04/7fd661b5184e1734f91f628b6f89a31f_7367318474207189623.png")'
|
document.querySelector('#firstPanel').style.backgroundImage = 'url("https://webstatic.hoyoverse.com/upload/event/2020/11/04/7fd661b5184e1734f91f628b6f89a31f_7367318474207189623.png")'
|
||||||
|
|
||||||
|
debug.log('Setting second panel to: ' + privImage)
|
||||||
|
|
||||||
// Set the private background image
|
// Set the private background image
|
||||||
document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")`
|
document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")`
|
||||||
|
|
||||||
|
debug.log('Setting third panel to: ' + servImage)
|
||||||
|
|
||||||
// Set the server background image
|
// Set the server background image
|
||||||
document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")`
|
document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")`
|
||||||
|
|
||||||
@ -177,6 +194,8 @@ async function handleFavoriteInput() {
|
|||||||
|
|
||||||
const addr = `${ip}:${port}`
|
const addr = `${ip}:${port}`
|
||||||
|
|
||||||
|
debug.log('Checking if IP is a favorite: ' + addr)
|
||||||
|
|
||||||
if (!ip || !ipArr.includes(addr)) {
|
if (!ip || !ipArr.includes(addr)) {
|
||||||
document.querySelector('#star').src = 'icons/star_empty.svg'
|
document.querySelector('#star').src = 'icons/star_empty.svg'
|
||||||
} else {
|
} else {
|
||||||
@ -196,6 +215,8 @@ async function setIp(ip) {
|
|||||||
const parseIp = ip.split(':')[0]
|
const parseIp = ip.split(':')[0]
|
||||||
const parsePort = ip.split(':')[1]
|
const parsePort = ip.split(':')[1]
|
||||||
|
|
||||||
|
debug.log('Setting IP input elm to: ' + parseIp + ' and port to: ' + parsePort)
|
||||||
|
|
||||||
// Set star
|
// Set star
|
||||||
if (ip) {
|
if (ip) {
|
||||||
document.querySelector('#star').src = 'icons/star_filled.svg'
|
document.querySelector('#star').src = 'icons/star_filled.svg'
|
||||||
@ -213,6 +234,8 @@ async function handleFavoriteList() {
|
|||||||
const ipList = document.querySelector('#ipList')
|
const ipList = document.querySelector('#ipList')
|
||||||
|
|
||||||
if (ipList.style.display === 'none') {
|
if (ipList.style.display === 'none') {
|
||||||
|
debug.log('IP list was closed, opening it')
|
||||||
|
|
||||||
ipList.innerHTML = ''
|
ipList.innerHTML = ''
|
||||||
|
|
||||||
const list = ipList.appendChild(
|
const list = ipList.appendChild(
|
||||||
@ -220,11 +243,12 @@ async function handleFavoriteList() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (ipArr.length < 1) {
|
if (ipArr.length < 1) {
|
||||||
|
console.log('No favorites found')
|
||||||
const listItem = list.appendChild(
|
const listItem = list.appendChild(
|
||||||
document.createElement('li')
|
document.createElement('li')
|
||||||
)
|
)
|
||||||
|
|
||||||
listItem.innerHTML = localeObj.noFavorites
|
listItem.innerHTML = localeObj.noFavorites || 'No favorites set'
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ip of ipArr) {
|
for (const ip of ipArr) {
|
||||||
@ -240,6 +264,8 @@ async function handleFavoriteList() {
|
|||||||
const xy = [ transform.split(',')[4], transform.split(',')[5] ]
|
const xy = [ transform.split(',')[4], transform.split(',')[5] ]
|
||||||
let newY = (27 * ipArr.length) * window.devicePixelRatio
|
let newY = (27 * ipArr.length) * window.devicePixelRatio
|
||||||
|
|
||||||
|
debug.log('IP list height: 56vh - ' + newY)
|
||||||
|
|
||||||
if (ipArr.length === 0 || ipArr.length === 1) newY = 0
|
if (ipArr.length === 0 || ipArr.length === 1) newY = 0
|
||||||
|
|
||||||
ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)`
|
ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)`
|
||||||
@ -250,23 +276,37 @@ async function openDownloads() {
|
|||||||
const downloads = document.querySelector('#downloadPanel')
|
const downloads = document.querySelector('#downloadPanel')
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Opening downloads panel')
|
||||||
|
|
||||||
if (downloads.style.display === 'none') {
|
if (downloads.style.display === 'none') {
|
||||||
downloads.style.removeProperty('display')
|
downloads.style.removeProperty('display')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable the resource download button if a serverFolder path is not set
|
// Disable the resource download button if a serverFolder path is not set
|
||||||
if (!config.serverFolder) {
|
if (!config.serverFolder) {
|
||||||
|
debug.log('Server folder not set, disabling resource download button and data download button')
|
||||||
document.querySelector('#resourceInstall').disabled = true
|
document.querySelector('#resourceInstall').disabled = true
|
||||||
document.querySelector('#resourceInstall').classList.add('disabled')
|
document.querySelector('#resourceInstall').classList.add('disabled')
|
||||||
|
|
||||||
|
// Disable data installer
|
||||||
|
document.querySelector('#dataInstall').disabled = true
|
||||||
|
document.querySelector('#dataInstall').classList.add('disabled')
|
||||||
} else {
|
} else {
|
||||||
|
debug.log('Server folder is set, enabling resource download button and data download button')
|
||||||
document.querySelector('#resourceInstall').disabled = false
|
document.querySelector('#resourceInstall').disabled = false
|
||||||
document.querySelector('#resourceInstall').classList.remove('disabled')
|
document.querySelector('#resourceInstall').classList.remove('disabled')
|
||||||
|
|
||||||
|
// Enable data installer
|
||||||
|
document.querySelector('#dataInstall').disabled = false
|
||||||
|
document.querySelector('#dataInstall').classList.remove('disabled')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function closeDownloads() {
|
async function closeDownloads() {
|
||||||
const downloads = document.querySelector('#downloadPanel')
|
const downloads = document.querySelector('#downloadPanel')
|
||||||
|
|
||||||
|
debug.log('Closing downloads panel')
|
||||||
|
|
||||||
downloads.style.display = 'none'
|
downloads.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +314,8 @@ async function openSettings() {
|
|||||||
const settings = document.querySelector('#settingsPanel')
|
const settings = document.querySelector('#settingsPanel')
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Opening settings panel')
|
||||||
|
|
||||||
if (settings.style.display === 'none') {
|
if (settings.style.display === 'none') {
|
||||||
settings.style.removeProperty('display')
|
settings.style.removeProperty('display')
|
||||||
}
|
}
|
||||||
@ -287,6 +329,10 @@ async function openSettings() {
|
|||||||
serverLaunch.checked = config.serverLaunchPanel
|
serverLaunch.checked = config.serverLaunchPanel
|
||||||
httpsCheckbox.checked = config.useHttps
|
httpsCheckbox.checked = config.useHttps
|
||||||
|
|
||||||
|
debug.log('Set killswitch to: ' + config.enableKillswitch)
|
||||||
|
debug.log('Set server launch to: ' + config.serverLaunchPanel)
|
||||||
|
debug.log('Set https to: ' + config.useHttps)
|
||||||
|
|
||||||
// Load languages
|
// Load languages
|
||||||
getLanguages()
|
getLanguages()
|
||||||
|
|
||||||
@ -298,10 +344,14 @@ async function closeSettings() {
|
|||||||
const settings = document.querySelector('#settingsPanel')
|
const settings = document.querySelector('#settingsPanel')
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Closing settings panel')
|
||||||
|
|
||||||
settings.style.display = 'none'
|
settings.style.display = 'none'
|
||||||
|
|
||||||
// In case we installed the proxy server
|
// In case we installed the proxy server
|
||||||
if (await proxyIsInstalled() && config.gameexe) {
|
if (await proxyIsInstalled() && config.gameexe) {
|
||||||
|
debug.log('Proxy has been installed and EXE is set, enabling playPrivate')
|
||||||
|
|
||||||
const playPriv = document.querySelector('#playPrivate')
|
const playPriv = document.querySelector('#playPrivate')
|
||||||
|
|
||||||
playPriv.classList.remove('disabled')
|
playPriv.classList.remove('disabled')
|
||||||
@ -320,19 +370,28 @@ async function openLogin() {
|
|||||||
const useHttps = config.useHttps
|
const useHttps = config.useHttps
|
||||||
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
|
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
|
||||||
|
|
||||||
|
debug.log('Opening login panel')
|
||||||
|
debug.log('Url: ' + url)
|
||||||
|
|
||||||
// Check if we even need to authenticate
|
// Check if we even need to authenticate
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(url + '/authentication/type')
|
const { data } = await axios.get(url + '/authentication/type')
|
||||||
|
|
||||||
|
debug.log('Request successful')
|
||||||
|
|
||||||
if (!data.includes('GCAuthAuthenticationHandler')) {
|
if (!data.includes('GCAuthAuthenticationHandler')) {
|
||||||
|
debug.log('No authentication required')
|
||||||
launchPrivate()
|
launchPrivate()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
debug.warn('Request failed')
|
||||||
launchPrivate()
|
launchPrivate()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug.log('Login panel opening')
|
||||||
|
|
||||||
loginIpDisplay.innerText = ip
|
loginIpDisplay.innerText = ip
|
||||||
registerIpDisplay.innerText = ip
|
registerIpDisplay.innerText = ip
|
||||||
|
|
||||||
@ -344,6 +403,8 @@ async function openLogin() {
|
|||||||
async function closeLogin() {
|
async function closeLogin() {
|
||||||
const login = document.querySelector('#loginPanel')
|
const login = document.querySelector('#loginPanel')
|
||||||
|
|
||||||
|
debug.log('Closing login panel')
|
||||||
|
|
||||||
login.style.display = 'none'
|
login.style.display = 'none'
|
||||||
|
|
||||||
setLoginSection()
|
setLoginSection()
|
||||||
@ -351,16 +412,22 @@ async function closeLogin() {
|
|||||||
|
|
||||||
async function closeFirstTimePopup() {
|
async function closeFirstTimePopup() {
|
||||||
const firstTimePopup = document.querySelector('#firstTimeNotice')
|
const firstTimePopup = document.querySelector('#firstTimeNotice')
|
||||||
|
|
||||||
|
debug.log('Closing first time popup')
|
||||||
|
|
||||||
firstTimePopup.style.display = 'none'
|
firstTimePopup.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runInstallScript() {
|
async function runInstallScript() {
|
||||||
|
debug.log('Running install script')
|
||||||
createCmdWindow(`.\\scripts\\install.cmd "${NL_CWD}" true`)
|
createCmdWindow(`.\\scripts\\install.cmd "${NL_CWD}" true`)
|
||||||
|
|
||||||
// Create an interval that will check for the proxy server installation finish
|
// Create an interval that will check for the proxy server installation finish
|
||||||
const interval = setInterval(async () => {
|
const interval = setInterval(async () => {
|
||||||
|
debug.log('Checking if proxy server is installed')
|
||||||
if (await proxyIsInstalled()) {
|
if (await proxyIsInstalled()) {
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
|
debug.log('Proxy server installed')
|
||||||
enableButtons()
|
enableButtons()
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
@ -380,9 +447,11 @@ async function checkForUpdatesAndShow() {
|
|||||||
|
|
||||||
// Version mismatch? Update!
|
// Version mismatch? Update!
|
||||||
if (manifest?.version !== NL_APPVERSION) {
|
if (manifest?.version !== NL_APPVERSION) {
|
||||||
|
debug.log('New update available')
|
||||||
subtitle.innerHTML = 'New update available!'
|
subtitle.innerHTML = 'New update available!'
|
||||||
updateBtn.classList.remove('disabled')
|
updateBtn.classList.remove('disabled')
|
||||||
} else {
|
} else {
|
||||||
|
debug.log('New update not available')
|
||||||
subtitle.innerHTML = 'You are on the latest version! :)'
|
subtitle.innerHTML = 'You are on the latest version! :)'
|
||||||
updateBtn.classList.add('disabled')
|
updateBtn.classList.add('disabled')
|
||||||
}
|
}
|
||||||
@ -392,10 +461,14 @@ async function displayServerLaunchSection() {
|
|||||||
const serverPanel = document.querySelector('#thirdPanel')
|
const serverPanel = document.querySelector('#thirdPanel')
|
||||||
const bottomBtnSection = document.querySelector('#serverPath').parentElement
|
const bottomBtnSection = document.querySelector('#serverPath').parentElement
|
||||||
|
|
||||||
|
debug.log('Displaying server launch section')
|
||||||
|
|
||||||
if (serverPanel.style.display === 'none') {
|
if (serverPanel.style.display === 'none') {
|
||||||
|
debug.log('Showing server launch section')
|
||||||
serverPanel.style.removeProperty('display')
|
serverPanel.style.removeProperty('display')
|
||||||
bottomBtnSection.style.removeProperty('display')
|
bottomBtnSection.style.removeProperty('display')
|
||||||
} else {
|
} else {
|
||||||
|
debug.log('Hiding server launch section')
|
||||||
serverPanel.style.display = 'none'
|
serverPanel.style.display = 'none'
|
||||||
bottomBtnSection.style.display = 'none'
|
bottomBtnSection.style.display = 'none'
|
||||||
}
|
}
|
||||||
@ -405,13 +478,16 @@ async function displayServerLaunchSection() {
|
|||||||
* Set the game folder by opening a folder picker
|
* Set the game folder by opening a folder picker
|
||||||
*/
|
*/
|
||||||
async function setGameExe() {
|
async function setGameExe() {
|
||||||
const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, {
|
const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog || 'Select game folder', {
|
||||||
filters: [
|
filters: [
|
||||||
{ name: 'Executable files', extensions: ['exe'] }
|
{ name: 'Executable files', extensions: ['exe'] }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
debug.log('Game exe selected: ' + gameExe[0])
|
||||||
|
|
||||||
if (!gameExe[0]) return
|
if (!gameExe[0]) return
|
||||||
|
if (hasForeignChars(gameExe[0])) displayAlert(localeObj.foreignCharacterAlert || 'The file path set contains foreign characters, this may cause problems!')
|
||||||
|
|
||||||
// Set the folder in our configuration
|
// Set the folder in our configuration
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
@ -419,6 +495,8 @@ async function setGameExe() {
|
|||||||
// It's an array of selections, so only get the first one
|
// It's an array of selections, so only get the first one
|
||||||
config.gameexe = gameExe[0].replace(/\//g, '\\')
|
config.gameexe = gameExe[0].replace(/\//g, '\\')
|
||||||
|
|
||||||
|
debug.log('Setting game exe to: ' + config.gameexe)
|
||||||
|
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
|
|
||||||
// Refresh background and path
|
// Refresh background and path
|
||||||
@ -428,18 +506,24 @@ async function setGameExe() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function setGrasscutterFolder() {
|
async function setGrasscutterFolder() {
|
||||||
const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, {
|
const folder = await Neutralino.os.showOpenDialog(localeObj?.grasscutterFileDialog || 'Select Grasscutter server jar file', {
|
||||||
filters: [
|
filters: [
|
||||||
{ name: 'Jar files', extensions: ['jar'] }
|
{ name: 'Jar files', extensions: ['jar'] }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
debug.log('Grasscutter folder selected: ' + folder[0])
|
||||||
|
|
||||||
if (!folder[0]) return
|
if (!folder[0]) return
|
||||||
|
if (hasForeignChars(folder[0])) displayAlert(localeObj.foreignCharacterAlert || 'The file path set contains foreign characters, this may cause problems!')
|
||||||
|
|
||||||
// Set the folder in our configuration
|
// Set the folder in our configuration
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
config.serverFolder = folder[0]
|
config.serverFolder = folder[0]
|
||||||
|
|
||||||
|
debug.log('Setting grasscutter folder to: ' + config.serverFolder)
|
||||||
|
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
|
|
||||||
displayServerFolder()
|
displayServerFolder()
|
||||||
@ -452,6 +536,8 @@ async function setGrasscutterFolder() {
|
|||||||
async function launchOfficial() {
|
async function launchOfficial() {
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Launching game at ' + config.gameexe)
|
||||||
|
|
||||||
Neutralino.os.execCommand(`"${config.gameexe}"`)
|
Neutralino.os.execCommand(`"${config.gameexe}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,18 +550,24 @@ async function launchPrivate() {
|
|||||||
|
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
console.log('connecting to ' + ip + ':' + port)
|
debug.log('Connecting to ' + ip + ':' + port)
|
||||||
|
|
||||||
// Set the last connect
|
// Set the last connect
|
||||||
config.lastConnect = ip
|
config.lastConnect = ip
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
|
|
||||||
// Pass IP and game folder to the private server launcher
|
// Pass IP and game folder to the private server launcher
|
||||||
createCmdWindow(`.\\scripts\\private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e))
|
Neutralino.os.execCommand(
|
||||||
|
`.\\scripts\\private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`, {
|
||||||
|
background: true
|
||||||
|
}
|
||||||
|
).catch(e => debug.error(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function launchLocalServer() {
|
async function launchLocalServer() {
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Launching local server')
|
||||||
|
|
||||||
createCmdWindow(`.\\scripts\\local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e))
|
createCmdWindow(`.\\scripts\\local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e))
|
||||||
}
|
}
|
||||||
|
2
resources/js/init.js
Normal file
2
resources/js/init.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// This file is the very first loaded when the app is started.
|
||||||
|
Neutralino.init()
|
@ -7,6 +7,8 @@ async function setLoginSection() {
|
|||||||
const loginSection = document.getElementById('loginPopupContentBody')
|
const loginSection = document.getElementById('loginPopupContentBody')
|
||||||
const registerSection = document.getElementById('registerPopupContentBody')
|
const registerSection = document.getElementById('registerPopupContentBody')
|
||||||
|
|
||||||
|
debug.log('Setting to login section')
|
||||||
|
|
||||||
title.classList.add('selectedTitle')
|
title.classList.add('selectedTitle')
|
||||||
altTitle.classList.remove('selectedTitle')
|
altTitle.classList.remove('selectedTitle')
|
||||||
|
|
||||||
@ -23,6 +25,8 @@ async function setRegisterSection(fromLogin = false) {
|
|||||||
const loginSection = document.getElementById('loginPopupContentBody')
|
const loginSection = document.getElementById('loginPopupContentBody')
|
||||||
const registerSection = document.getElementById('registerPopupContentBody')
|
const registerSection = document.getElementById('registerPopupContentBody')
|
||||||
|
|
||||||
|
debug.log('Setting to register section')
|
||||||
|
|
||||||
title.classList.add('selectedTitle')
|
title.classList.add('selectedTitle')
|
||||||
altTitle.classList.remove('selectedTitle')
|
altTitle.classList.remove('selectedTitle')
|
||||||
|
|
||||||
@ -30,6 +34,8 @@ async function setRegisterSection(fromLogin = false) {
|
|||||||
registerSection.style.removeProperty('display')
|
registerSection.style.removeProperty('display')
|
||||||
|
|
||||||
if (fromLogin) {
|
if (fromLogin) {
|
||||||
|
debug.log('Just registered, setting to login page')
|
||||||
|
|
||||||
// Take the values from the login section and put them in the register section
|
// Take the values from the login section and put them in the register section
|
||||||
const loginUsername = document.getElementById('loginUsername').value
|
const loginUsername = document.getElementById('loginUsername').value
|
||||||
const loginPassword = document.getElementById('loginPassword').value
|
const loginPassword = document.getElementById('loginPassword').value
|
||||||
@ -42,6 +48,9 @@ async function setRegisterSection(fromLogin = false) {
|
|||||||
function parseJwt(token) {
|
function parseJwt(token) {
|
||||||
const base64Url = token.split('.')[1]
|
const base64Url = token.split('.')[1]
|
||||||
const base64 = base64Url.replace('-', '+').replace('_', '/')
|
const base64 = base64Url.replace('-', '+').replace('_', '/')
|
||||||
|
|
||||||
|
debug.log('Parsed JWT: ' + base64)
|
||||||
|
|
||||||
return JSON.parse(window.atob(base64))
|
return JSON.parse(window.atob(base64))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,12 +66,14 @@ async function login() {
|
|||||||
const useHttps = config.useHttps
|
const useHttps = config.useHttps
|
||||||
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
|
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
|
||||||
|
|
||||||
|
debug.log('Attempting login to ' + url)
|
||||||
|
|
||||||
const reqBody = {
|
const reqBody = {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await axios.post(url + '/authentication/login', reqBody)
|
const { data } = await axios.post(url + '/authentication/login', reqBody).catch(e => debug.error('Login request failed: ' + e))
|
||||||
|
|
||||||
switch(data.message) {
|
switch(data.message) {
|
||||||
case 'INVALID_ACCOUNT':
|
case 'INVALID_ACCOUNT':
|
||||||
@ -92,6 +103,8 @@ async function login() {
|
|||||||
const tkData = parseJwt(data.jwt)
|
const tkData = parseJwt(data.jwt)
|
||||||
await Neutralino.clipboard.writeText(tkData.token)
|
await Neutralino.clipboard.writeText(tkData.token)
|
||||||
|
|
||||||
|
debug.log('Login success')
|
||||||
|
|
||||||
displayLoginAlert(localeObj.alertLoginSuccess || 'Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000)
|
displayLoginAlert(localeObj.alertLoginSuccess || 'Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000)
|
||||||
launchPrivate()
|
launchPrivate()
|
||||||
break
|
break
|
||||||
@ -111,13 +124,15 @@ async function register() {
|
|||||||
const useHttps = config.useHttps
|
const useHttps = config.useHttps
|
||||||
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
|
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
|
||||||
|
|
||||||
|
debug.log('Attempting registration to ' + url)
|
||||||
|
|
||||||
const reqBody = {
|
const reqBody = {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
password_confirmation
|
password_confirmation
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await axios.post(url + '/authentication/register', reqBody)
|
const { data } = await axios.post(url + '/authentication/register', reqBody).catch(e => debug.error('Registration request failed: ' + e))
|
||||||
|
|
||||||
switch(data.message) {
|
switch(data.message) {
|
||||||
case 'USERNAME_TAKEN':
|
case 'USERNAME_TAKEN':
|
||||||
@ -147,6 +162,8 @@ async function register() {
|
|||||||
const loginUsername = document.getElementById('loginUsername')
|
const loginUsername = document.getElementById('loginUsername')
|
||||||
loginUsername.value = username
|
loginUsername.value = username
|
||||||
|
|
||||||
|
debug.log('Registered with username ' + username)
|
||||||
|
|
||||||
setLoginSection()
|
setLoginSection()
|
||||||
displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000)
|
displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000)
|
||||||
break
|
break
|
||||||
|
@ -7,6 +7,8 @@ async function toggleKillSwitch() {
|
|||||||
|
|
||||||
config.enableKillswitch = killSwitch.checked
|
config.enableKillswitch = killSwitch.checked
|
||||||
|
|
||||||
|
debug.log('Killswitch is now ', config.enableKillswitch)
|
||||||
|
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,9 +20,25 @@ async function toggleServerLaunchSection() {
|
|||||||
|
|
||||||
displayServerLaunchSection()
|
displayServerLaunchSection()
|
||||||
|
|
||||||
|
debug.log('Toggling server panel')
|
||||||
|
|
||||||
// Save setting
|
// Save setting
|
||||||
config.serverLaunchPanel = !config.serverLaunchPanel
|
config.serverLaunchPanel = !config.serverLaunchPanel
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
|
|
||||||
|
// Show a dialog for those who may want to open the downloads section
|
||||||
|
if (config.serverLaunchPanel && !config.serverFolder) {
|
||||||
|
closeSettings()
|
||||||
|
|
||||||
|
debug.log('First time server launcher')
|
||||||
|
|
||||||
|
openDialog(
|
||||||
|
localeObj.serverEnableDialogTitle || 'You found the Grasscutter server launcher!',
|
||||||
|
localeObj.serverEnableDialogText || 'If you do not have an existing Grasscutter installation to set, would you like to download a build?',
|
||||||
|
true,
|
||||||
|
openDownloads
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,6 +48,8 @@ async function getLanguages() {
|
|||||||
const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json'))
|
const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json'))
|
||||||
const config = await getCfg()
|
const config = await getCfg()
|
||||||
|
|
||||||
|
debug.log('Grabbing languages')
|
||||||
|
|
||||||
// Clear language options
|
// Clear language options
|
||||||
const languageSelect = document.querySelector('#languageSelect')
|
const languageSelect = document.querySelector('#languageSelect')
|
||||||
languageSelect.innerHTML = ''
|
languageSelect.innerHTML = ''
|
||||||
@ -39,12 +59,15 @@ async function getLanguages() {
|
|||||||
const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName
|
const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName
|
||||||
const lang = file.entry.split('.json')[0]
|
const lang = file.entry.split('.json')[0]
|
||||||
|
|
||||||
|
debug.log('Loading language: ', lang)
|
||||||
|
|
||||||
const option = document.createElement('option')
|
const option = document.createElement('option')
|
||||||
option.value = lang
|
option.value = lang
|
||||||
option.innerHTML = fullLanguageName
|
option.innerHTML = fullLanguageName
|
||||||
|
|
||||||
// Set language selected to config language
|
// Set language selected to config language
|
||||||
if (lang === config.language) {
|
if (lang === config.language) {
|
||||||
|
debug.log('Selected language: ', lang)
|
||||||
option.selected = true
|
option.selected = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +88,8 @@ async function handleLanguageChange(elm) {
|
|||||||
config.language = list.value
|
config.language = list.value
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
|
|
||||||
|
debug.log('Language changed to: ', list.value)
|
||||||
|
|
||||||
// Force refresh of application, no need for restart!
|
// Force refresh of application, no need for restart!
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
@ -78,6 +103,22 @@ async function toggleHttps() {
|
|||||||
|
|
||||||
config.useHttps = httpsCheckbox.checked
|
config.useHttps = httpsCheckbox.checked
|
||||||
|
|
||||||
|
debug.log('HTTPS set to: ', config.useHttps)
|
||||||
|
|
||||||
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle debugging
|
||||||
|
*/
|
||||||
|
async function toggleDebugging() {
|
||||||
|
const debugCheckbox = document.querySelector('#debugOption')
|
||||||
|
const config = await getCfg()
|
||||||
|
|
||||||
|
config.debug = debugCheckbox.checked
|
||||||
|
|
||||||
|
debug.log('Debugging set to: ', config.debug)
|
||||||
|
|
||||||
Neutralino.storage.setData('config', JSON.stringify(config))
|
Neutralino.storage.setData('config', JSON.stringify(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,12 +134,16 @@ async function setFavorite() {
|
|||||||
|
|
||||||
const addr = `${ip}:${port}`
|
const addr = `${ip}:${port}`
|
||||||
|
|
||||||
|
debug.log('Handling favorite: ', addr)
|
||||||
|
|
||||||
// Set star icon
|
// Set star icon
|
||||||
const star = document.querySelector('#star')
|
const star = document.querySelector('#star')
|
||||||
|
|
||||||
if (star.src.includes('filled') && ip) {
|
if (star.src.includes('filled') && ip) {
|
||||||
star.src = 'icons/star_empty.svg'
|
star.src = 'icons/star_empty.svg'
|
||||||
|
|
||||||
|
debug.log('Removing from list: ', addr)
|
||||||
|
|
||||||
// remove from list
|
// remove from list
|
||||||
ipArr.splice(ipArr.indexOf(addr), 1)
|
ipArr.splice(ipArr.indexOf(addr), 1)
|
||||||
} else {
|
} else {
|
||||||
@ -106,6 +151,7 @@ async function setFavorite() {
|
|||||||
|
|
||||||
// add to list
|
// add to list
|
||||||
if (ip && !ipArr.includes(addr)) {
|
if (ip && !ipArr.includes(addr)) {
|
||||||
|
debug.log('Adding to list: ', addr)
|
||||||
ipArr.push(addr)
|
ipArr.push(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,8 @@ async function doTranslation() {
|
|||||||
set('grasscutterFileSet', 'grasscutterFileSet')
|
set('grasscutterFileSet', 'grasscutterFileSet')
|
||||||
|
|
||||||
// Private options
|
// Private options
|
||||||
document.querySelector('#ip').placeholder = localeObj.ipPlaceholder
|
document.querySelector('#ip').placeholder = localeObj.ipPlaceholder || 'IP Address'
|
||||||
document.querySelector('#port').placeholder = localeObj.portPlaceholder
|
document.querySelector('#port').placeholder = localeObj.portPlaceholder || 'Port'
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
set('fullSettingsTitle', 'settingsTitle')
|
set('fullSettingsTitle', 'settingsTitle')
|
||||||
@ -58,6 +58,7 @@ async function doTranslation() {
|
|||||||
set('serverSubtitle', 'enableServerLauncherSubtitle')
|
set('serverSubtitle', 'enableServerLauncherSubtitle')
|
||||||
set('httpsTitle', 'httpsOption')
|
set('httpsTitle', 'httpsOption')
|
||||||
set('httpsSubtitle', 'httpsSubtitle')
|
set('httpsSubtitle', 'httpsSubtitle')
|
||||||
|
set('debugTitle', 'debugOption')
|
||||||
|
|
||||||
// Intro popup
|
// Intro popup
|
||||||
const popup = document.getElementById('firstTimeNotice')
|
const popup = document.getElementById('firstTimeNotice')
|
||||||
@ -100,6 +101,8 @@ async function doTranslation() {
|
|||||||
set('stableSubtitle', 'stableSubtitle')
|
set('stableSubtitle', 'stableSubtitle')
|
||||||
set('downloadDev', 'downloadDev')
|
set('downloadDev', 'downloadDev')
|
||||||
set('devSubtitle', 'devSubtitle')
|
set('devSubtitle', 'devSubtitle')
|
||||||
|
set('dataSubtitle', 'dataSubtitle')
|
||||||
|
set('downloadData', 'downloadData')
|
||||||
set('downloadResources', 'downloadResources')
|
set('downloadResources', 'downloadResources')
|
||||||
set('resourceSubtitle', 'resourceSubtitle')
|
set('resourceSubtitle', 'resourceSubtitle')
|
||||||
set('stableInstall', 'stableInstall')
|
set('stableInstall', 'stableInstall')
|
||||||
|
@ -35,6 +35,7 @@ img {
|
|||||||
margin: 10px;
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#miscDialog span,
|
||||||
#firstTimeNotice span {
|
#firstTimeNotice span {
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -159,6 +160,7 @@ img {
|
|||||||
margin: 10px;
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#miscDialog,
|
||||||
#firstTimeNotice,
|
#firstTimeNotice,
|
||||||
#loginPanel,
|
#loginPanel,
|
||||||
#downloadPanel,
|
#downloadPanel,
|
||||||
@ -601,3 +603,42 @@ img {
|
|||||||
#newestVersion {
|
#newestVersion {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#alert {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
color: #704a1d;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: -100%;
|
||||||
|
left: 15%;
|
||||||
|
background: linear-gradient(#ffc61e, #ffd326);
|
||||||
|
border: 1px solid #704a1d;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
height: 50px;
|
||||||
|
width: 70%;
|
||||||
|
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
transition: top 0.15s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#alert.show {
|
||||||
|
top: 6%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dialogTitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dialogBtns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0.6em;
|
||||||
|
}
|
@ -14,14 +14,14 @@ if not exist ".\temp" mkdir ".\temp"
|
|||||||
echo Downloading Grasscutter prebuilt jar...
|
echo Downloading Grasscutter prebuilt jar...
|
||||||
|
|
||||||
:: Download the jar
|
:: Download the jar
|
||||||
powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip"
|
powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile ".\temp\gcjar.zip"
|
||||||
|
|
||||||
echo Extracting...
|
echo Extracting...
|
||||||
|
|
||||||
:: Delete old file if there is one there
|
:: Delete old file if there is one there
|
||||||
if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar"
|
if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar"
|
||||||
|
|
||||||
powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force
|
powershell Expand-Archive -Path ".\temp\gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force
|
||||||
|
|
||||||
:: Find the jar file name and rename it, just in case
|
:: Find the jar file name and rename it, just in case
|
||||||
for %%i in (%FOLDER_NAME%/*) do (
|
for %%i in (%FOLDER_NAME%/*) do (
|
||||||
@ -32,7 +32,7 @@ for %%i in (%FOLDER_NAME%/*) do (
|
|||||||
echo Downloading keystore.p12...
|
echo Downloading keystore.p12...
|
||||||
|
|
||||||
:: Download the keystore.p12 file
|
:: Download the keystore.p12 file
|
||||||
powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12"
|
powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile ".\%FOLDER_NAME%\keystore.p12"
|
||||||
|
|
||||||
:: Check java version, this will automatically output some tuff
|
:: Check java version, this will automatically output some tuff
|
||||||
call .\scripts\javaver.cmd %BRANCH%
|
call .\scripts\javaver.cmd %BRANCH%
|
||||||
|
@ -14,19 +14,19 @@ if not exist "%ORIGIN%/ext" mkdir "%ORIGIN%/ext"
|
|||||||
if not exist "%ORIGIN%/temp" mkdir "%ORIGIN%/temp
|
if not exist "%ORIGIN%/temp" mkdir "%ORIGIN%/temp
|
||||||
|
|
||||||
:: Begin by retrieving mitmproxy 7.0.4
|
:: Begin by retrieving mitmproxy 7.0.4
|
||||||
powershell Invoke-WebRequest -Uri https://snapshots.mitmproxy.org/7.0.4/mitmproxy-7.0.4-windows.zip -OutFile "'%ORIGIN%/temp/mitmproxy-7.0.4-windows.zip'"
|
powershell Invoke-WebRequest -Uri https://snapshots.mitmproxy.org/7.0.4/mitmproxy-7.0.4-windows.zip -OutFile "'%ORIGIN%\temp\mitmproxy-7.0.4-windows.zip'"
|
||||||
|
|
||||||
echo Extracting...
|
echo Extracting...
|
||||||
|
|
||||||
:: Extract from temp/ to ext/ with powershell
|
:: Extract from temp/ to ext/ with powershell
|
||||||
powershell Expand-Archive -Path "'%ORIGIN%/temp/mitmproxy-7.0.4-windows.zip'" -DestinationPath "'%ORIGIN%/ext/'" -Force
|
powershell Expand-Archive -Path "'%ORIGIN%\temp\mitmproxy-7.0.4-windows.zip'" -DestinationPath "'%ORIGIN%\ext\'" -Force
|
||||||
|
|
||||||
del /s /q "%ORIGIN%/temp"
|
del /s /q "%ORIGIN%/temp"
|
||||||
|
|
||||||
echo Running proxy server in order to generate certificates...
|
echo Running proxy server in order to generate certificates...
|
||||||
|
|
||||||
:: Start proxy server
|
:: Start proxy server
|
||||||
start "Proxy Server" "%ORIGIN%/ext/mitmdump.exe" --ssl-insecure --set ip=%ip%
|
start "Proxy Server" "%ORIGIN%\ext\mitmdump.exe" --ssl-insecure --set ip=%ip%
|
||||||
|
|
||||||
:: Allow the proxy server to create the certificates
|
:: Allow the proxy server to create the certificates
|
||||||
ping 127.0.0.1 -n 6 > nul
|
ping 127.0.0.1 -n 6 > nul
|
||||||
@ -51,3 +51,4 @@ echo Done! You can now open GrassClipper.exe!
|
|||||||
pause
|
pause
|
||||||
|
|
||||||
taskkill /f /fi "WINDOWTITLE eq Grassclipper Installer"
|
taskkill /f /fi "WINDOWTITLE eq Grassclipper Installer"
|
||||||
|
taskkill /f /fi "WINDOWTITLE eq Administrator: Grassclipper Installer"
|
@ -9,14 +9,7 @@ if %errorlevel%==1 (
|
|||||||
echo =======================================================================================
|
echo =======================================================================================
|
||||||
echo No version of Java was found!
|
echo No version of Java was found!
|
||||||
|
|
||||||
if %BRANCH% EQU stable (
|
echo To launch the server, you must install Java 17
|
||||||
echo To launch the stable branch server, you must install Java 8
|
|
||||||
)
|
|
||||||
|
|
||||||
if %BRANCH% EQU development (
|
|
||||||
echo To launch the development branch server, you must install Java 17
|
|
||||||
)
|
|
||||||
|
|
||||||
echo =======================================================================================
|
echo =======================================================================================
|
||||||
|
|
||||||
exit /b
|
exit /b
|
||||||
@ -35,36 +28,13 @@ for /f "delims=. tokens=1-3" %%v in ("%JAVAVER%") do (
|
|||||||
set BUILD=%%x
|
set BUILD=%%x
|
||||||
)
|
)
|
||||||
|
|
||||||
if %BRANCH% EQU stable (
|
:: Ensure java 17
|
||||||
:: Ensure java 8
|
if "%MAJOR%" NEQ "17" (
|
||||||
if %MAJOR% EQU 1 (
|
echo =======================================================================================
|
||||||
if %MINOR% LSS 8 (
|
echo !! Java version is not 17 !!
|
||||||
echo =======================================================================================
|
echo Please download Java 17 or later to ensure %BRANCH% branch server launches correctly.
|
||||||
echo !! Java version is less than 8 !!
|
echo =======================================================================================
|
||||||
echo Please download Java 8 to ensure %BRANCH% branch server launches correctly.
|
exit /b
|
||||||
echo =======================================================================================
|
|
||||||
exit /b
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if %MAJOR% NEQ 1 (
|
|
||||||
echo =======================================================================================
|
|
||||||
echo !! Java version is not 8 !!
|
|
||||||
echo Please download Java 8 to ensure %BRANCH% branch server launches correctly.
|
|
||||||
echo =======================================================================================
|
|
||||||
exit /b
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if %BRANCH% EQU development (
|
|
||||||
:: Ensure java 17
|
|
||||||
if %MAJOR% LSS 17 (
|
|
||||||
echo =======================================================================================
|
|
||||||
echo !! Java version is less than 17 !!
|
|
||||||
echo Please download Java 17 to ensure %BRANCH% branch server launches correctly.
|
|
||||||
echo =======================================================================================
|
|
||||||
exit /b
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
echo Java version is compatible
|
echo Java version is compatible
|
@ -22,6 +22,9 @@ if "%PROXY_IP%" EQU "localhost" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
:loop
|
:loop
|
||||||
|
:: Wait a couple seconds
|
||||||
|
ping 127.0.0.1 -n 2 > nul
|
||||||
|
|
||||||
:: Check if the game is even running
|
:: Check if the game is even running
|
||||||
:: tasklist /fi "ImageName eq %GAME_EXE_NAME%" /fo csv 2>NUL | find /I "%GAME_EXE_NAME%.exe">NUL
|
:: tasklist /fi "ImageName eq %GAME_EXE_NAME%" /fo csv 2>NUL | find /I "%GAME_EXE_NAME%.exe">NUL
|
||||||
:: IF %ERRORLEVEL% NEQ 0 (
|
:: IF %ERRORLEVEL% NEQ 0 (
|
||||||
@ -32,6 +35,7 @@ if "%PROXY_IP%" EQU "localhost" (
|
|||||||
:: https://stackoverflow.com/questions/162291/how-to-check-if-a-process-is-running-via-a-batch-script
|
:: https://stackoverflow.com/questions/162291/how-to-check-if-a-process-is-running-via-a-batch-script
|
||||||
tasklist /fi "ImageName eq mitmdump.exe" /fo csv 2>NUL | find /I "mitmdump.exe">NUL
|
tasklist /fi "ImageName eq mitmdump.exe" /fo csv 2>NUL | find /I "mitmdump.exe">NUL
|
||||||
if "%ERRORLEVEL%" NEQ "0" (
|
if "%ERRORLEVEL%" NEQ "0" (
|
||||||
|
echo "mitmdump not running"
|
||||||
goto killgame
|
goto killgame
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,8 +66,6 @@ if "%PROXY_IP%" EQU "localhost" (
|
|||||||
goto killgame
|
goto killgame
|
||||||
)
|
)
|
||||||
|
|
||||||
ping 127.0.0.1 -n 2 > nul
|
|
||||||
|
|
||||||
goto loop
|
goto loop
|
||||||
|
|
||||||
:killgame
|
:killgame
|
||||||
|
@ -26,4 +26,4 @@ echo Starting local Grasscutter server...
|
|||||||
:: Change dir to server directory
|
:: Change dir to server directory
|
||||||
cd /d "%GRASSCUTTER_ROOT%"
|
cd /d "%GRASSCUTTER_ROOT%"
|
||||||
|
|
||||||
call java -jar %GRASSCUTTER_JAR%
|
call java -jar "%GRASSCUTTER_JAR%"
|
@ -9,6 +9,9 @@
|
|||||||
:: Use to force task kill
|
:: Use to force task kill
|
||||||
title PS Launcher Script
|
title PS Launcher Script
|
||||||
|
|
||||||
|
:: Use a character encoding that allows for use of Chinese characters. This should work but doesn't, but I'm keeping it in here just in case
|
||||||
|
chcp 65001
|
||||||
|
|
||||||
echo Starting Proxy Server
|
echo Starting Proxy Server
|
||||||
|
|
||||||
set IP=%1
|
set IP=%1
|
||||||
@ -41,7 +44,7 @@ reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v Pr
|
|||||||
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /d "127.0.0.1:8080" /f >nul 2>nul
|
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /d "127.0.0.1:8080" /f >nul 2>nul
|
||||||
|
|
||||||
:: Start proxy server
|
:: Start proxy server
|
||||||
start "Proxy Server" "%ORIGIN%\ext\mitmdump.exe" -s "%ORIGIN%/proxy/proxy.py" -k --allow-hosts ".*\.yuanshen\.com|.*\.mihoyo\.com|.*\.hoyoverse\.com" --ssl-insecure --set ip=%IP% --set port=%PORT% --set use_https=%USE_HTTPS%
|
start "Proxy Server" "%ORIGIN%\ext\mitmdump.exe" -s "%ORIGIN%\proxy\proxy.py" -k --allow-hosts ".*\.yuanshen\.com|.*\.mihoyo\.com|.*\.hoyoverse\.com" --ssl-insecure --set ip=%IP% --set port=%PORT% --set use_https=%USE_HTTPS%
|
||||||
|
|
||||||
echo Opening %GAME_PATH%
|
echo Opening %GAME_PATH%
|
||||||
|
|
||||||
@ -57,7 +60,7 @@ echo Killswitch: %ENABLE_KILLSWITCH%
|
|||||||
if "%ENABLE_KILLSWITCH%" EQU "true" (
|
if "%ENABLE_KILLSWITCH%" EQU "true" (
|
||||||
echo Killswitch is enabled!
|
echo Killswitch is enabled!
|
||||||
:: Start killswitch
|
:: Start killswitch
|
||||||
start /b %ORIGIN%\scripts\killswitch.cmd "%GAME_EXE%" %IP%
|
start /b %ORIGIN%\scripts\killswitch.cmd "%GAME_EXE%" 127.0.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
:: Launch game
|
:: Launch game
|
||||||
|
@ -4,22 +4,22 @@ set FOLDER_NAME=%1
|
|||||||
set FOLDER_NAME=%FOLDER_NAME:"=%
|
set FOLDER_NAME=%FOLDER_NAME:"=%
|
||||||
|
|
||||||
if not exist ".\temp" mkdir ".\temp"
|
if not exist ".\temp" mkdir ".\temp"
|
||||||
if not exist ".\resources" mkdir ".\resources"
|
if not exist "%FOLDER_NAME%\resources" mkdir "%FOLDER_NAME%\resources"
|
||||||
|
|
||||||
echo Downloading resources, this can take a while...
|
echo Downloading resources, this can take a while...
|
||||||
|
|
||||||
:: Grab the giant ass resource zip
|
:: Grab the giant ass resource zip
|
||||||
powershell Invoke-WebRequest -Uri https://github.com/Koko-boya/Grasscutter_Resources/archive/refs/heads/main.zip -OutFile "./temp/resources.zip"
|
powershell Invoke-WebRequest -Uri https://github.com/Koko-boya/Grasscutter_Resources/archive/refs/heads/main.zip -OutFile ".\temp\resources.zip"
|
||||||
|
|
||||||
echo Extracting...
|
echo Extracting...
|
||||||
|
|
||||||
:: Extract resources to the folder
|
:: Extract resources to the folder
|
||||||
powershell Expand-Archive -Path "./temp/resources.zip" -DestinationPath "%FOLDER_NAME%" -Force
|
powershell Expand-Archive -Path ".\temp\resources.zip" -DestinationPath "%FOLDER_NAME%" -Force
|
||||||
|
|
||||||
:: Delete old resources folder if there is one there
|
:: Delete old resources folder if there is one there
|
||||||
del /s /q "%FOLDER_NAME%\resources">nul
|
del /s /q "%FOLDER_NAME%\resources">nul
|
||||||
|
|
||||||
echo Moving resources to folder...
|
echo Moving resources to folder (this also takes a bit)...
|
||||||
|
|
||||||
robocopy "%FOLDER_NAME%\Grasscutter_Resources-main\Resources" "%FOLDER_NAME%\resources" /E /MOVE>nul
|
robocopy "%FOLDER_NAME%\Grasscutter_Resources-main\Resources" "%FOLDER_NAME%\resources" /E /MOVE>nul
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
set BINARY_URL="https://github.com/SpikeHD/neutralinojs/releases/download/v1337.0.0/neutralino-win_x64.exe"
|
set BINARY_URL="https://github.com/SpikeHD/neutralinojs/releases/download/v1337.0.0/neutralino-win_x64.exe"
|
||||||
|
|
||||||
call npm install
|
call npm install
|
||||||
|
call neu update
|
||||||
|
|
||||||
:: Use powershell to download the binary
|
:: Use powershell to download the binary
|
||||||
powershell Invoke-WebRequest -Uri %BINARY_URL% -OutFile "./bin/neutralino-win_x64.exe"
|
powershell Invoke-WebRequest -Uri %BINARY_URL% -OutFile "./bin/neutralino-win_x64.exe"
|
Loading…
x
Reference in New Issue
Block a user