From f4fd4c2dce50ac7e999afb74dcad5b97b1686992 Mon Sep 17 00:00:00 2001 From: labalityowo <56186498+labalityowo@users.noreply.github.com> Date: Sat, 23 Apr 2022 12:49:55 +0700 Subject: [PATCH 001/248] Vietnamese --- vie.json | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 vie.json diff --git a/vie.json b/vie.json new file mode 100644 index 0000000..3a618fd --- /dev/null +++ b/vie.json @@ -0,0 +1,40 @@ +{ + "fullLangName": "Vietnamese", + "appName": "GrassClipper", + + "playOfficial": "Máy chủ chính thức", + "playPrivate": "Máy chủ riêng tư", + "launchLocalServer": "Khởi động máy chủ local", + + "genshinFolderSet": "Chỉnh địa điểm thư mục \"Genshin Impact Game\"", + "grasscutterFileSet": "Chỉnh địa điểm file \"GrassCutter\"", + "folderNotSet": "Chưa chỉnh file", + + "ipPlaceholder": "IP Address", + "noFavorites": "Không có máy chủ yêu thích", + + "settingsTitle": "Cài đặt", + "scriptsSectionTitle": "Scripts", + "killswitchOption": "Công tắc đóng", + "killswitchSubtitle": "Dành cho những ai sợ bị ban. Tắt game *và mạng* nếu proxy có vấn đề.", + "proxyOption": "Proxy", + "proxySubtitle": "Tải proxy", + "updateOption": "Cập nhật", + "updateSubtitle": "Tạm thời bị. Check GitHub for the newest releease.", + "languageOption": "Ngôn ngữ", + "languageSubtitle": "Chọn ngôn ngữ", + + "enableServerLauncherOption": "Bật máy chủ local", + "enableServerLauncherSubtitle": "Enable to server launcher tile for launcher a local Grasscutter instance.", + + "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! :)", + "introSen3": "Bạn có muốn tải proxy không?", + "introSen4": "(dùng để vào máy chủ riêng)", + + "proxyInstallBtn": "Có", + "proxyInstallDeny": "Không", + + "genshinFolderDialog": "Chọn thư mục có chứa game", + "grasscutterFileDialog": "Chọn file Grasscutter" + } \ No newline at end of file From a807af18abaa96f08570ab5cfe56ab36d04ed168 Mon Sep 17 00:00:00 2001 From: labalityowo <56186498+labalityowo@users.noreply.github.com> Date: Sat, 23 Apr 2022 12:55:34 +0700 Subject: [PATCH 002/248] Delete vie.json --- vie.json | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 vie.json diff --git a/vie.json b/vie.json deleted file mode 100644 index 3a618fd..0000000 --- a/vie.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "fullLangName": "Vietnamese", - "appName": "GrassClipper", - - "playOfficial": "Máy chủ chính thức", - "playPrivate": "Máy chủ riêng tư", - "launchLocalServer": "Khởi động máy chủ local", - - "genshinFolderSet": "Chỉnh địa điểm thư mục \"Genshin Impact Game\"", - "grasscutterFileSet": "Chỉnh địa điểm file \"GrassCutter\"", - "folderNotSet": "Chưa chỉnh file", - - "ipPlaceholder": "IP Address", - "noFavorites": "Không có máy chủ yêu thích", - - "settingsTitle": "Cài đặt", - "scriptsSectionTitle": "Scripts", - "killswitchOption": "Công tắc đóng", - "killswitchSubtitle": "Dành cho những ai sợ bị ban. Tắt game *và mạng* nếu proxy có vấn đề.", - "proxyOption": "Proxy", - "proxySubtitle": "Tải proxy", - "updateOption": "Cập nhật", - "updateSubtitle": "Tạm thời bị. Check GitHub for the newest releease.", - "languageOption": "Ngôn ngữ", - "languageSubtitle": "Chọn ngôn ngữ", - - "enableServerLauncherOption": "Bật máy chủ local", - "enableServerLauncherSubtitle": "Enable to server launcher tile for launcher a local Grasscutter instance.", - - "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! :)", - "introSen3": "Bạn có muốn tải proxy không?", - "introSen4": "(dùng để vào máy chủ riêng)", - - "proxyInstallBtn": "Có", - "proxyInstallDeny": "Không", - - "genshinFolderDialog": "Chọn thư mục có chứa game", - "grasscutterFileDialog": "Chọn file Grasscutter" - } \ No newline at end of file From 754bd33462e8caf7278127ae6bb6c9a8e3d99966 Mon Sep 17 00:00:00 2001 From: labalityowo <56186498+labalityowo@users.noreply.github.com> Date: Sat, 23 Apr 2022 12:56:08 +0700 Subject: [PATCH 003/248] Add files via upload --- languages/vie.json | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 languages/vie.json diff --git a/languages/vie.json b/languages/vie.json new file mode 100644 index 0000000..d9c6cca --- /dev/null +++ b/languages/vie.json @@ -0,0 +1,40 @@ +{ + "fullLangName": "Vietnamese", + "appName": "GrassClipper", + + "playOfficial": "Máy chủ chính thức", + "playPrivate": "Máy chủ riêng tư", + "launchLocalServer": "Khởi động Grasscutter", + + "genshinFolderSet": "Chỉnh địa điểm thư mục \"Genshin Impact Game\"", + "grasscutterFileSet": "Chỉnh địa điểm file \"GrassCutter\"", + "folderNotSet": "Chưa chỉnh file", + + "ipPlaceholder": "Địa chỉ IP", + "noFavorites": "Không có máy chủ yêu thích", + + "settingsTitle": "Cài đặt", + "scriptsSectionTitle": "Scripts", + "killswitchOption": "Công tắc đóng", + "killswitchSubtitle": "Dành cho những ai sợ bị ban. Tắt game *và mạng* nếu proxy có vấn đề.", + "proxyOption": "Proxy", + "proxySubtitle": "Tải proxy", + "updateOption": "Cập nhật", + "updateSubtitle": "Tạm thời chưa dùng được. Kiểm tra Github để có bản cập nhật mới", + "languageOption": "Ngôn ngữ", + "languageSubtitle": "Chọn ngôn ngữ", + + "enableServerLauncherOption": "Grasscutter", + "enableServerLauncherSubtitle": "Thêm lựa chọn bật grasscutter", + + "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! :)", + "introSen3": "Bạn có muốn tải proxy không?", + "introSen4": "(dùng để vào máy chủ riêng)", + + "proxyInstallBtn": "Có", + "proxyInstallDeny": "Không", + + "genshinFolderDialog": "Chọn thư mục có chứa game", + "grasscutterFileDialog": "Chọn file Grasscutter" + } \ No newline at end of file From 1dd49ae9c8b65f07b5846097089508acf538c95d Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:08:10 -0700 Subject: [PATCH 004/248] rollback to mitmdump 7.0.4 --- scripts/install.cmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/install.cmd b/scripts/install.cmd index 0e29eca..df02932 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -17,13 +17,13 @@ cd "%ORIGIN%" if not exist "%ORIGIN%/ext" mkdir "%ORIGIN%/ext" if not exist "%ORIGIN%/temp" mkdir "%ORIGIN%/temp" -:: Begin by retrieving mitmproxy 8.0.0 -powershell Invoke-WebRequest -Uri https://snapshots.mitmproxy.org/8.0.0/mitmproxy-8.0.0-windows.zip -OutFile "%ORIGIN%/temp/mitmproxy-8.0.0-windows.zip" +:: 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" echo Extracting... :: Extract from temp/ to ext/ with powershell -powershell Expand-Archive -Path "%ORIGIN%/temp/mitmproxy-8.0.0-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" From e31e33e790afa92e46695597b0ad6c3f54436173 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:10:25 -0700 Subject: [PATCH 005/248] fix version display --- resources/js/translation.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/js/translation.js b/resources/js/translation.js index 1d24191..06a3617 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -20,6 +20,12 @@ async function doTranslation() { // Begin filling in values set('titleSection', localeObj.appName) + const verSpan = document.createElement('span') + verSpan.id = 'version' + verSpan.innerHTML = ` v${NL_APPVERSION}` + + document.querySelector('#titleSection').appendChild(verSpan) + // Play buttons set('playOfficial', localeObj.playOfficial) set('playPrivate', localeObj.playPrivate) From d56bdd6037ae3fe38b2b48f10ddd8e81e6b7e739 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:10:40 -0700 Subject: [PATCH 006/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 31387d0..7cc6406 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.0", + "version": "0.6.1", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 2d31a3d..2a5aa5e 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.0", + "version": "0.6.1", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index a92cf81..c9a1824 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "GrassClipper", - "version": "0.6.0", + "version": "0.6.1", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From db38c66eaba26630bb6826383fc3da12399602ee Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:20:52 -0700 Subject: [PATCH 007/248] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9bb046c..1a7a09e 100644 --- a/README.md +++ b/README.md @@ -71,5 +71,6 @@ The launcher most likely did not close correctly, and was unable to clean your p ![image](https://user-images.githubusercontent.com/25207995/164393024-56543ddf-7063-4c04-9a9f-0c6238f30e90.png) ![image](https://user-images.githubusercontent.com/25207995/164393118-de844e75-f9a2-491a-aea6-f2d563abecc7.png) ![image](https://user-images.githubusercontent.com/25207995/164574339-50bbda5e-e25a-47c3-ae14-2b0b0b4ca92c.png) +![image](https://user-images.githubusercontent.com/25207995/164882716-c9f16cd0-c0b6-4c0a-ae9e-4c95da9ef7f5.png) From 79f28ccb2a3f78293d43739594f015f9e01e80ac Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:21:30 -0700 Subject: [PATCH 008/248] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a7a09e..812a4b9 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ The launcher most likely did not close correctly, and was unable to clean your p ![image](https://user-images.githubusercontent.com/25207995/164393040-4da72f29-6d59-4af4-bd60-072269f2ba2a.png) ![image](https://user-images.githubusercontent.com/25207995/164393024-56543ddf-7063-4c04-9a9f-0c6238f30e90.png) ![image](https://user-images.githubusercontent.com/25207995/164393118-de844e75-f9a2-491a-aea6-f2d563abecc7.png) -![image](https://user-images.githubusercontent.com/25207995/164574339-50bbda5e-e25a-47c3-ae14-2b0b0b4ca92c.png) +![image](https://user-images.githubusercontent.com/25207995/164882735-77aa535c-0e93-4b32-af7c-f8b59888257a.png) ![image](https://user-images.githubusercontent.com/25207995/164882716-c9f16cd0-c0b6-4c0a-ae9e-4c95da9ef7f5.png) From 7c84540dc39454d0685788c751f2079b238316a8 Mon Sep 17 00:00:00 2001 From: nuoxian <56551535+nuoxianCN@users.noreply.github.com> Date: Sat, 23 Apr 2022 14:26:00 +0800 Subject: [PATCH 009/248] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=AD=E6=96=87zh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- languages/zh.json | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 languages/zh.json diff --git a/languages/zh.json b/languages/zh.json new file mode 100644 index 0000000..cd0fedf --- /dev/null +++ b/languages/zh.json @@ -0,0 +1,39 @@ +{ + "fullLangName": "Chinese", + "appName": "割草机启动器", + + "playOfficial": "启动官方服务器", + "playPrivate": "启动私人服务器", + "launchLocalServer": "启动本地服务器", + + "genshinFolderSet": "设置 \"Genshin Impact Game\" 文件夹", + "grasscutterFileSet": "设置 \"GrassCutter\" .jar 文件", + "folderNotSet": "没有设置启动文件夹或文件", + + "ipPlaceholder": "IP地址", + "noFavorites": "没有收藏", + + "settingsTitle": "设置", + "scriptsSectionTitle": "进程", + "killswitchOption": "杀死服务进程", + "killswitchSubtitle": "如果IE代理发生了一些错误,启用此选项可以杀死服务进程和你的网络连接。", + "proxyOption": "代理", + "proxySubtitle": "通过安装脚本安装代理服务器。", + "updateOption": "更新", + "updateSubtitle": "自动更新暂时不可用。查看GitHub以获取最新的Release。", + "languageOption": "语言", + "languageSubtitle": "选择你最熟悉的语言!", + "enableServerLauncherOption": "启用本地服务器", + "enableServerLauncherSubtitle": "启动器内为你显示启动本地服务器选项。", + + "introSen1": "看来这是你第一次使用割草机启动器!", + "introSen2": "首先,欢迎你使用割草机启动器,其次很高兴在这里见到你! :)", + "introSen3": "是否要运行代理安装程序?", + "introSen4": "(需要连接到专用服务器)", + + "proxyInstallBtn": "安装", + "proxyInstallDeny": "不用了,谢谢", + + "genshinFolderDialog": "选择Genshin Impact Game文件夹", + "grasscutterFileDialog": "选择GrassCutter服务器jar文件" +} \ No newline at end of file From 3b3c3f635a0a04d3bcde9d4429b08c311f3d1276 Mon Sep 17 00:00:00 2001 From: Ana Eunha <66442365+actuallyeunha@users.noreply.github.com> Date: Sat, 23 Apr 2022 03:38:30 -0300 Subject: [PATCH 010/248] Add "Portugues Brasileiro" language --- languages/pt-br.json | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 languages/pt-br.json diff --git a/languages/pt-br.json b/languages/pt-br.json new file mode 100644 index 0000000..5a16707 --- /dev/null +++ b/languages/pt-br.json @@ -0,0 +1,39 @@ +{ + "fullLangName": "Portugues Brasileiro", + "appName": "GrassClipper", + + "playOfficial": "Jogar (Oficial)", + "playPrivate": "Jogar (Privado)", + "launchLocalServer": "Abrir Servidor Local", + + "genshinFolderSet": "Definir a pasta: \"Genshin Impact Game\" ", + "grasscutterFileSet": "Definir o arquivo .jar de \"GrassCutter\" ", + "folderNotSet": "Não Definida", + + "ipPlaceholder": "Endereço Ip", + "noFavorites": "Nenhum favorito definido", + + "settingsTitle": "Configurações", + "scriptsSectionTitle": "Scripts", + "killswitchOption": "Kill Switch", + "killswitchSubtitle": "Apenas para aqueles paranoicos sobre banimentos. Finaliza o processo do jogo *e a sua internet* se algo acontecer com o proxy", + "proxyOption": "Proxy", + "proxySubtitle": "Instalar o servidor proxy a partir do script instalador", + "updateOption": "Atualizar", + "updateSubtitle": "A atualização automática esta temporariamente desativada. Cheque o Github para a versão mais atualizada", + "languageOption": "Idioma", + "languageSubtitle": "Selecione seu idioma!", + "enableServerLauncherOption": "Permitir ao launcher ligar o servidor", + "enableServerLauncherSubtitle": "Permitir ao launcher iniciar uma instancia local do GrassCutter", + + "introSen1": "Parece que essa é a sua primeira vez usando o GrassClipper!", + "introSen2": "Primeiramente, bem-vindo, estou feliz de te ver aqui! :)", + "introSen3": "Você gostaria de instalar o proxy?", + "introSen4": "(necessário para conectar a servidores privados)", + + "proxyInstallBtn": "Instalar", + "proxyInstallDeny": "Não obrigado", + + "genshinFolderDialog": "Selecione a pasta Genshin Impact Game", + "grasscutterFileDialog": "Selecione o arquivo jar do GrassCutter" +} \ No newline at end of file From 0fc48e8302bdabd9e692acca94e1126ad8f68dd3 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:43:41 -0700 Subject: [PATCH 011/248] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 812a4b9..490cc33 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Grasscutter launcher for easily switching between Official and Private servers * [White Screen Fix](#white-screen-fix) * [Broken Discord/Youtube](#my-discord-is-not-letting-me-send-messages-or-load-images-my-youtube-is-acting-strange) * [No internet](#i-have-no-internet-after-closing-everything-restarting-my-pc) +* [Translation Credits](#translation-credits) * [Screenshots](#screenshots) # Setup (for Users) @@ -63,6 +64,13 @@ Discord/YouTube (plus surely some others) does not seem to be a fan of the proxy The launcher most likely did not close correctly, and was unable to clean your proxy settings back to what they were. Disable your proxy in the Windows proxy settings. +# Translation Credits + +Thank you to everyone who has provided translations! + +* ZH - nuoxianCN +* PT-BR - na.na + # Screenshots ![image](https://user-images.githubusercontent.com/25207995/164574276-645548c2-7ba6-47c3-8df4-77082003648f.png) From e4d70f4e021da234490acff1d31d45449f4e1f99 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:45:43 -0700 Subject: [PATCH 012/248] fix languages list --- resources/js/index.js | 4 ++++ scripts/local_server_launch.cmd | 3 +++ 2 files changed, 7 insertions(+) diff --git a/resources/js/index.js b/resources/js/index.js index 290a957..128377b 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -499,6 +499,10 @@ async function getLanguages() { const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) const config = await getCfg() + // Clear language options + const languageSelect = document.querySelector('#languageSelect') + languageSelect.innerHTML = '' + // Load all languages as options for (const file of languageFiles) { const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName diff --git a/scripts/local_server_launch.cmd b/scripts/local_server_launch.cmd index d411daa..c775e0d 100644 --- a/scripts/local_server_launch.cmd +++ b/scripts/local_server_launch.cmd @@ -11,4 +11,7 @@ set GRASSCUTTER_JAR=%GRASSCUTTER_JAR:"=% echo Starting local Grasscutter server... +:: Change dir to server directory + + start /b java -jar %GRASSCUTTER_JAR% \ No newline at end of file From 476eb70ae0f931a24221d3eed44104e3aa4bc1f7 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:48:15 -0700 Subject: [PATCH 013/248] set ip placeholder properly --- resources/js/translation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/translation.js b/resources/js/translation.js index 06a3617..80644f9 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -36,7 +36,7 @@ async function doTranslation() { set('grasscutterFileSet', localeObj.grasscutterFileSet) // Private options - set('ip', localeObj.ipPlaceholder) + document.querySelector('#ip').placeholder = localeObj.ipPlaceholder // Settings set('fullSettingsTitle', localeObj.settingsTitle) From df0a0aa494cc0690cdb76567e38e7207c386861e Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:51:48 -0700 Subject: [PATCH 014/248] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 490cc33..de7e912 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Grasscutter launcher for easily switching between Official and Private servers * [White Screen Fix](#white-screen-fix) * [Broken Discord/Youtube](#my-discord-is-not-letting-me-send-messages-or-load-images-my-youtube-is-acting-strange) * [No internet](#i-have-no-internet-after-closing-everything-restarting-my-pc) -* [Translation Credits](#translation-credits) +* [Languages and Translation Credits](#available-languages-and-translation-credits) * [Screenshots](#screenshots) # Setup (for Users) @@ -64,9 +64,9 @@ Discord/YouTube (plus surely some others) does not seem to be a fan of the proxy The launcher most likely did not close correctly, and was unable to clean your proxy settings back to what they were. Disable your proxy in the Windows proxy settings. -# Translation Credits +# Available Languages and Translation Credits -Thank you to everyone who has provided translations! +Thank you to everyone who has provided translations! <3 * ZH - nuoxianCN * PT-BR - na.na From c7e73778ca8c04eb8a3d67a95079ea6bc37e10ff Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Fri, 22 Apr 2022 23:57:43 -0700 Subject: [PATCH 015/248] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index de7e912..fac518d 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Thank you to everyone who has provided translations! <3 * ZH - nuoxianCN * PT-BR - na.na +* Vietnamese - labalityowo # Screenshots From dfc351aa6a020e08124ccf14c89901512441021a Mon Sep 17 00:00:00 2001 From: Iqrar Agalosi Nureyza Date: Sat, 23 Apr 2022 14:03:27 +0700 Subject: [PATCH 016/248] Add Bahasa Indonesia localization --- languages/id.json | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 languages/id.json diff --git a/languages/id.json b/languages/id.json new file mode 100644 index 0000000..d8ca49c --- /dev/null +++ b/languages/id.json @@ -0,0 +1,39 @@ +{ + "fullLangName": "Bahasa Indonesia", + "appName": "GrassClipper", + + "playOfficial": "Mainkan Official", + "playPrivate": "Mainkan Private", + "launchLocalServer": "Luncurkan Local Server", + + "genshinFolderSet": "Atur folder \"Genshin Impact Game\"", + "grasscutterFileSet": "Atur file \"GrassCutter\" .jar", + "folderNotSet": "Belum diatur", + + "ipPlaceholder": "Alamat IP", + "noFavorites": "Tidak ada favorite yang diatur", + + "settingsTitle": "Pengaturan", + "scriptsSectionTitle": "Scripts", + "killswitchOption": "Matikan Switch", + "killswitchSubtitle": "Untuk kamu yang paranoid terhadap ban. Matikan proses game *dan internetmu* apabila sesuatu terjadi pada proxy nya.", + "proxyOption": "Proxy", + "proxySubtitle": "Install proxy server melalui install script", + "updateOption": "Update", + "updateSubtitle": "Update otomatis dinonaktifkan untuk sementara. Cek GitHub untuk rilis terbaru.", + "languageOption": "Bahasa", + "languageSubtitle": "Pilih bahasamu!", + "enableServerLauncherOption": "Nyalakan Server Launcher", + "enableServerLauncherSubtitle": "Nyalakan tile server launcher untuk meluncurkan instance Grasscutter secara lokal.", + + "introSen1": "Sepertinya ini pertama kalinya kamu menggunakan GrassClipper!", + "introSen2": "Pertama-tama, selamat datang, senang bertemu denganmu! :)", + "introSen3": "Apa kamu ingin menjalankan installer proxy?", + "introSen4": "(diperlukan untuk terhubung dengan private servers)", + + "proxyInstallBtn": "Install", + "proxyInstallDeny": "Tidak terima kasih", + + "genshinFolderDialog": "Pilih folder Genshin Impact Game", + "grasscutterFileDialog": "Pilih file jar server GrassCutter" + } \ No newline at end of file From dfac36137caf85d094ebace19ee3666a5afc8833 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 00:09:50 -0700 Subject: [PATCH 017/248] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fac518d..1b2c29c 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,8 @@ Thank you to everyone who has provided translations! <3 * ZH - nuoxianCN * PT-BR - na.na -* Vietnamese - labalityowo +* VIE - labalityowo +* ID - Iqrar99 # Screenshots From cbdfc745f0f868c2079d9f4f04d0991eecd51913 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 00:14:55 -0700 Subject: [PATCH 018/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 7cc6406..f8547f3 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.1", + "version": "0.6.2", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 2a5aa5e..fc1491c 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.1", + "version": "0.6.2", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index c9a1824..bece276 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "GrassClipper", - "version": "0.6.1", + "version": "0.6.2", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 896ca2f912f8b85004b9b172477dc3a8c5a1f781 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 00:32:54 -0700 Subject: [PATCH 019/248] Fix server launcher --- scripts/local_server_launch.cmd | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/local_server_launch.cmd b/scripts/local_server_launch.cmd index c775e0d..2df8358 100644 --- a/scripts/local_server_launch.cmd +++ b/scripts/local_server_launch.cmd @@ -3,6 +3,16 @@ set GRASSCUTTER_JAR=%1 set GRASSCUTTER_JAR=%GRASSCUTTER_JAR:"=% +:: Get folder the jar is in +set "X=%GRASSCUTTER_JAR%" +:l +if "%X:~-1%"=="\" goto al +set "X=%X:~0,-1%" +goto l +:al +set "X=%X:~0,-1%" +set "GRASSCUTTER_ROOT=%X%" + :: Ensure admin >nul 2>&1 reg query "HKU\S-1-5-19" || ( set params = %*:"="""% @@ -12,6 +22,6 @@ set GRASSCUTTER_JAR=%GRASSCUTTER_JAR:"=% echo Starting local Grasscutter server... :: Change dir to server directory - +cd /d "%GRASSCUTTER_ROOT%" start /b java -jar %GRASSCUTTER_JAR% \ No newline at end of file From 3b89776d9ecd574daf20a98369b0bcf4d26f0185 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 00:34:19 -0700 Subject: [PATCH 020/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index f8547f3..f2da173 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.2", + "version": "0.6.3", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index fc1491c..0fd7add 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.2", + "version": "0.6.3", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index bece276..1743867 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "GrassClipper", - "version": "0.6.2", + "version": "0.6.3", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 0356b06ea0d1740431246f26388c45f0e0fb0972 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 01:10:39 -0700 Subject: [PATCH 021/248] Properly close scripts --- scripts/killswitch.cmd | 5 +++++ scripts/private_server_launch.cmd | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/scripts/killswitch.cmd b/scripts/killswitch.cmd index 0c8e8ec..9c1465f 100644 --- a/scripts/killswitch.cmd +++ b/scripts/killswitch.cmd @@ -5,6 +5,9 @@ set GAME_EXE_NAME=%GAME_EXE_NAME:"=% set PROXY_IP=%2 set PROXY_IP=%PROXY_IP:"=% +:: For task killing +title PS Killswitch + :: Get current wifi SSID to reconnect for /f "delims=: tokens=2" %%n in ('netsh wlan show interface name="Wi-Fi" ^| findstr "Profile"') do set "WIFI=%%n" set WIFI=%WIFI: =% @@ -84,4 +87,6 @@ if "%PROXY_IP%" EQU "localhost" ( :: Reconnect to the WiFi netsh wlan connect name="%WIFI%" + taskkill /f /fi "WINDOWTITLE eq Administrator: PS Killswitch" + exit \ No newline at end of file diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index a9ea591..1a15d66 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -6,6 +6,9 @@ cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 "%2" ""%cd%"" %4", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) ) +:: Use to force task kill +title PS Launcher Script + echo Starting Proxy Server set IP=%1 @@ -60,5 +63,10 @@ if "%PROXY%" == "" ( :: Kill proxy server taskkill /f /im mitmdump.exe + echo Done! See you next time! + + timeout /t 2 /nobreak >nul + taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" + exit /b ) \ No newline at end of file From 2dc1b6a0a30a24ac6e86373a73c39a6f25ff5523 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 01:12:28 -0700 Subject: [PATCH 022/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index f2da173..b589907 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.3", + "version": "0.6.4", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 0fd7add..15fd24d 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.3", + "version": "0.6.4", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 1743867..2612e1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "GrassClipper", - "version": "0.6.3", + "version": "0.6.4", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 3c85c6640f313d524851d371c1e845ec6685bd16 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 01:20:18 -0700 Subject: [PATCH 023/248] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1b2c29c..ba85856 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Grasscutter launcher for easily switching between Official and Private servers # TODO * Interface + * [ ] Integrated banner creator * [x] UI * [x] Official and Private options * [x] Server IP input From cb5cf0e755fe26dd17f7be4155b4efceead73d22 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 02:16:00 -0700 Subject: [PATCH 024/248] Add extra domains to proxy filter --- proxy/proxy.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/proxy/proxy.py b/proxy/proxy.py index 841e8fc..eae593f 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -63,7 +63,14 @@ class MlgmXyysd_Genshin_Impact_Proxy: "sdk-os-static.hoyoverse.com", "api-account-os.hoyoverse.com", "hk4e-sdk-os.hoyoverse.com", - "overseauspider.yuanshen.com" + "overseauspider.yuanshen.com", + "gameapi-account.mihoyo.com", + "minor-api.mihoyo.com", + "public-data-api.mihoyo.com", + "uspider.yuanshen.com", + "sdk-static.mihoyo.com", + "abtest-api-data-sg.hoyoverse.com", + "log-upload-os.hoyoverse.com" ] if flow.request.host in LIST_DOMAINS: From ddf357d3333467d4aab812e20c0c08b733bab84d Mon Sep 17 00:00:00 2001 From: Scirese <62688390+Scirese@users.noreply.github.com> Date: Sat, 23 Apr 2022 19:00:36 +0800 Subject: [PATCH 025/248] Fix some translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1 :I think "GrassClipper" is a proper noun,its inappropriate to translate it literally. 2:"Play(游玩)" is not "launch(启动)". 3:“Genshin Impact Game(原神)” is not translated. 4:"killswitchSubtitle" is completely wrong. 5:“set” here is preferably translated as "选择(select)" 6: Change some expressions of "folderNotSet" to let it looks clearer --- languages/zh.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/languages/zh.json b/languages/zh.json index cd0fedf..9e170c1 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -1,14 +1,14 @@ { "fullLangName": "Chinese", - "appName": "割草机启动器", + "appName": "GrassClipper启动器", - "playOfficial": "启动官方服务器", - "playPrivate": "启动私人服务器", + "playOfficial": "游玩官方服务器", + "playPrivate": "游玩私人服务器", "launchLocalServer": "启动本地服务器", - "genshinFolderSet": "设置 \"Genshin Impact Game\" 文件夹", - "grasscutterFileSet": "设置 \"GrassCutter\" .jar 文件", - "folderNotSet": "没有设置启动文件夹或文件", + "genshinFolderSet": "选择 \"原神\" 文件夹", + "grasscutterFileSet": "选择 \"GrassCutter\" .jar 文件", + "folderNotSet": "没有设置原神文件夹或GrassCutter文件", "ipPlaceholder": "IP地址", "noFavorites": "没有收藏", @@ -16,7 +16,7 @@ "settingsTitle": "设置", "scriptsSectionTitle": "进程", "killswitchOption": "杀死服务进程", - "killswitchSubtitle": "如果IE代理发生了一些错误,启用此选项可以杀死服务进程和你的网络连接。", + "killswitchSubtitle": "仅为那些害怕被封号的人准备。此选项可以结束游戏进程(还可以让你断网,如果修改了代理设置的话)。", "proxyOption": "代理", "proxySubtitle": "通过安装脚本安装代理服务器。", "updateOption": "更新", @@ -26,8 +26,8 @@ "enableServerLauncherOption": "启用本地服务器", "enableServerLauncherSubtitle": "启动器内为你显示启动本地服务器选项。", - "introSen1": "看来这是你第一次使用割草机启动器!", - "introSen2": "首先,欢迎你使用割草机启动器,其次很高兴在这里见到你! :)", + "introSen1": "看来这是你第一次使用GrassClipper启动器!", + "introSen2": "首先,欢迎你使用GrassClipper启动器,其次很高兴在这里见到你! :)", "introSen3": "是否要运行代理安装程序?", "introSen4": "(需要连接到专用服务器)", @@ -36,4 +36,4 @@ "genshinFolderDialog": "选择Genshin Impact Game文件夹", "grasscutterFileDialog": "选择GrassCutter服务器jar文件" -} \ No newline at end of file +} From 20757517d14eaa0badbd7cfbb24492e2cb3cf286 Mon Sep 17 00:00:00 2001 From: Scirese <62688390+Scirese@users.noreply.github.com> Date: Sat, 23 Apr 2022 19:17:18 +0800 Subject: [PATCH 026/248] fix some errors --- languages/zh.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages/zh.json b/languages/zh.json index 9e170c1..1a3b1b4 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -29,11 +29,11 @@ "introSen1": "看来这是你第一次使用GrassClipper启动器!", "introSen2": "首先,欢迎你使用GrassClipper启动器,其次很高兴在这里见到你! :)", "introSen3": "是否要运行代理安装程序?", - "introSen4": "(需要连接到专用服务器)", + "introSen4": "(需要连接到私人服务器)", "proxyInstallBtn": "安装", "proxyInstallDeny": "不用了,谢谢", - "genshinFolderDialog": "选择Genshin Impact Game文件夹", + "genshinFolderDialog": "选择原神文件夹", "grasscutterFileDialog": "选择GrassCutter服务器jar文件" } From 1c48b4601311b542ebc241bfb19282d5ddbfc701 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 15:19:51 -0700 Subject: [PATCH 027/248] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba85856..b6fa6b6 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ The launcher most likely did not close correctly, and was unable to clean your p Thank you to everyone who has provided translations! <3 -* ZH - nuoxianCN +* ZH - nuoxianCN & Scirese * PT-BR - na.na * VIE - labalityowo * ID - Iqrar99 From e4e83fc13a7e35fca6c16d98a131407738824ea5 Mon Sep 17 00:00:00 2001 From: LinSoraK Date: Sun, 24 Apr 2022 00:31:02 +0200 Subject: [PATCH 028/248] adding french langage --- languages/fr.json | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 languages/fr.json diff --git a/languages/fr.json b/languages/fr.json new file mode 100644 index 0000000..6129ae9 --- /dev/null +++ b/languages/fr.json @@ -0,0 +1,39 @@ +{ + "fullLangName": "Français", + "appName": "GrassClipper", + + "playOfficial": "Jouer sur Officiel", + "playPrivate": "Jouer sur Privé", + "launchLocalServer": "Lancer le serveur en local", + + "genshinFolderSet": "Définir le dossier \"Genshin Impact Game\"", + "grasscutterFileSet": "Définir le fichier .jar \"GrassCutter\"", + "folderNotSet": "Pas encore défini", + + "ipPlaceholder": "Adresse IP", + "noFavorites": "Aucun favori n'est défini", + + "settingsTitle": "Paramètres", + "scriptsSectionTitle": "Scripts", + "killswitchOption": "Coupe-Circuit", + "killswitchSubtitle": "Seulement pour ceux qui sont très paranoïaques au sujet des bannissements. Tuez le processus de jeu *et coupez votre Internet* si le proxy ne fonctionne pas correctement.", + "proxyOption": "Proxy", + "proxySubtitle": "Install the proxy server via the install script", + "updateOption": "Mise à jour", + "updateSubtitle": "La mise à jour automatique est temporairement désactivée. Consultez GitHub pour la dernière version.", + "languageOption": "Langages", + "languageSubtitle": "Sélectionnez votre langue!", + "enableServerLauncherOption": "Activer le lanceur de serveur", + "enableServerLauncherSubtitle": "Autoriser le lanceur à executer une instance locale de GrassCutter", + + "introSen1": "On dirait que c’est la première fois que vous ouvrez GrassClipper!", + "introSen2": "Bienvenue! Nous sommes heureux de vous voir parmis nous :)", + "introSen3": "Voulez-vous lancer l’installateur du proxy ?", + "introSen4": "(nécessaire pour se connecter à des serveurs privés)", + + "proxyInstallBtn": "Installer", + "proxyInstallDeny": "Non merci", + + "genshinFolderDialog": Sélectionnez le dossier contenant Genshin Impact", + "grasscutterFileDialog": "Selectionnez le fichier jar du serveur de GrassCutter" +} \ No newline at end of file From 6e5ea041ea234f9f63c73fd8054d4cf25fe62d38 Mon Sep 17 00:00:00 2001 From: LinSoraK Date: Sun, 24 Apr 2022 01:16:13 +0200 Subject: [PATCH 029/248] Fixing misspells in french file --- languages/fr.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/languages/fr.json b/languages/fr.json index 6129ae9..c3a8001 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -24,16 +24,16 @@ "languageOption": "Langages", "languageSubtitle": "Sélectionnez votre langue!", "enableServerLauncherOption": "Activer le lanceur de serveur", - "enableServerLauncherSubtitle": "Autoriser le lanceur à executer une instance locale de GrassCutter", + "enableServerLauncherSubtitle": "Autoriser le lanceur à executer une instance locale de Grasscutter", "introSen1": "On dirait que c’est la première fois que vous ouvrez GrassClipper!", "introSen2": "Bienvenue! Nous sommes heureux de vous voir parmis nous :)", - "introSen3": "Voulez-vous lancer l’installateur du proxy ?", + "introSen3": "Voulez-vous lancer l’installateur du proxy?", "introSen4": "(nécessaire pour se connecter à des serveurs privés)", "proxyInstallBtn": "Installer", "proxyInstallDeny": "Non merci", - "genshinFolderDialog": Sélectionnez le dossier contenant Genshin Impact", - "grasscutterFileDialog": "Selectionnez le fichier jar du serveur de GrassCutter" + "genshinFolderDialog": "Sélectionnez le dossier contenant Genshin Impact", + "grasscutterFileDialog": "Selectionnez le fichier jar du serveur de Grasscutter" } \ No newline at end of file From 091fed2e751d3bc06896e52b672a8b453a6759e4 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 16:33:21 -0700 Subject: [PATCH 030/248] Update en.json --- languages/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages/en.json b/languages/en.json index 9140483..c658846 100644 --- a/languages/en.json +++ b/languages/en.json @@ -29,11 +29,11 @@ "introSen1": "Looks like this is your first time opening GrassClipper!", "introSen2": "First of all, welcome, happy to see you here! :)", "introSen3": "Would you like to run the proxy installer?", - "introSen4": "(required to connect to private servers)", + "introSen4": "(required to connect to servers)", "proxyInstallBtn": "Install", "proxyInstallDeny": "No thanks", "genshinFolderDialog": "Select Genshin Impact Game folder", "grasscutterFileDialog": "Select GrassCutter server jar file" -} \ No newline at end of file +} From ec7d242f29c7a4067c9e9b5a6998d9f547ca3e29 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 16:33:38 -0700 Subject: [PATCH 031/248] Update fr.json --- languages/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages/fr.json b/languages/fr.json index c3a8001..de1ac42 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -29,11 +29,11 @@ "introSen1": "On dirait que c’est la première fois que vous ouvrez GrassClipper!", "introSen2": "Bienvenue! Nous sommes heureux de vous voir parmis nous :)", "introSen3": "Voulez-vous lancer l’installateur du proxy?", - "introSen4": "(nécessaire pour se connecter à des serveurs privés)", + "introSen4": "(nécessaire pour se connecter à des serveurs)", "proxyInstallBtn": "Installer", "proxyInstallDeny": "Non merci", "genshinFolderDialog": "Sélectionnez le dossier contenant Genshin Impact", "grasscutterFileDialog": "Selectionnez le fichier jar du serveur de Grasscutter" -} \ No newline at end of file +} From 6c415b9111146b78a13db5b7dd976e74e71f9394 Mon Sep 17 00:00:00 2001 From: LinSoraK Date: Sun, 24 Apr 2022 01:33:58 +0200 Subject: [PATCH 032/248] Remove private hint from french file translation --- languages/fr.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/languages/fr.json b/languages/fr.json index c3a8001..8c3fae5 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -3,11 +3,11 @@ "appName": "GrassClipper", "playOfficial": "Jouer sur Officiel", - "playPrivate": "Jouer sur Privé", + "playPrivate": "Jouer sur Grasscutter", "launchLocalServer": "Lancer le serveur en local", "genshinFolderSet": "Définir le dossier \"Genshin Impact Game\"", - "grasscutterFileSet": "Définir le fichier .jar \"GrassCutter\"", + "grasscutterFileSet": "Définir le fichier .jar \"Grasscutter\"", "folderNotSet": "Pas encore défini", "ipPlaceholder": "Adresse IP", @@ -29,7 +29,7 @@ "introSen1": "On dirait que c’est la première fois que vous ouvrez GrassClipper!", "introSen2": "Bienvenue! Nous sommes heureux de vous voir parmis nous :)", "introSen3": "Voulez-vous lancer l’installateur du proxy?", - "introSen4": "(nécessaire pour se connecter à des serveurs privés)", + "introSen4": "(nécessaire pour se connecter sur des serveurs Grasscutter)", "proxyInstallBtn": "Installer", "proxyInstallDeny": "Non merci", From c21f6b13d813b5656751b0b8504f60e71a2c3676 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 16:41:52 -0700 Subject: [PATCH 033/248] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b6fa6b6..a9ea2b2 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Thank you to everyone who has provided translations! <3 * PT-BR - na.na * VIE - labalityowo * ID - Iqrar99 +* FR - linsorak & memetrollsXD # Screenshots From da87d3d2ab758fde84faffd0bda670febc55e50f Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 16:48:21 -0700 Subject: [PATCH 034/248] move similarily categorized functions to seperate files --- resources/index.html | 3 + resources/js/helpers.js | 89 ++++++++++++++ resources/js/index.js | 255 ---------------------------------------- resources/js/onLoad.js | 78 ++++++++++++ resources/js/options.js | 100 ++++++++++++++++ 5 files changed, 270 insertions(+), 255 deletions(-) create mode 100644 resources/js/helpers.js create mode 100644 resources/js/onLoad.js create mode 100644 resources/js/options.js diff --git a/resources/index.html b/resources/index.html index 9766e00..2a19427 100644 --- a/resources/index.html +++ b/resources/index.html @@ -5,7 +5,10 @@ + + + diff --git a/resources/js/helpers.js b/resources/js/helpers.js new file mode 100644 index 0000000..bfd99d3 --- /dev/null +++ b/resources/js/helpers.js @@ -0,0 +1,89 @@ +/** + * Get configuration + * + * @returns {Promise} + */ + async function getCfg() { + const defaultConf = { + genshinImpactFolder: '', + serverFolder: '', + lastConnect: '', + enableKillswitch: false, + serverLaunchPanel: false, + language: 'en' + } + const cfgStr = await Neutralino.storage.getData('config').catch(e => { + // The data isn't set, so this is our first time opening + Neutralino.storage.setData('config', JSON.stringify(defaultConf)) + + // Show the first time notice if there is no config + document.querySelector('#firstTimeNotice').style.display = 'block' + }) + + const config = cfgStr ? JSON.parse(cfgStr) : defaultConf + + return config +} + +/** + * Get the list of favorite IPs + * + * @returns {Promise} + */ + async function getFavIps() { + const ipStr = await Neutralino.storage.getData('favorites').catch(e => { + // The data isn't set, so this is our first time opening + Neutralino.storage.setData('favorites', JSON.stringify([])) + }) + + const ipArr = ipStr ? JSON.parse(ipStr) : [] + + return ipArr +} + +async function proxyIsInstalled() { + // Check if the proxy server is installed + const curDirList = await filesystem.readDirectory(NL_CWD) + + if (curDirList.find(f => f.entry === 'ext')) { + const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') + + if (extFiles.find(f => f.entry === 'mitmdump.exe')) { + return true + } + } + + return false +} + +/** + * Get the name of the game executable + * + * @returns {Promise} + */ + async function getGenshinExecName() { + // Scan genshin dir + const config = await getCfg() + const genshinDir = await filesystem.readDirectory(config.genshinImpactFolder) + + // Find the executable + const genshinExec = genshinDir.find(file => file.entry.endsWith('.exe')) + + return genshinExec.entry +} + +/** + * Minimize the window + */ + function minimizeWin() { + console.log('min') + Neutralino.window.minimize() +} + +/** + * Close the window + */ +function closeWin() { + console.log('close') + Neutralino.app.exit() +} diff --git a/resources/js/index.js b/resources/js/index.js index 128377b..edc4bd8 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -3,127 +3,6 @@ Neutralino.init(); let localeObj; const filesystem = Neutralino.filesystem -/** - * Every autofill, such as backgrounds and the game folder, - * should be done here to ensure DOM contents are loaded. - */ -document.addEventListener('DOMContentLoaded', async () => { - setBackgroundImage(); - displayGenshinFolder(); - displayServerFolder(); - - // Set title version - document.querySelector('#version').innerHTML = NL_APPVERSION - - const config = await getCfg() - const ipArr = await getFavIps() - - if (config.serverLaunchPanel) { - displayServerLaunchSection() - } - - // Set last connect - document.querySelector('#ip').value = config.lastConnect - - if (ipArr.includes(config.lastConnect)) { - document.querySelector('#star').src = 'icons/star_filled.svg' - } - - // Disable private game launch if proxy IP or proxy server is not found - const playPriv = document.querySelector('#playPrivate') - - if (!(await proxyIsInstalled())) { - playPriv.classList.add('disabled') - playPriv.disabled = true - } - - // Exit favorites list and settings panel when clicking outside of it - window.addEventListener("click", function(e) { - const favList = document.querySelector('#ipList') - const settingsPanel = document.querySelector('#settingsPanel') - - // This will close the favorites list no matter what is clicked - if (favList.style.display !== 'none') { - favList.style.display = 'none' - favList.style.transform = '' - } - - // This will close the settings panel no matter what is clicked - let settingCheckElm = e.target - - while(settingCheckElm.tagName !== 'BODY') { - if (settingCheckElm.id === 'settingsPanel' - || settingCheckElm.id === 'settingsBtn') { - return - } - - settingCheckElm = settingCheckElm.parentElement - } - - // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel - if (settingCheckElm.tagName === 'BODY') { - // This will close the settings panel only when something outside of it is clicked - if (settingsPanel.style.display !== 'none') { - settingsPanel.style.display = 'none' - } - } - }); - - // Ensure we do the translation at the very end, after everything else has loaded - await doTranslation() - - if (!config.genshinImpactFolder) { - handleGenshinFolderNotSet() - } - - if (!config.serverFolder) { - handleServerNotSet() - } -}) - -/** - * Get the list of favorite IPs - * - * @returns {Promise} - */ -async function getFavIps() { - const ipStr = await Neutralino.storage.getData('favorites').catch(e => { - // The data isn't set, so this is our first time opening - Neutralino.storage.setData('favorites', JSON.stringify([])) - }) - - const ipArr = ipStr ? JSON.parse(ipStr) : [] - - return ipArr -} - -/** - * Get configuration - * - * @returns {Promise} - */ -async function getCfg() { - const defaultConf = { - genshinImpactFolder: '', - serverFolder: '', - lastConnect: '', - enableKillswitch: false, - serverLaunchPanel: false, - language: 'en' - } - const cfgStr = await Neutralino.storage.getData('config').catch(e => { - // The data isn't set, so this is our first time opening - Neutralino.storage.setData('config', JSON.stringify(defaultConf)) - - // Show the first time notice if there is no config - document.querySelector('#firstTimeNotice').style.display = 'block' - }) - - const config = cfgStr ? JSON.parse(cfgStr) : defaultConf - - return config -} - /** * Enable play buttons */ @@ -186,21 +65,6 @@ async function handleServerNotSet() { privBtn.disabled = true } -async function proxyIsInstalled() { - // Check if the proxy server is installed - const curDirList = await filesystem.readDirectory(NL_CWD) - - if (curDirList.find(f => f.entry === 'ext')) { - const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') - - if (extFiles.find(f => f.entry === 'mitmdump.exe')) { - return true - } - } - - return false -} - /** * Show the game folder under the select button */ @@ -366,35 +230,6 @@ async function handleFavoriteList() { } } -/** - * Add the current value of the IP input to the favorites list - * OR - * Remove the current value of the IP input from the favorites list - */ -async function setFavorite() { - const ip = document.querySelector('#ip').value - const ipArr = await getFavIps() - - // Set star icon - const star = document.querySelector('#star') - - if (star.src.includes('filled') && ip) { - star.src = 'icons/star_empty.svg' - - // remove from list - ipArr.splice(ipArr.indexOf(ip), 1) - } else { - star.src = 'icons/star_filled.svg' - - // add to list - if (ip && !ipArr.includes(ip)) { - ipArr.push(ip) - } - } - - Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) -} - async function openSettings() { const settings = document.querySelector('#settingsPanel') const config = await getCfg() @@ -432,15 +267,6 @@ async function closeSettings() { } } -async function toggleKillSwitch() { - const killSwitch = document.querySelector('#killswitchOption') - const config = await getCfg() - - config.enableKillswitch = killSwitch.checked - - Neutralino.storage.setData('config', JSON.stringify(config)) -} - async function closeFirstTimePopup() { const firstTimePopup = document.querySelector('#firstTimeNotice') firstTimePopup.style.display = 'none' @@ -485,55 +311,6 @@ async function displayServerLaunchSection() { } } -async function toggleServerLaunchSection() { - const config = await getCfg() - - displayServerLaunchSection() - - // Save setting - config.serverLaunchPanel = !config.serverLaunchPanel - Neutralino.storage.setData('config', JSON.stringify(config)) -} - -async function getLanguages() { - const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) - const config = await getCfg() - - // Clear language options - const languageSelect = document.querySelector('#languageSelect') - languageSelect.innerHTML = '' - - // Load all languages as options - for (const file of languageFiles) { - const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName - const lang = file.entry.split('.json')[0] - - const option = document.createElement('option') - option.value = lang - option.innerHTML = fullLanguageName - - // Set language selected to config language - if (lang === config.language) { - option.selected = true - } - - document.querySelector('#languageSelect').appendChild(option) - } - -} - -async function handleLanguageChange(elm) { - const list = elm - const config = await getCfg() - - // Set language in config - config.language = list.value - Neutralino.storage.setData('config', JSON.stringify(config)) - - // Force refresh of application, no need for restart! - window.location.reload() -} - /** * Set the game folder by opening a folder picker */ @@ -579,22 +356,6 @@ async function setGrassCutterFolder() { enableServerButton() } -/** - * Get the name of the game executable - * - * @returns {Promise} - */ -async function getGenshinExecName() { - // Scan genshin dir - const config = await getCfg() - const genshinDir = await filesystem.readDirectory(config.genshinImpactFolder) - - // Find the executable - const genshinExec = genshinDir.find(file => file.entry.endsWith('.exe')) - - return genshinExec.entry -} - /** * Launch the game with no modifications nor proxy */ @@ -627,19 +388,3 @@ async function launchLocalServer() { Neutralino.os.execCommand(`${NL_CWD}/scripts/local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e)) } - -/** - * Minimize the window - */ -function minimizeWin() { - console.log('min') - Neutralino.window.minimize() -} - -/** - * Close the window - */ -function closeWin() { - console.log('close') - Neutralino.app.exit() -} \ No newline at end of file diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js new file mode 100644 index 0000000..3224bb6 --- /dev/null +++ b/resources/js/onLoad.js @@ -0,0 +1,78 @@ + +/** + * Every autofill, such as backgrounds and the game folder, + * should be done here to ensure DOM contents are loaded. + */ + document.addEventListener('DOMContentLoaded', async () => { + setBackgroundImage(); + displayGenshinFolder(); + displayServerFolder(); + + // Set title version + document.querySelector('#version').innerHTML = NL_APPVERSION + + const config = await getCfg() + const ipArr = await getFavIps() + + if (config.serverLaunchPanel) { + displayServerLaunchSection() + } + + // Set last connect + document.querySelector('#ip').value = config.lastConnect + + if (ipArr.includes(config.lastConnect)) { + document.querySelector('#star').src = 'icons/star_filled.svg' + } + + // Disable private game launch if proxy IP or proxy server is not found + const playPriv = document.querySelector('#playPrivate') + + if (!(await proxyIsInstalled())) { + playPriv.classList.add('disabled') + playPriv.disabled = true + } + + // Exit favorites list and settings panel when clicking outside of it + window.addEventListener("click", function(e) { + const favList = document.querySelector('#ipList') + const settingsPanel = document.querySelector('#settingsPanel') + + // This will close the favorites list no matter what is clicked + if (favList.style.display !== 'none') { + favList.style.display = 'none' + favList.style.transform = '' + } + + // This will close the settings panel no matter what is clicked + let settingCheckElm = e.target + + while(settingCheckElm.tagName !== 'BODY') { + if (settingCheckElm.id === 'settingsPanel' + || settingCheckElm.id === 'settingsBtn') { + return + } + + settingCheckElm = settingCheckElm.parentElement + } + + // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel + if (settingCheckElm.tagName === 'BODY') { + // This will close the settings panel only when something outside of it is clicked + if (settingsPanel.style.display !== 'none') { + settingsPanel.style.display = 'none' + } + } + }); + + // Ensure we do the translation at the very end, after everything else has loaded + await doTranslation() + + if (!config.genshinImpactFolder) { + handleGenshinFolderNotSet() + } + + if (!config.serverFolder) { + handleServerNotSet() + } +}) diff --git a/resources/js/options.js b/resources/js/options.js new file mode 100644 index 0000000..65eb8a1 --- /dev/null +++ b/resources/js/options.js @@ -0,0 +1,100 @@ +/** + * Toggle the killswitch script + */ +async function toggleKillSwitch() { + const killSwitch = document.querySelector('#killswitchOption') + const config = await getCfg() + + config.enableKillswitch = killSwitch.checked + + Neutralino.storage.setData('config', JSON.stringify(config)) +} + +/** + * Toggles the server launching panel + */ +async function toggleServerLaunchSection() { + const config = await getCfg() + + displayServerLaunchSection() + + // Save setting + config.serverLaunchPanel = !config.serverLaunchPanel + Neutralino.storage.setData('config', JSON.stringify(config)) +} + +/** + * Get all languages for the language selector + */ +async function getLanguages() { + const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) + const config = await getCfg() + + // Clear language options + const languageSelect = document.querySelector('#languageSelect') + languageSelect.innerHTML = '' + + // Load all languages as options + for (const file of languageFiles) { + const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName + const lang = file.entry.split('.json')[0] + + const option = document.createElement('option') + option.value = lang + option.innerHTML = fullLanguageName + + // Set language selected to config language + if (lang === config.language) { + option.selected = true + } + + document.querySelector('#languageSelect').appendChild(option) + } +} + +/** + * Save lang, refresh to apply + * + * @param {DOMElement} elm + */ +async function handleLanguageChange(elm) { + const list = elm + const config = await getCfg() + + // Set language in config + config.language = list.value + Neutralino.storage.setData('config', JSON.stringify(config)) + + // Force refresh of application, no need for restart! + window.location.reload() +} + + +/** + * Add the current value of the IP input to the favorites list + * OR + * Remove the current value of the IP input from the favorites list + */ + async function setFavorite() { + const ip = document.querySelector('#ip').value + const ipArr = await getFavIps() + + // Set star icon + const star = document.querySelector('#star') + + if (star.src.includes('filled') && ip) { + star.src = 'icons/star_empty.svg' + + // remove from list + ipArr.splice(ipArr.indexOf(ip), 1) + } else { + star.src = 'icons/star_filled.svg' + + // add to list + if (ip && !ipArr.includes(ip)) { + ipArr.push(ip) + } + } + + Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) +} From dd644b449ef082dfef44aa1d81ccbdea44d75851 Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Sun, 24 Apr 2022 01:57:28 +0200 Subject: [PATCH 035/248] Check commit description - Add Spanish and Dutch as languages - Replace "GrassCutter" with "GrassCutter" - Fix minor problem with package.json - Fix some potential terminology problems --- README.md | 2 +- languages/en.json | 8 ++++---- languages/es.json | 39 +++++++++++++++++++++++++++++++++++++++ languages/fr.json | 2 +- languages/id.json | 4 ++-- languages/nl.json | 39 +++++++++++++++++++++++++++++++++++++++ languages/pt-br.json | 6 +++--- languages/vie.json | 2 +- languages/zh.json | 6 +++--- package.json | 2 +- resources/index.html | 2 +- resources/js/index.js | 2 +- 12 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 languages/es.json create mode 100644 languages/nl.json diff --git a/README.md b/README.md index b6fa6b6..2ce1c39 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Grasscutter launcher for easily switching between Official and Private servers * [x] Server IP input * [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)) * [ ] 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) + * [ ] Optional username/password creation for servers before entering (not implemented in Grasscutter yet) * [x] Kill switch script (optional) * [x] Automatically run `install.cmd` when opening for the first time * [ ] Fix Windows scaling issues? diff --git a/languages/en.json b/languages/en.json index c658846..4d9a21f 100644 --- a/languages/en.json +++ b/languages/en.json @@ -3,11 +3,11 @@ "appName": "GrassClipper", "playOfficial": "Play Official", - "playPrivate": "Play Private", + "playPrivate": "Play on Grasscutter", "launchLocalServer": "Launch Local Server", "genshinFolderSet": "Set \"Genshin Impact Game\" folder", - "grasscutterFileSet": "Set \"GrassCutter\" .jar file", + "grasscutterFileSet": "Set \"Grasscutter\" .jar file", "folderNotSet": "Not set", "ipPlaceholder": "IP Address", @@ -20,7 +20,7 @@ "proxyOption": "Proxy", "proxySubtitle": "Install the proxy server via the install script", "updateOption": "Update", - "updateSubtitle": "Auto updating is temporarily disabled. Check GitHub for the newest releease.", + "updateSubtitle": "Auto updating is temporarily disabled. Check GitHub for the newest release.", "languageOption": "Language", "languageSubtitle": "Select your language!", "enableServerLauncherOption": "Enable Server Launcher", @@ -35,5 +35,5 @@ "proxyInstallDeny": "No thanks", "genshinFolderDialog": "Select Genshin Impact Game folder", - "grasscutterFileDialog": "Select GrassCutter server jar file" + "grasscutterFileDialog": "Select Grasscutter server jar file" } diff --git a/languages/es.json b/languages/es.json new file mode 100644 index 0000000..72119a9 --- /dev/null +++ b/languages/es.json @@ -0,0 +1,39 @@ +{ + "fullLangName": "Español", + "appName": "GrassClipper", + + "playOfficial": "Jugar en oficial", + "playPrivate": "Jugar en Grasscutter", + "launchLocalServer": "Iniciar servidor local", + + "genshinFolderSet": "Establece el folder \"Genshin Impact Game\"", + "grasscutterFileSet": "Establece el archivo .jar de \"Grasscutter\"", + "folderNotSet": "No establecido", + + "ipPlaceholder": "Dirección IP", + "noFavorites": "No hay favoritos", + + "settingsTitle": "Ajustes", + "scriptsSectionTitle": "Scripts", + "killswitchOption": "Kill Switch", + "killswitchSubtitle": "Solo para aquellos muy paranoicos con bans. Cierra el proceso del juego *y tu Internet* si algo le sucede al proxy.", + "proxyOption": "Proxy", + "proxySubtitle": "Instale el servidor proxy a través del script de instalación", + "updateOption": "Update", + "updateSubtitle": "Las actualizaciónes automáticas están deshabilitadas temporalmente. Consulte GitHub para ver la versión más reciente.", + "languageOption": "Idioma", + "languageSubtitle": "Seleccióne su idioma!", + "enableServerLauncherOption": "Habilita el launcher del servidor", + "enableServerLauncherSubtitle": "Habilite el tile del launche del servidor para iniciar una instancia local de Grasscutter.", + + "introSen1": "¡Parece que es la primera vez que abres GrassClipper!", + "introSen2": "En primer lugar, ¡bienvenido, feliz de verte por aquí! :)", + "introSen3": "Quieres ejecutar el instalador de proxy?", + "introSen4": "(necesario para conectarse a los servidores)", + + "proxyInstallBtn": "Instalar", + "proxyInstallDeny": "No gracias", + + "genshinFolderDialog": "Selecciona la carpeta Genshin Impact game", + "grasscutterFileDialog": "Selecciona el archivo .jar de Grasscutter" +} diff --git a/languages/fr.json b/languages/fr.json index de1ac42..4ee7bb1 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -7,7 +7,7 @@ "launchLocalServer": "Lancer le serveur en local", "genshinFolderSet": "Définir le dossier \"Genshin Impact Game\"", - "grasscutterFileSet": "Définir le fichier .jar \"GrassCutter\"", + "grasscutterFileSet": "Définir le fichier .jar \"Grasscutter\"", "folderNotSet": "Pas encore défini", "ipPlaceholder": "Adresse IP", diff --git a/languages/id.json b/languages/id.json index d8ca49c..e29c7b6 100644 --- a/languages/id.json +++ b/languages/id.json @@ -7,7 +7,7 @@ "launchLocalServer": "Luncurkan Local Server", "genshinFolderSet": "Atur folder \"Genshin Impact Game\"", - "grasscutterFileSet": "Atur file \"GrassCutter\" .jar", + "grasscutterFileSet": "Atur file \"Grasscutter\" .jar", "folderNotSet": "Belum diatur", "ipPlaceholder": "Alamat IP", @@ -35,5 +35,5 @@ "proxyInstallDeny": "Tidak terima kasih", "genshinFolderDialog": "Pilih folder Genshin Impact Game", - "grasscutterFileDialog": "Pilih file jar server GrassCutter" + "grasscutterFileDialog": "Pilih file jar server Grasscutter" } \ No newline at end of file diff --git a/languages/nl.json b/languages/nl.json new file mode 100644 index 0000000..b88c2c7 --- /dev/null +++ b/languages/nl.json @@ -0,0 +1,39 @@ +{ + "fullLangName": "English", + "appName": "GrassClipper", + + "playOfficial": "Normaal spelen", + "playPrivate": "Op Grasscutter spelen", + "launchLocalServer": "Lokale server starten", + + "genshinFolderSet": "Selecteer de \"Genshin Impact Game\" folder", + "grasscutterFileSet": "Selecteer het \"Grasscutter\" .jar bestand", + "folderNotSet": "Niet geselecteerd", + + "ipPlaceholder": "IP adres", + "noFavorites": "Geen favorieten", + + "settingsTitle": "Instellingen", + "scriptsSectionTitle": "Scripts", + "killswitchOption": "Kill Switch", + "killswitchSubtitle": "Alleen voor de paranoïde gebruikers. Als iets met de proxy gebeurt, sluit dit jouw spel *en je internet* af.", + "proxyOption": "Proxy", + "proxySubtitle": "Installeer de proxy server via de installeer script", + "updateOption": "Update", + "updateSubtitle": "Automatisch updaten is tijdelijk uitgeschakeld. Ga naar de GitHub voor de nieuwste release.", + "languageOption": "Taal", + "languageSubtitle": "Selecteer je taal!", + "enableServerLauncherOption": "Server Launcher inschakelen", + "enableServerLauncherSubtitle": "Schakel dit in om de server launcher tile te gebruiken om een lokale Grasscutter server te starten.", + + "introSen1": "Het lijkt erop dat het de eerste keer is dat je Grasscutter gebruikt!", + "introSen2": "Ten eerste, welkom, goed om jou hier te zien! :)", + "introSen3": "Wil je de proxy installer uitvoeren?", + "introSen4": "(vereist om te verbinden naar servers)", + + "proxyInstallBtn": "Installeren", + "proxyInstallDeny": "Nee dank je", + + "genshinFolderDialog": "Selecteer de Genshin Impact Game folder", + "grasscutterFileDialog": "Selecteer het Grasscutter server jar bestand" +} diff --git a/languages/pt-br.json b/languages/pt-br.json index 5a16707..fe64647 100644 --- a/languages/pt-br.json +++ b/languages/pt-br.json @@ -7,7 +7,7 @@ "launchLocalServer": "Abrir Servidor Local", "genshinFolderSet": "Definir a pasta: \"Genshin Impact Game\" ", - "grasscutterFileSet": "Definir o arquivo .jar de \"GrassCutter\" ", + "grasscutterFileSet": "Definir o arquivo .jar de \"Grasscutter\" ", "folderNotSet": "Não Definida", "ipPlaceholder": "Endereço Ip", @@ -24,7 +24,7 @@ "languageOption": "Idioma", "languageSubtitle": "Selecione seu idioma!", "enableServerLauncherOption": "Permitir ao launcher ligar o servidor", - "enableServerLauncherSubtitle": "Permitir ao launcher iniciar uma instancia local do GrassCutter", + "enableServerLauncherSubtitle": "Permitir ao launcher iniciar uma instancia local do Grasscutter", "introSen1": "Parece que essa é a sua primeira vez usando o GrassClipper!", "introSen2": "Primeiramente, bem-vindo, estou feliz de te ver aqui! :)", @@ -35,5 +35,5 @@ "proxyInstallDeny": "Não obrigado", "genshinFolderDialog": "Selecione a pasta Genshin Impact Game", - "grasscutterFileDialog": "Selecione o arquivo jar do GrassCutter" + "grasscutterFileDialog": "Selecione o arquivo jar do Grasscutter" } \ No newline at end of file diff --git a/languages/vie.json b/languages/vie.json index d9c6cca..521c135 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -7,7 +7,7 @@ "launchLocalServer": "Khởi động Grasscutter", "genshinFolderSet": "Chỉnh địa điểm thư mục \"Genshin Impact Game\"", - "grasscutterFileSet": "Chỉnh địa điểm file \"GrassCutter\"", + "grasscutterFileSet": "Chỉnh địa điểm file \"Grasscutter\"", "folderNotSet": "Chưa chỉnh file", "ipPlaceholder": "Địa chỉ IP", diff --git a/languages/zh.json b/languages/zh.json index 1a3b1b4..39cd328 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -7,8 +7,8 @@ "launchLocalServer": "启动本地服务器", "genshinFolderSet": "选择 \"原神\" 文件夹", - "grasscutterFileSet": "选择 \"GrassCutter\" .jar 文件", - "folderNotSet": "没有设置原神文件夹或GrassCutter文件", + "grasscutterFileSet": "选择 \"Grasscutter\" .jar 文件", + "folderNotSet": "没有设置原神文件夹或Grasscutter文件", "ipPlaceholder": "IP地址", "noFavorites": "没有收藏", @@ -35,5 +35,5 @@ "proxyInstallDeny": "不用了,谢谢", "genshinFolderDialog": "选择原神文件夹", - "grasscutterFileDialog": "选择GrassCutter服务器jar文件" + "grasscutterFileDialog": "选择Grasscutter服务器jar文件" } diff --git a/package.json b/package.json index 2612e1b..66eb121 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "GrassClipper", + "name": "grassclipper", "version": "0.6.4", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", diff --git a/resources/index.html b/resources/index.html index 9766e00..f7cb4d1 100644 --- a/resources/index.html +++ b/resources/index.html @@ -118,7 +118,7 @@
- +
diff --git a/resources/js/index.js b/resources/js/index.js index 128377b..a3f9dc8 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -562,7 +562,7 @@ async function setGenshinImpactFolder() { enableButtons() } -async function setGrassCutterFolder() { +async function setGrasscutterFolder() { const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { filters: [ { name: 'Jar files', extensions: ['jar'] } From 4a8a17d1d71a3233529dd9bef48a988eb4a917ad Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Sun, 24 Apr 2022 02:00:34 +0200 Subject: [PATCH 036/248] Even more terminology --- languages/id.json | 2 +- languages/pt-br.json | 2 +- languages/vie.json | 2 +- languages/zh.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/languages/id.json b/languages/id.json index e29c7b6..f1f1a8b 100644 --- a/languages/id.json +++ b/languages/id.json @@ -3,7 +3,7 @@ "appName": "GrassClipper", "playOfficial": "Mainkan Official", - "playPrivate": "Mainkan Private", + "playPrivate": "Mainkan Grasscutter", "launchLocalServer": "Luncurkan Local Server", "genshinFolderSet": "Atur folder \"Genshin Impact Game\"", diff --git a/languages/pt-br.json b/languages/pt-br.json index fe64647..48c3ef5 100644 --- a/languages/pt-br.json +++ b/languages/pt-br.json @@ -3,7 +3,7 @@ "appName": "GrassClipper", "playOfficial": "Jogar (Oficial)", - "playPrivate": "Jogar (Privado)", + "playPrivate": "Jogar (Grasscutter)", "launchLocalServer": "Abrir Servidor Local", "genshinFolderSet": "Definir a pasta: \"Genshin Impact Game\" ", diff --git a/languages/vie.json b/languages/vie.json index 521c135..df26360 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -3,7 +3,7 @@ "appName": "GrassClipper", "playOfficial": "Máy chủ chính thức", - "playPrivate": "Máy chủ riêng tư", + "playPrivate": "Grasscutter", "launchLocalServer": "Khởi động Grasscutter", "genshinFolderSet": "Chỉnh địa điểm thư mục \"Genshin Impact Game\"", diff --git a/languages/zh.json b/languages/zh.json index 39cd328..93667c3 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -3,7 +3,7 @@ "appName": "GrassClipper启动器", "playOfficial": "游玩官方服务器", - "playPrivate": "游玩私人服务器", + "playPrivate": "在 Grasscutter 上播放", "launchLocalServer": "启动本地服务器", "genshinFolderSet": "选择 \"原神\" 文件夹", From 1483b6ac1262945d4d77be137e9b52788ab4b04f Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Sun, 24 Apr 2022 02:02:59 +0200 Subject: [PATCH 037/248] Clarify what type of Spanish --- languages/es.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages/es.json b/languages/es.json index 72119a9..bf0dad4 100644 --- a/languages/es.json +++ b/languages/es.json @@ -1,5 +1,5 @@ { - "fullLangName": "Español", + "fullLangName": "Español (México)", "appName": "GrassClipper", "playOfficial": "Jugar en oficial", From 4b13e0240ad3aae7a3c9a9a402a9bfc357fe055c Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Sun, 24 Apr 2022 02:03:36 +0200 Subject: [PATCH 038/248] Change official name on NL translation --- languages/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages/nl.json b/languages/nl.json index b88c2c7..c514295 100644 --- a/languages/nl.json +++ b/languages/nl.json @@ -1,5 +1,5 @@ { - "fullLangName": "English", + "fullLangName": "Nederlands", "appName": "GrassClipper", "playOfficial": "Normaal spelen", From 43694dc0c5b5d407a2df396f4b402959cce0b3f2 Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Sun, 24 Apr 2022 02:05:14 +0200 Subject: [PATCH 039/248] Localise language names --- languages/vie.json | 2 +- languages/zh.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/languages/vie.json b/languages/vie.json index df26360..0550a2b 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -1,5 +1,5 @@ { - "fullLangName": "Vietnamese", + "fullLangName": "Tiếng Việt", "appName": "GrassClipper", "playOfficial": "Máy chủ chính thức", diff --git a/languages/zh.json b/languages/zh.json index 93667c3..59fb4e7 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -1,5 +1,5 @@ { - "fullLangName": "Chinese", + "fullLangName": "Simplified Chinese (中国人)", "appName": "GrassClipper启动器", "playOfficial": "游玩官方服务器", From 3213b4cbfdfdfb4049456a05439781d147481eda Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 17:05:21 -0700 Subject: [PATCH 040/248] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 21541b3..d0ef8ea 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,8 @@ Thank you to everyone who has provided translations! <3 * VIE - labalityowo * ID - Iqrar99 * FR - linsorak & memetrollsXD +* ES - memetrollsXD +* ND - memetrollsXD # Screenshots From 19a35fce2d82ca240a1e19def568e894089f33bc Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 17:13:35 -0700 Subject: [PATCH 041/248] Update README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d0ef8ea..161745a 100644 --- a/README.md +++ b/README.md @@ -33,21 +33,22 @@ Grasscutter launcher for easily switching between Official and Private servers # TODO -* Interface - * [ ] Integrated banner creator +* Interface/internals * [x] UI * [x] Official and Private options * [x] Server IP input * [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)) - * [ ] 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] Kill switch script (optional) * [x] Automatically run `install.cmd` when opening for the first time - * [ ] Fix Windows scaling issues? + * [ ] 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) + * [ ] Platform detection and bash scripts + * [ ] Fix Windows scaling issues? (partially done) + * [ ] Integrated banner creator * Proxy service * [x] Local proxy server * [x] Intercept and modify GI requests like with Fiddler, allow anything else to pass through - * [ ] Fix Discord and YouTube issues when proxy is enabled (not sure what's up with them?) + * [ ] Fix Discord and YouTube issues when proxy is enabled (maybe fixed) # Having problems? From f9eb06c3e725422b64142c17ed28d50481546e31 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 21:05:07 -0700 Subject: [PATCH 042/248] Change references to anime game to generic references --- README.md | 2 +- languages/en.json | 4 ++-- languages/es.json | 4 ++-- languages/fr.json | 4 ++-- languages/id.json | 4 ++-- languages/nl.json | 4 ++-- languages/pt-br.json | 4 ++-- languages/vie.json | 4 ++-- languages/zh.json | 4 ++-- proxy/proxy.py | 6 +++--- resources/bg/private/1.png | Bin 12441 -> 12406 bytes resources/index.html | 4 ++-- resources/js/helpers.js | 12 ++++++------ resources/js/index.js | 34 +++++++++++++++++----------------- resources/js/onLoad.js | 6 +++--- resources/js/translation.js | 2 +- resources/style/index.css | 2 +- 17 files changed, 50 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 161745a..07def0f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Grasscutter launcher for easily switching between Official and Private servers 1. Download the zip file 2. Extract the zip file somewhere -3. Run `GrassClipper.exe`, install the proxy server, and set your `Genshin Impact Game` folder! +3. Run `GrassClipper.exe`, install the proxy server, and set your game folder! # Setup (for Development) diff --git a/languages/en.json b/languages/en.json index 4d9a21f..cbf092b 100644 --- a/languages/en.json +++ b/languages/en.json @@ -6,7 +6,7 @@ "playPrivate": "Play on Grasscutter", "launchLocalServer": "Launch Local Server", - "genshinFolderSet": "Set \"Genshin Impact Game\" folder", + "gameFolderSet": "Set game folder", "grasscutterFileSet": "Set \"Grasscutter\" .jar file", "folderNotSet": "Not set", @@ -34,6 +34,6 @@ "proxyInstallBtn": "Install", "proxyInstallDeny": "No thanks", - "genshinFolderDialog": "Select Genshin Impact Game folder", + "gameFolderDialog": "Select game folder", "grasscutterFileDialog": "Select Grasscutter server jar file" } diff --git a/languages/es.json b/languages/es.json index bf0dad4..c3cc788 100644 --- a/languages/es.json +++ b/languages/es.json @@ -6,7 +6,7 @@ "playPrivate": "Jugar en Grasscutter", "launchLocalServer": "Iniciar servidor local", - "genshinFolderSet": "Establece el folder \"Genshin Impact Game\"", + "gameFolderSet": "Establece el folder game", "grasscutterFileSet": "Establece el archivo .jar de \"Grasscutter\"", "folderNotSet": "No establecido", @@ -34,6 +34,6 @@ "proxyInstallBtn": "Instalar", "proxyInstallDeny": "No gracias", - "genshinFolderDialog": "Selecciona la carpeta Genshin Impact game", + "gameFolderDialog": "Selecciona la carpeta game", "grasscutterFileDialog": "Selecciona el archivo .jar de Grasscutter" } diff --git a/languages/fr.json b/languages/fr.json index 1aa6707..3eb9246 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -6,7 +6,7 @@ "playPrivate": "Jouer sur Grasscutter", "launchLocalServer": "Lancer le serveur en local", - "genshinFolderSet": "Définir le dossier \"Genshin Impact Game\"", + "gameFolderSet": "Définir le dossier game", "grasscutterFileSet": "Définir le fichier .jar \"Grasscutter\"", "folderNotSet": "Pas encore défini", @@ -34,6 +34,6 @@ "proxyInstallBtn": "Installer", "proxyInstallDeny": "Non merci", - "genshinFolderDialog": "Sélectionnez le dossier contenant Genshin Impact", + "gameFolderDialog": "Sélectionnez le dossier contenant le game", "grasscutterFileDialog": "Selectionnez le fichier jar du serveur de Grasscutter" } diff --git a/languages/id.json b/languages/id.json index f1f1a8b..5c200f0 100644 --- a/languages/id.json +++ b/languages/id.json @@ -6,7 +6,7 @@ "playPrivate": "Mainkan Grasscutter", "launchLocalServer": "Luncurkan Local Server", - "genshinFolderSet": "Atur folder \"Genshin Impact Game\"", + "gameFolderSet": "Atur folder game", "grasscutterFileSet": "Atur file \"Grasscutter\" .jar", "folderNotSet": "Belum diatur", @@ -34,6 +34,6 @@ "proxyInstallBtn": "Install", "proxyInstallDeny": "Tidak terima kasih", - "genshinFolderDialog": "Pilih folder Genshin Impact Game", + "gameFolderDialog": "Pilih folder game", "grasscutterFileDialog": "Pilih file jar server Grasscutter" } \ No newline at end of file diff --git a/languages/nl.json b/languages/nl.json index c514295..cdbeed2 100644 --- a/languages/nl.json +++ b/languages/nl.json @@ -6,7 +6,7 @@ "playPrivate": "Op Grasscutter spelen", "launchLocalServer": "Lokale server starten", - "genshinFolderSet": "Selecteer de \"Genshin Impact Game\" folder", + "gameFolderSet": "Selecteer de game folder", "grasscutterFileSet": "Selecteer het \"Grasscutter\" .jar bestand", "folderNotSet": "Niet geselecteerd", @@ -34,6 +34,6 @@ "proxyInstallBtn": "Installeren", "proxyInstallDeny": "Nee dank je", - "genshinFolderDialog": "Selecteer de Genshin Impact Game folder", + "gameFolderDialog": "Selecteer de game folder", "grasscutterFileDialog": "Selecteer het Grasscutter server jar bestand" } diff --git a/languages/pt-br.json b/languages/pt-br.json index 48c3ef5..23c3402 100644 --- a/languages/pt-br.json +++ b/languages/pt-br.json @@ -6,7 +6,7 @@ "playPrivate": "Jogar (Grasscutter)", "launchLocalServer": "Abrir Servidor Local", - "genshinFolderSet": "Definir a pasta: \"Genshin Impact Game\" ", + "gameFolderSet": "Definir a game pasta ", "grasscutterFileSet": "Definir o arquivo .jar de \"Grasscutter\" ", "folderNotSet": "Não Definida", @@ -34,6 +34,6 @@ "proxyInstallBtn": "Instalar", "proxyInstallDeny": "Não obrigado", - "genshinFolderDialog": "Selecione a pasta Genshin Impact Game", + "gameFolderDialog": "Selecione a game pasta", "grasscutterFileDialog": "Selecione o arquivo jar do Grasscutter" } \ No newline at end of file diff --git a/languages/vie.json b/languages/vie.json index 0550a2b..31800c3 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -6,7 +6,7 @@ "playPrivate": "Grasscutter", "launchLocalServer": "Khởi động Grasscutter", - "genshinFolderSet": "Chỉnh địa điểm thư mục \"Genshin Impact Game\"", + "gameFolderSet": "Chỉnh địa điểm thư mục trò chơi", "grasscutterFileSet": "Chỉnh địa điểm file \"Grasscutter\"", "folderNotSet": "Chưa chỉnh file", @@ -35,6 +35,6 @@ "proxyInstallBtn": "Có", "proxyInstallDeny": "Không", - "genshinFolderDialog": "Chọn thư mục có chứa game", + "gameFolderDialog": "Chọn thư mục có chứa trò chơi", "grasscutterFileDialog": "Chọn file Grasscutter" } \ No newline at end of file diff --git a/languages/zh.json b/languages/zh.json index 59fb4e7..1791328 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -6,7 +6,7 @@ "playPrivate": "在 Grasscutter 上播放", "launchLocalServer": "启动本地服务器", - "genshinFolderSet": "选择 \"原神\" 文件夹", + "gameFolderSet": "选择 \"原神\" 文件夹", "grasscutterFileSet": "选择 \"Grasscutter\" .jar 文件", "folderNotSet": "没有设置原神文件夹或Grasscutter文件", @@ -34,6 +34,6 @@ "proxyInstallBtn": "安装", "proxyInstallDeny": "不用了,谢谢", - "genshinFolderDialog": "选择原神文件夹", + "gameFolderDialog": "选择原神文件夹", "grasscutterFileDialog": "选择Grasscutter服务器jar文件" } diff --git a/proxy/proxy.py b/proxy/proxy.py index eae593f..581b3cb 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -6,7 +6,7 @@ ## # -# Genshin Impact script for mitmproxy +# Anime game script for mitmproxy # # https://github.com/MlgmXyysd/ # @@ -24,7 +24,7 @@ import string from mitmproxy import ctx from mitmproxy import http -class MlgmXyysd_Genshin_Impact_Proxy: +class MlgmXyysd_Anime_Game_Proxy: def load(self, loader): loader.add_option( @@ -77,5 +77,5 @@ class MlgmXyysd_Genshin_Impact_Proxy: flow.request.host = REMOTE_HOST addons = [ - MlgmXyysd_Genshin_Impact_Proxy() + MlgmXyysd_Anime_Game_Proxy() ] \ No newline at end of file diff --git a/resources/bg/private/1.png b/resources/bg/private/1.png index 61405603d11d9658d78f0822a24ce3f23689189c..295812c42f32bdf2624e0fddb858b02dcd61af87 100644 GIT binary patch literal 12406 zcmeHt2UJttx93F^5h)^46samIN{0wRKq(?>=p7-n0D**1LJ3H*Q5F3Dd~^`0hR~%+ z3n<-4Zvg}pX#oN05Zc`MmGyt~-ppI?&6_ndYYht)_ny1YK4&m5 zu9+tQur|^D=wh$2@&dpyE~KF;))e*tYKK9K+t_1l5#qjRH;@_tZmRgY+1R-tu!6P- zN2IHg@N!MPuprW2N!UaVCJA#>LpUMt`gtG>{Im`2{9No5?1fd71#kL7K?Z09)<)15 zjdJyb`YH+k;tK_zY0VPCg1<@RX-R2G3CSB0Qj%iQ(ojhVR8B_l&mUoMG!J_RsJ{B0KgR;!l!TqISU0GIgpZGp zxQ~oD#=}uUNaKSV&g{ms_Z^G`K_3X|})ag&e|m!ygGi_qTgZ#p+G57e*0?d>EGCxR3i&swJq>Yg2nl_J zC&tUe4x!-1Hm-IEEp;VfP&wjAq&*ZND<=&uEQFY?EJ8ud_J*vz zn5~_Sf|v{fVecSkYcC72lm4r}I>ye6wgmp_Z~q_cuj7FPx1bH`Kh1}>F==ZDdKc*l zS{3)_)-gc1|M`SM3jSIyP#ZhiHc%3_quC!}FZ^dS@;|MCKiK*>AwZ`8lXdY2nJ2~p z>to}Axa|mP>)%~>65!+|XdCtqIVApj5r2LAr_KErIe22w9{)b7z?Z)dJA^BE!g+v4 znYekP2>^&vwA61K`dTfHDgEAOn#5pT;<$OfZSKVhvxZdWvcjv|Erl9dN&`0(JkL*Z$4fFD>=|xLy-5L0yV{ zL?Klj0R-s}jSo%&l73HEfLAOZ7=X4AYkI(5t(XpYCqxE-;ZrCe7{v$yZb6Rn0)o8% zSCR3ci*fr@uacS?MWlpP?G?;1pkg>%V)hd$^Id7F!K3Y;>9xjZLPJBF``+r1T!041 zIdpLqmZFcN+|bn2Z2sOFO>3=a7bQO=KC0SYrx@T^05Zhv0e{pj4&|VOhkMk8q8Jj; zuz40yoU6k{^xtyD`)r zM&ZE*&r`mpK!DvDjCDicsa!q1TVyC4rI)_I;( zd(LXF%ycBTZ^)a^|M-FOI198*;6))wyjGq}EKdY=bmG9+YS-`C?*!PPZLjy9gUN&W z!piq`N&PH90IyNA2=vpZ{EmaQw8NVx-RLdq=bAXa0 zyyl(#trj8dIoAK z>}D+X13slvht9R~-2I9T}`3DAZyL2o_~`-5vxw%LMG?(dK~bjIt>p>sp+d`R zMRY(Ft-XLc9QM82PUY1JVCNH*{0zH&K~z2@3lM~xv1u4hra;_XlRw?Hk_L+36fi=B zl>Az8Xh2YB82s3~Hln`K@{kv3>l!pf&Ciyf5WNAsiZ93|s|V+%X*R3d0&OJli)f%G z6R=t?$C-TZSpu&90;kG*+`?eND}qnR7?IX>4%pF|!Vy#_8A z@x9J7JHx}nSCt=a>sswv?TO-^JudNInbcUBYLCIhwjp@pjiK#`i z2oYO@FT5^V(9#s|mGWF3`uJ;6@1kDOpy45JzY2%Vi`e8G=l+d_q02>xprHC%1d;Jh ztXzN*aNQmpTOeq!q_#hmQH=e;wv~{!HrQ+Ts%sh>x}^GAXhOsKTwy*eAD6j+DDhY)<1s;p2WixLXGv{H{bLR}N)v z^m%^%z|k4ABFyXUN7+9j7lIKAPNH4K2p|UO(rMQ*PSX9UFt)4@fRA z;yU3=S(_Oya~_x7U?Pd8=MeJ|@$|*4PhiM7R+QD7aG_^8te0FzCnhkDw9C>JC$M7y zc_!>h=7wD3^+9muOf%{>&Nc`Gt~2HPpkVtIFY}%yF}6_N#qoVQV#@s?N7nwh@p4!% zM66pjk;^0GeA2z4(Mqgksd;U5si+CXZj`)EfGPbH<8aP7wuqoV-B8U42~UR>=X`1; zc=Gh>a-s1yx!BZzeoU{HxU49AuN8rw8ZWjT@?I|>Jx6!OjIW)U>W4&Opdggh} zIPm6xVOI?gxTZVUvt}EG+Cna5GFrxpZ*l9{js65v-3IJ zJZhSGEU`(#Kn1s&Ra;@Mo5#BvVCG=Cu~kxio@;De>S(fP_uf#@{!pc)Wo1;CV1w>K z!Crh)V`JlL?+~H&U9axi*AGw2u~(u6REWjnPoF+r)jz2A6S$$L^j^I!eEv(RV^>Z{ zl2-r&T}Xzlj2idCm*4AG7mSh%D-dl%l|QO`XS2a^U^t1O{f(jaQ+*T)r61rZgx4#d z@U}FX1zK(uC)x~n5q(!CRlV%TYM^{^6lV*X(3U3DYJ*7ERvPt9Hl4~mblgc&7k#7i}~6oe!O?o7w$g5JE`rFpEzC-QKw>+rhkShdmk$l<|p zo~J#As6lonV@pTsBM!)rOJ5#D3RP88W3l&*EhypqK>r!%Nf|5_YY1A0D6gz6?mAv; zHco#FA^X9BuklJ=p{GS?AVhD!tr(`?(VQgrdA(KTpu~4~b8*V+0Y^+YUB#GFNCx?V z-Ps7HJpQwTLoP4x!8o0JZE_%-iG`h&M_-+c2{mg^2q8nto!8>)_YkX?qe%(dHEogx z(5ARioF5P;L@xeE2}>nR;FT}Qef9_(AG!pIX75)yR4XyH%<>{$}NUv~Hp zUoOJQ4Frp0`B7H&ftKgbpMPYMUKOzG?e6U@(gpx^6j`!5zUt525Blk6=KyQQ)Q*xw zE@#^|P+dSsw^ng@=Iis~$mKH1wYIi`Qwp}p zKZ8mNNu%+wG-iS*Dk?UEPW6*Z^OQO+BozquGDAke&N*l3UjR8Ql<7B%1QzAK`)CUQ z(2_WT4@ZHyr~hXD@Irs@MeEYi(o|cmnHWDu^f7Bi`7gUdAYl_3}=+{_xF!UTM5%0>jy)XPnulKvt4QR zyCufJY9_eQveGImR4S-@J8P5eF_)+1(hP#XY<}DzYys?o*M|J|5pWmt6wjF+o`xDG5c-$*s;hGX3HcpdYX64rgYU z=2w2?Ymh=gkUCUP+`XP9 z#xL-gEqJlSqxeKmx>0KTDWS|9}IPUu@EhN4@ zAj&@PBp3SKGL_}YT2{-?%o{qlD?V0;?{4z{Qnn1rPynUBb>o9bR#5p3uQvf8b!Xbp;gsm zeD-5*{h{UE_@RE|L^YXf`QDtL0Uj&I44V zh0a6X6%DYoWci-8FsE8wOAzBt_^#0R7RgUk@i!VL4#>Fv;<$6$FM<0a z?wJ)V?!8%8h{P`^mwB-}s~*j9PAnlBWsmZRX9(!Yw2 z?Ywyt)|dFCOEL9%S8&aX_0P3=#4@beY`Xn7nV}X8XLF+4wT;E_Qpn*>R}k?heRN5h zLu&I4rO~yFq9RIuGpV)^X1-IC^dKqPS~+lUyN0!t%9mMU zUMBOR_#YuPbA}7HiH?qr&5NUzB#XdNoxVW-YaeYAxE^s0ATA4#=KXM_h<(1a4~!;8 z{yVFPx1+}!7@&tAmtlRiQOdJln!ZF}E%VI1&A{-nS+ZZ&9o~1!h`HdpjGlMWn)d$3 z)m@&D-0?N>I3*XW?lK3b6V^2w=TM>>tmO-=in4sfS^^?&;EeN#cLlrK{H|!BPkB-A z8$kegm3jLKtPeikW8-5plGP&)UBcqf`KO&l`v_+Op4|r8U=lH*$xThY35p(me&*xS zK^Z9CzfVf|!0gubYpJz<{GvJ9kD`Xwe+-wl?WFQUh;^$=#1I1@%X^({ z*qiAm%I?OcWGgB%dq;O(`a!=O+Qq^WrK$7-5u^EU|GFB{SbF{Zn(2kd*xeW=;Z1&srju=+9wOT zxrhiB<}0eOZSXjrn(#8XeZ(WvmY%+vR)5L80{IrC#CcKh#uFB1r@kj0IcT;90<#9) zf3)CKEV9xVQ&UqDlO~6+d_Tr!aO8R?M&m=Ua9NpL6PrQK==VIJ?QsOlI^HVQtcg}m zI1yZNly{E2FjQ3kJP~v%++b#NZ5hdBl!%Y(A6;2--wEr`tAnT^8giu19J?RJdhqqD zwX0L&Ea*I4SR~g%GK6by`fuj1c(F$obG_ZEL#|fl;;{H>KZvX7^SpG z8$w+Ev00WQeC+!ra>MDsy_MG0Uaa2B@Sm%oj-Gi_+*iinhF!&O3(ZD4lkdYlJbxd zk!(AtYi7b+_2E69+z`yKE}Q|fIp4xo*C~C20|{7pH!DRjS54a( z039dkegn@7Y4YcDGA2-mn6dZn-&ODW9_-<8x&G)7l0J;@P^6QNaBvuX4>nc?l-`y1 z-`if9QZQ-=cRT)~wS`rqK>rS{=l*)1PBWN7+^niy>T=$b(jD$DdU7)3o&lRIn7O}Z zrl4(&PVkK1F+ve8NKKNw$ETXjQphi0ajafEGfs}?u_B_fsw}TY!mJIBC24&8oG-No zQ+mdwiv5Vx{4(oi$eJ|Ms~#(Ia5&MwqtZalS0XpTZQZll%5E9(Nn2ou-8`k(@jHDF z*@@bP#@TdSc} z@jiW7Nu2fCWOHPD(^u%@5cKH}IrHx`ORZWjPQq9qEBmJ=IAZa=sQD^vaEJ7^uHoJ# zF3smzgdJ&BmeHx7KZ|SE%b&>P^qtA#*w1X9F04>FLJN@Y+0C7Gasf9YHQqF(@4LX^ zcBsVlcbs%zi-PuDR>1H(+Z~S_GfGB?LfEY*qhr9ND6aC+z`*A6j~@>X04Axub($wf z1Vb3|$c91RvV+2#;rXg83Xz$(@mgG;{Q9{T&XWgWwcblU)`|1>KlcK?_&?fq_0srFg`kCG}U3I(^yIUQ>=7aO3W1W`* zd)Z4w;_czFIt`vB6XVfli?w~CX#>$g`wMV5D;rz==xfBF;-c5a{<)F6m5y;0(F^9u z8?TSQI2rB#^XqL~mkA{x?{2&S{P-=4y1+=Q8t=uA@dJ?1q`60!@mhtQ8%N*Qg7Eb`iq z!*Qb*$GG)0?&g_p3~I#M{B}#GX}8zGKcf-F`)DDppiJytN;Q@@8jL|LOk!L|ucHNq z${`Cdfxa?K->yl|fJgA+;OLFE+WOTBtvV06A~EO0PoG8U-n@j2p4pNxNOvAdv#fpn zt6pVw^s_j@kpk)L-E_BfDILc}C;9~OZWJ>W=Z_O__e$g{D|SoW-O?E8b=LCR&6qj% zRwxg#77}L6BDld?OzJYee(eaX{0EIk#a}$kqQe2jg@cMcp`+OB_{@w+d~!eTxSo~p zhQQ&9z;yP2Z0dEfl;cTrNCw5~i&4Rm7c3n1^>;-zn+Dhvl$Qa;eN^+i7Pq+#kz9fH zvKR7Aib|h%Z=R2j2jYIpO4yr;Vb7WR0S# z^SK7%CrmC$TDB4z^(gNgkh|{-%gr!-c1fb1B;pX|)Yq51H$W#5*GH;!;)Z)GXl-d4 zFy{K4A|-IT_E!9;je~%d8+K^#^wv(*y++4}R*0bN(VO>2TfM{r3XIwc?^mMDEfCvR zSn|OLV!8kzQIyC(_YcCfRXQm#<5uMphX-3Rt=IEl4dI>n(W2VbQH3lDRb@mryCAV^ zmYu&0R%U)$%*x-=FUY{cYuvE@}M)@-*hlxfd$uP_8i~)Bh!@+E30daqD8h0gXi{)v?%hFu-!of2YBlGM(JS zJ)lv#sk!eq?6=^j{QzrQN|4Vpd@;iO)Cm3CMphTEN2l?RJnAc(KHZM%6i-J`y~NMv zhxxnJ-CL`V7kf!J!X*fi4vW!#av8`a*t1||k-bhPg**lVj*j4r9*j{AblPw$ZS!aU zP_S508SoJ9P!RO5$M=I9UZ67bmdYAgWN<8xNH1s!)Ud9+Zi3{DN-fu!Vy$$m_q_0f zV`T?sTLr?K@IA;-Jy@9CdiTg$5maUG5cjw0CT=&Z{fb}Q3GUL(*8JTNCf->2{t6;d zS@wCQ*@$wXPTzQBPM4}uzk1}*&HLqhUa9;-V}sRZTVmG=9QK!d>XY{t`cK{B_M==S zNaQsSof}CqPa7$GyZD_tc*b?4ObSb; zYz}r*W6rK5@=~wdu=Zc4RT!Ubyy-E)=Z=)sXK>413l9B~%7 zQFpM7%KC75ywO);G|cnRulA2{6fJESbbASx6wu>($~Rg10nZ3Ng3J?c`RZ+ zwD5X^+pmuDwIx09-A6`f>Bo-zQw#eH)ZaCVDFiAzyd~gh6c!f{nk3ZtVAM-aj_=F+ zCjWt%TJ=8jl#^|{EX+cY)&^;8rA}{^3Z5>_N6K5y5JsW*4V>xV$aGa#R(LUyq*!^B;oWsj&Vg5-&!02(@;GytYuQQ=wtO- z`c9Hh^-ZiO%;wV`O27JGp_^*T4P5`Ozc*X!IsYa0nn^@gnu?Binok%Fu)7>zvq}p= z!E$tSYqS8#g6O>K;qC1m!6u;m`w$Vj{3dd(!N6*vb8WUO^0Llrux;MO5-9HQI|)(Q zUpH7;>jIg<|A71Yz@n(Oj?QILQ79O9e9XQd|LK0S{irQ3U9kIZ&Wm@Ykln=7#8s4g6lWl<4R%!*-+-FSZz2&UUGE;*rB zo~s@f=1dZuk4<8{M>0l&p6&AC9mylWYPU#VLp(g`p6HSUHNzXRdTMCLCSkHEeJ&32}qq{W&#U|EOQ=ie-%-YlZ}8H~-s z80A2~LuBs=FhQxabf;|v7fd3rRtT68WeCejg< z<8j+h4nUG5sHO)1YNq#_8Gtuz|1}V=-QHi z%}z1l$MtMs{7Qzb$<78 zbJM*UbWmG+NdScE#Fi$&QUN}4h#5qaSS)72m}okivbnWI0@qt$$7m&{o;SyDbxI4; zC_B*I2UfyASpY5V;IuD6e}eT;a1}=gW&cVbQF>L|-$Dh%4J9*}$KWA{@iGMMT}uEZGCu7|B{2sNOHluM&8ZGS!!!i~stH3XYP<|2^)jJXk z-%IeX9qjL}nvE$aD-(+g#l>pA7){I?eY6e;%KDJa?+ZfqpZozxnsw>zYDQUP0OGaJe6^)K#`W4!PBI za5t^;!TVej7s3Vv&D%iUo*5BDhMq(FtT_iuc^LLHP*%g@k)$M_i=Rcdr{m!wjtw9-0w-A*t4!ia z0Tz{Q@A_KBYbN>-hFmxpWz8XR`ra zjR2mhTKeQK#CF@$?$sSD=5c4^?#1_HQ|(7_T(}>y8|f|c0r}$-WKEK`w$+g2#akwZ zC}}USUT8&Kj89x}9OG+*PtT@q`@|;uJ-5-bG!B@IFAgh#6)U|>-Co7ae;)OIl$DWNR#Ok`+G{Q<#ZpU{(D<3R_ zH@CO9e~LjTkEbD0jx&Th(Wh{rAitox3vsIPnENStSx{-w7dv7)a1x=&E>X9~=uM)- zZ|Ktw0CCoBnMIdPP6+zGFe@}r(^1}Gz=bmD)z6mf+6STo!xs1xk*FA5`kzXi$t=1> z_-AuBzhk$6TmGUDUcmyq;r#96K!Q%QgPN=nx>gP-<^joi49n>Nu1wp~+w=9cKMLrA zoAIEQm7^=@g3*HDQwl4IA=pdu%rWqG(LbI4|7G`#)COtr$d9EZu6S`vXO#N{&679* zEla)ep3{i7d;jE25|{oc#M_kA*Tct;H1M2&*t{ZEwj=P9X@{TCP{@P5pVaDk-u;6FR zdH(P|@FG5fWjG=|`<|gK*V#C8qtDA#UJG&I?EpOois!*TV>U7RZbW-SWQ0(jkx@+C zL@mzF>7=zah;}>x(Q)GCAI57A4#)6}G9@gQx%JwIk#x+O#Ws?Zlz78u$)Hz>9cqyX zNVNA8nE^a$#_FQGYFs;2Cqk1rXj=_1Qp4(|aAZ*A#Mf~aB08vp`g zNGB7xoSARa(Kwo)cBY-xYO}(?mujy(@FJBM=B!FOgZ23b{5hUr;WZ}n`J_*J#`g&j zKwCb08T@kdC@<6pEcr}=QD6*--4%p0Wvg!9QDtd(&l8d1Nnx|R(-1zPH!?QHH`e{T zF1@7k6P8r4y5+t?yX!Jy0@m4*Q?h;f=(V3El3N(EsrQy!GKlAz1T*gF2g9vNH0qvlS^EpUD(`p$rI&Pl!s1fd8GNA)n9?Y=xv+88 z8+2YGYeBaBrvMx~?Q&kiP3HesF6{l^e3|h7&+Y%n%};f`J(Y;mx4-*|a`w?K|7&Sz Ks~4(TKlyJsi3NxN literal 12441 zcmeHuc|6qbyZ1;7g%WLKt%&R~7|WF9D={cUm`4!^|?Qv>%Q*mzV7Y1-tSwig_#lW zexdy!5Qx|KlEGCFXcrg+;@IZe3%ud>1&;y$arj>~(gTq`oSX#;yWK9rE`mT6i3hfv z_Uy>`T)OTL0`a}s`Q=DC$0rN|?K$dUWs9?gnL?0QjDnL3))}P`gz*8SK_G2tkdG76 z3xyMRM!9)->qsutHA;$mxadgQsKJzAKKdwkk4qtbD9aEtD`bclQqx5esw=J?1OXIa zP&g;?APm~u9}=V^`IlY@@VxU{QBwRb5uBHf+S!yn*fI?208gCDk~`Mbm=ca7vyg_AG{y>uf|=FiYPP+ zgYw4t1G37$WqsVSIIO=r_Wz>#_ve4p0N`2}>~|agt}PhM?J(13QFQc`7bL_L>xXdyI_!aQaziQlc)Ll8|8^rpAB)EN0SyDzo&VSGjrH{{{IISb zXyC)n@)0*S)CVhTg2D1C3d(<(3xh$7z5Q`c-bj?OfsQ2L90d;#7YIsKO$C@(D0yd9 zl%~A1x~hx3Gtx;@{yYlh;;QECq6$W;{G+}B7Kz`P0{^J*@?WfP?&kq4K_~QoThGqI z+?hL&OCJ8fs0RPNbSzQ6e?Or;#Q&Nu5GUl$GSHDk?upz`$ih%KoI}7$#KNSD>F8=lHUoGx`hyy#u&g1W`3Ml;E z>`>mo4(A7KWeRqWZ9t%NJjMnWt%7dMk2EF;c!ca*6xF(Uuf#7!;&#V)jBu?uva(a# zK;7WLkT=ePZ~ClF@L*eJC#u;n`FR763U+$&hnUaf?`@`FmmtyZhP4kSCUb}$T;mGU zs-f;tx;MT$FT62i)TZZE!GR;73mhyG3kqtQ;0A*(DDM^qJv)Aj7i7WnYA@()j3XyV zP`{i56elqV0<|1MgCd=|{+Yy{e{)=!>noWXZ3yjq_3G8LqwQ}Yph%R)IxdImaIYFW zcFjCnw-oqlGxn!e;KFEWLSkac^XJbuj)J}v3!Xs#_*`q*5W%KW$%tEgAcw5nnB3f} z0?kGqg__#hFFtg2m9$|A!|&c1H^hYJUS3^aLN?oieD=f@4H^^%uYSA27;nC_k=hkd z8>)z)zIY0axPjR0xi74KEho-HRsY^aYo183p%uD6Iz!t0>8G@SuS1n?!X?^}Q4h5h zVr~oSh%(48zHG26I)h8KprC-EcKM-Ao7Edon>=KYOKreh)cfeuc8>Hx=iB!!{0S|A zJZc|4eBfbnES4DV70#IssS93lWh{Md?L#$R0p%T454J6o(B+wMFME8qn=DIdwKx2t@nC!m$<$$7z>|41g; zlQ-RfXXjD4PpIEmnm_agsQhl+eNSF^x*KQH_jBNg^=7f~ZNr%_a7~#NH0V+%#aY1L zt7mKv1n`^UE4S$((1Q$oi&VC~z{1CAn;>+%Udm9%Az*# zmKFyy71|5>h9tk5Zizp}IFl5^5$Wx!C78men6BC(6_X2c@A%VMKy1Z~Tdlbzt$(C0 z5ZlKr^IBSZ(0L>%xykxIH*_PY%MwSg!54e~ zgx_iy$Fm$~%SbMMq#o?joxEJn-oOd(Yzg8=D^!MS8-Jus;h>xY?a-%>$bgmUPDF%6 zoq3<@h?1?s^v08{tWuGq!tYo1M8?E*zHVu)?Y+RC@*oFTAas-MVlWe&*Ym!ESgQ+C z+Vjfw&hq%<`up3YRGFA(SCt=X@QNxM5#z&zGsFcj3HqjV(X@)heW3F`-OLU%^tE2% z;&f-GIk4Wg@mapi@84gr21f2~*5m2@`2-KIV;6I8IM> zIa*UcUz11k4GFOuqd;f3%aZQUU>KPR-*;;=Bt#1mq;zaRa&Xf6E)0Wi@;IP|$vL&X zM(ROLg!j-b-zN@`W&aS0%7vXcTz6>!O4g}Xa3?03gly_oH==h@s~Z7wK|U=^U(x|dte@ET$0>9;kW z!q45@)MkPF{pN4MGVvn*h~Oir-bIUzKzM$89;SEuUUxwy6bfbIfFF;#3^IMc+2_EJ zh@#`E#%#<;#rted|D*+@UcQ3|Z8pUw*i59XH3#y&&L}}y`nw=akLF1>Cna>07wk6@ z)a|kpB;ekbM^N9Cu2M{g13cQc(FfE$GG)Kz(M|KK)l=@{iNyhV{*Dv2_fqzaV>Xpf zKiHM*oa)w4qAgR6e-GEH!9B)r@YqcCO!bgWkP8JSZ6^dIg=RN|n2ViYCiy4#%OZ?_ z_=eEosNM%)!TaU(zDI2k&z3wp!KxcMh!Okh+-*s`10tRIZlx0Ufn2m*=c*3>_z zF$)nQ#N-Gu!F&}SAG!|BQYgBkmUqrY<{yvfAGx_|5N;iV^P#b*bnRGt4=R)FRaakz zzbFlvppHwybyr2G#`*2MrKj`h$GzGp%RXvk$-U)*bqgobs#D-iyzAppuleNC|^>m`; z*6Vd!OSDnQ3*^`aYk5s@lV21X?tl;?&L5+tZG`OlmdB@2nbe4+#sy|{ZU^d^&W;s~ zp?az$Ry_SWwH9Ui)uOk2GxRE{?(iv^vWrMWL&K?)8DfYhqz2o*cCPI_Fkt= zE0sVC7*l5Fl&U0E%QV_WBrNlVnc^`WPaffFiLmb2g7I8)pZHoU{WJ{MY0!2DWH4$v zPZTrOd}WqUJ$u-*2Rzw6ld-7kGDLW%wMZRzwY>2C)JTj(d)axZ8fLC`EXYB>tHlBD2wzok|`74ZL!`1snY2WXA6| zN+r~7?5YH+_f^Z4^=8E@j888vmP53(gtwxjK@aS$%DI>1%jr}dHAowm1fdyb|BSnP zi5k95q3#8BjL1b?bxPt=TvA|9PUcaku#&59Y(9#eJo&;dt?X5zg#a}4<5ACva8Trw ztwReDHl`^;J089(5@okj+WLsF-&0V=rTTCsN(f|2l#~TyF0)9j`9M=cqfpVhWGs<0Rlns|Tv~pU`%SqV5E`hcV@J2};rDlnvS85TuV24zJOT=; zKtbMAJO*{O;=dWc?g?egS>qQ*8~U&a2ByM6?x4wpk<#Pnov;$hT1PTyV=OWR0x8Bu zmk5Z2BDo9RHEvBQ_KC6ATj$IpHY^!GM(Q^Dm%KmMT*=DL9vE#|LzCvJd)mnV(!z)^;{%@jbVN9Q+a5yLE@(q)p#s=yIYQdwEq zC%o@$mSeLV7r3KyaAuMe6VqQy*bHFISC3s|FDtUIjx%%Z%UawQeO?eioCxJhWC2m@Bjb#1$`otf@CLVT_5Ec(WWSJ!2kjLkpo{ z)>;JHrtl`O6*_&-kxXX%myh|JW7dWex|(aNv%N3Zpo}*wtD4LR_F6tJdxOmbMdOseeYieng4AhT&-24#=rN4ntKC_dg&F9X%oehcb$n-?q zTw0av&>J>hRJYulQQs0`Zf;Hw^*olvD7CM)OIzpxyjNjo^t}~`7D5AA6$A`jM_YRf z7ao3t-4{e??wF@l+gzM$WYHVv)Ik0@$DEG#m?6`8o++&b4po#Q^$Z9415WnuDaPEK zn4Fx9M@fEG-Q-WJv#VwkWX}^g+lk<{nFEWD0hi{9w0-Kw_jG5(y*_DZ{S1?t33j2; zZW&dQtZ0NaZbAAFX}e<;h~UCmyPTobpg@eTc1An@bmSD^=jbZS$5+#eTOFEVl>7X$ zJ#<(*r?CzHVIVeCC@tY{m1`h$l$%pY?wKzRoFVA-eY8mW;TE#_k+6>x^HphM+S)7cYk)V zx4P0utq(p~@IUF1DAX{UrO?P~WsmN0TO&JBT9Hn`f;csA@pg_v!gDym58X8j$qIub z0Vk5kboi}LlsVJk+!eDDL13A@Nc*99P_0{XYl@aZGfX*6Mzsabm^O$sg$GZm2wMi6 zCG@8RQsC!QF~hGrEoMW8Ni%DG)oOir!v@_u>Ql9!sjgL&zD{P*1g#&bIx>QJmXREC zi8czA%7%A(>P;3ZNf?fth130*tRS0N$S~=S?zrnnc%GAsrJ-jM`MrgxMGxqNJd3Ic zo}EX&w7yTtn6L%ecx_$ZE%hkCK)?CI4duK2hNH88(1qQv&Thn9!}Q>zrv3aIy3c$@ z7vIW@Pa1XKq380SR*OLS?e~iuIBbl{oxnscPLI}4RSL^yf!}>D zQK=FccvYH80D*q*`ohxEQvTF)%>F32-ryn3k>~CNQKM!Hi@jwxT#<1~4-}xTI+ktc z6p-_t*)gQ*`BNkC+i!@Gy*BnKQg+!ENoCDSf^q|WS&SURVP)Qjzs2)6RdIzR7-f{S zJYKMVx-UH^Q-W4bx-3w-pxkvwiC6!XpU9gCg&S>32lnmT$Hh_Po#uA0s@8&`> zZOU#~L$?<7|IVGAANTh5ZVU%t$Ec-GbqRJ2p=%^+J{uAl%#Th_sdyzdFD{&~-GZQo zUDt_V)lY!MGfi1bQgniIZLsyri zm@)(8+>HD#Nq19uy$_V1KzL*#@de1+OD=Z`_T5iPN}Bujt&rMpzB_~Kls@@u-2$~l zk#Lm0D;3rfb3K-?N_n;Du?^;ONZf+6Msex;m!0F|PWXTTu;+Ra3~j{2i|5AF4exav zvO=FVvwJBsFA_w-5}Ml}gklH4O4Ek$?GWjklKm%~&bud>W<#N0w!Y6%krvEEt;%5{)*fAU)FdbRgxo3?Od0C490 zMqzBlvqd@Gr3agKF;|aY&`P?)5$Rm`&k5D&m* z*rxlLg@7)A80oUIXoEwCEYwiIGK=&WXl+lCTeGj93OfKdHC8K~B@cILd!7J0UpQ1_% zhujdsPx7t>6o`&@DN z%cvX0)ZI<^s`R+dp`js{BMBu>5}g#zAW_` z3tQcYv|}Of__}AADzIbiPDSg>Pcy`Itqj?6T;Iv-%+8^AHvUT*|^XGPm}Pi#|1-d zE>~I_9p*7z*L8IE&3JQj^BjXdP||)+AmwqPB+oX1tot_1sLy&3hjuQkr8_j~LWeV0 znC#8;%hXa!e^J-VmF${89;226!N*8neJnhX8?*0zPGq48u@XH_(Z^+n1wAKT3S@N) zVt(XEiG|Z}=#4PHN^^@#>;S|HZ|_Vq5p!Q%kiTkJlm;thzP4&!HvIvBrJ=_ZBdy>0 zy$@J&E*=Oc7-%y4OYKXx74x?;b%{K^`1J8y&P`nR%|4S9Y+CCXv6wir8QN%|G3zyP zJAn{gYj27zSNME9d;Z7Id0JWmocl5@n_$xHZJ)U!97*QWASGtq?os>5qXVWVFe&pN z5Y^oQXUI+?E8~ z7WHGSaZJD-m+PJgxgE5mu1ML5mamcDnLjx5ZKde&aDFTH zhm-o#X1J_OcZ}x&5n6&trRl(h6w)TWtdWWX;E~<1($cG6VW&)9){K7HTxe`uorss^ zqfJS-)p|n8-1!~A#%u2e*-Eqixn3>f#V_cS&pDq;*38hq4ObMj;~ugJ;W{ZS`(7g7 zNlc26wNNUWs`FWB=~n3a;&_?j1%EWf*xb%PT)O{fg0^?N)=0g8pQNZ%Y2@1}&6rH` zWf;WZF#D;EaLjQb)}~zVHB?8L`tnQ=Z4BLevW`4p;jR@Rt0o6;w0URxhFe}oqGT9N z&XdT5CB5ktSkXOa;nBL0$X-v(W{r!n#(M~5bk$UG=%_!BIun_7ZHD+g{SN6A+&hyj zi=-`MHdENJV;aQdY5<+jnQo{Owny5Fs4lB}0OsCUSk_Rreyg3Vz8v@Q@aWfOuPymrhZ7F_7{ zMCTtN3hnlTs|y6XQ&5sgXftOf8Y>s>xBr@ zo}SBm+Dl^*>`ge~FQms(6+4#S0ehGyi+n*F`fc~R5wYjR_#+MI>= zZ+{@O&72BXSpgoFEnXuZ^@Ld+} zIzs=m-9LZ+_)O08g|CO&XY}C%v%&3*s&zMpf;4}D^srmk(^6LU(?c<2jiFUu83`8o zx=|Vd!vfo72cnp5UU%?KJXohWvLRyEV?c)R+zIw+@$F@H{3x zKA0-SgB$6>5J%sF;pc2d88^r>ljzM8$vNXh54xTi%l7SxQp4v@kT>ZhMgI=L4oEh@b3`9yD@>dPQYeMFNL z@^D3?FV2J44dPodBVJ|mWB`8696+(ODYBT>&Xu&Q@R4&EXMH`rV;<2ibND+F^!dXR zJ&XXIoAZ*9RePdjOlzrJI6{obrl~DFPGhen-x1=3Z9epNPgPK7LZAA#ylfs*gi$9s zFM?*nqTEA1rV=;8W%-Z0X54U<8U`*3O!Yl;x4b++ducg)c!Ingnu&W1xAw}tug0kR zLdqdd2G(?b{e)|?j32n7tF6W$U=C;oi(`aeo3W{7m^Fmm@t9hnv2z`5BwdLV8w_zj zOoA6iAZx-E#-8S^c*V$78dF6qOGD=ZUlFw4kTNcRqy&rkKhn+ae<}0xRK)X-Gn&ws zWQ>P`k+5^GKlfl_?hTA@?r=-&X~aUZ^w%weL2FuF=i84G`4a6f1hPVC1$T(HffSO& z&FAr}x-o5QY+0>E1#)y;Wz;lsjfgi;C=ven zg1M~UUpJeDrBHRHKjCVX!O__pqLMk>1O6@vjWE$-umRHI7~BcD}Eq@}xgV^xXtw7HkVth`rd7;k<#(o zV#8sNml!vj3KnjN;2v6E2hLJ!>XT6!yjRNiBB?Px`|@b)&y-ub=CKD>s0YVQ$&*&`xM-lh%5Z)zPITUqaD_3hvJOq{2uLXzCornG@uoXlMgawRFS(7v|PBatG&H z`!Qnw63E#4s&_rm+F@0BI;?hQ>@cYcV>Q0dAy6m+zW0mD5n z0}#Qd>M$8yyKOP{l31E5aKYpCg5L~-VuO4EWtKzlQ%{d!fi$XG?mKm z1XyjLm5E_veV7$+{Xlgdz(!eVjj>|cTeAh(*KU5J@L1;S<71{H&s?b(A2u!#y>j0p zT&<4Z`tkaQbiBT`ji%|##5h<~x>)%7cn@pS(AQDM3TU?{TdGYTb~ny!cP24zWu*&h zgCH=hx685{&n^J@iXrR8tAz;m<{UucBBCITXZhr!9h+bJ)B8&|dP0nhj2QWzYK_xf z5v-MC%~oC6P({~t;)#%DOWvj)z+SspzAb=+EGi=$)xW$$AiwO)^;^mu+nT<*=alS) ziZG#=0F;gX6=u{Nz(kT{t;1h)*b2Rh@jA26bVqv|$t7E?Rz&E$IAmDkq1Af!9s9w7qSA=sDU5EgPa!F23>Ou&Du z+iPRk&t>b?>zR!#Mj7L3ucnSp0}f#+L>a9}TuE0-7fV#FnY=jzVCk%5kpTYc>JoP$ ziCh?k-Y)@PP-MAYN*|h@$p$p_0b}SJQ88kW26t(HTtQf)qW$2yGuC zwuHTsvdeb=E7w1k1K(R#ecKu~*cSkdX+KI-H>{@mgWQi90Cd1>5l`k`9?)V?^Xa3m zBfbkl;uAr6?Y!LT!7qumV`L2AMK{t3W36O&{Ta2%EQGgZVeR|CZ**A=ORIZ53|MIw zh4$KOtW^^c4iADCl-dcjsz;cm+i=P~G&k&QOU@3uUQNPeM?Jm`-JUfs!8UETBUo3* zR9FH=mZCI=Y{y30qoxOhMJHd;}tnujlI;c(cy+_^r zQP(%6JE2)Y5>mZp2irARbV4+x%DGhKAAYq)pyvvSFC$)jrd?k69BR(5S(R9ndNT+Q&h9>?KcT;>m{71 z6VumgvAXG+rAs^A0SbH9+TbRBP)!0-Q$W0&{ z7jmpWitFT=Jd$!K%Pnj~2lO!uDCQkW`9l;3ik!DXyXKa9e$C;C4FC1W30i&beEt+u zQ8CmV^i1qX=82)H0u1O2qBwe=|6A#4}`5IV=&-s~G1x_%^>1*G$g#_*rOhCT;u@C-Fj z>ZO(#=a!Qhe^@yK2VHm3t*>V|${l3Eg6CpVg|5WTo|jX**0B)0_~mBoJ5Z?9V7WR| zIyqoFHZPs$vklMn`+cT%tf@2v4~FCWP>?NRmt!_yKr!ZNr{I`~f1k5AYy+9ORLKkao}F_xJ+f8}v?4y( zbV+xDS4k`;*D-2(MgWw)@73Nv+GhHbl@MGz;OFtP#cH!yy~p;PK8%ivn;aPug;jQ6 z^LP6&tkBO2$QDSh{f?r$g}*t$3zc{8Q95{w7kBy-s3Y64c~TOj9klo?1Yqn4?aSP1 zpmxV)rKCFlnGbWldP{W{-AiI3B7N*XP4#%2{J6lTKYoMPr#?T)&Ms3>d}zVB!zZRY zZ0M))`%DBT1K?G4O^!^?UdQ0w!cuGBhbrd)yrZm)@DupbSH1c{=ZislEasll(MC34 zgV8h|mtE>rEBy2kFKVF@*9Ew%(oT) jzit2JtEC3k+faGk529E6da*lyA7E@~W
- - + +
diff --git a/resources/js/helpers.js b/resources/js/helpers.js index bfd99d3..6d83690 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -5,7 +5,7 @@ */ async function getCfg() { const defaultConf = { - genshinImpactFolder: '', + gamefolder: '', serverFolder: '', lastConnect: '', enableKillswitch: false, @@ -61,15 +61,15 @@ async function proxyIsInstalled() { * * @returns {Promise} */ - async function getGenshinExecName() { - // Scan genshin dir + async function getGameExecName() { + // Scan game dir const config = await getCfg() - const genshinDir = await filesystem.readDirectory(config.genshinImpactFolder) + const gameDir = await filesystem.readDirectory(config.gamefolder) // Find the executable - const genshinExec = genshinDir.find(file => file.entry.endsWith('.exe')) + const gameExec = gameDir.find(file => file.entry.endsWith('.exe')) - return genshinExec.entry + return gameExec.entry } /** diff --git a/resources/js/index.js b/resources/js/index.js index ff967b0..6b68a7e 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -33,9 +33,9 @@ async function enableButtons() { /** * Disable buttons when the game folder is not set */ -async function handleGenshinFolderNotSet() { +async function handleGameNotSet() { // Set buttons to greyed out and disable - document.querySelector('#genshinPath').innerHTML = localeObj.folderNotSet + document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet // Set official server background to default document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` @@ -68,11 +68,11 @@ async function handleServerNotSet() { /** * Show the game folder under the select button */ -async function displayGenshinFolder() { - const elm = document.querySelector('#genshinPath') +async function displayGameFolder() { + const elm = document.querySelector('#gamePath') const config = await getCfg() - elm.innerHTML = config.genshinImpactFolder + elm.innerHTML = config.gamefolder } /** @@ -126,17 +126,17 @@ async function setBackgroundImage() { await filesystem.createDirectory(NL_CWD + '/resources/bg/official') } - if (config.genshinImpactFolder) { + if (config.gamefolder) { // See if bg folder exists in parent dir - const parentDir = await filesystem.readDirectory(config.genshinImpactFolder + '/..') + const parentDir = await filesystem.readDirectory(config.gamefolder + '/..') if (parentDir.find(dir => dir.entry === 'bg')) { - const officialImages = (await filesystem.readDirectory(config.genshinImpactFolder + '/../bg')).filter(file => file.type === 'FILE') + const officialImages = (await filesystem.readDirectory(config.gamefolder + '/../bg')).filter(file => file.type === 'FILE') if (officialImages.length > 0) { for (const bg of officialImages) { - const path = config.genshinImpactFolder.replace('\\', '/') + '/../bg/' + bg.entry + const path = config.gamefolder.replace('\\', '/') + '/../bg/' + bg.entry // See if the file exists already const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') @@ -259,7 +259,7 @@ async function closeSettings() { settings.style.display = 'none' // In case we installed the proxy server - if (await proxyIsInstalled() && config.genshinImpactFolder) { + if (await proxyIsInstalled() && config.gamefolder) { const playPriv = document.querySelector('#playPrivate') playPriv.classList.remove('disabled') @@ -314,8 +314,8 @@ async function displayServerLaunchSection() { /** * Set the game folder by opening a folder picker */ -async function setGenshinImpactFolder() { - const folder = await Neutralino.os.showFolderDialog(localeObj.genshinFolderDialog) +async function setGameFolder() { + const folder = await Neutralino.os.showFolderDialog(localeObj.gameFolderDialog) // Set the folder in our configuration const config = await getCfg() @@ -325,17 +325,17 @@ async function setGenshinImpactFolder() { const gameFolder = folderList.filter(file => file.entry.includes('Genshin Impact Game')) if (gameFolder.length > 0) { - config.genshinImpactFolder = folder + '\\Genshin Impact Game' + config.gamefolder = folder + '\\Genshin Impact Game' Neutralino.storage.setData('config', JSON.stringify(config)) } else { - config.genshinImpactFolder = folder + config.gamefolder = folder } Neutralino.storage.setData('config', JSON.stringify(config)) // Refresh background and path setBackgroundImage() - displayGenshinFolder() + displayGameFolder() enableButtons() } @@ -362,7 +362,7 @@ async function setGrasscutterFolder() { async function launchOfficial() { const config = await getCfg() - Neutralino.os.execCommand(config.genshinImpactFolder + '/' + await getGenshinExecName()) + Neutralino.os.execCommand(config.gamefolder + '/' + await getGameExecName()) } /** @@ -380,7 +380,7 @@ async function launchPrivate() { Neutralino.storage.setData('config', JSON.stringify(config)) // Pass IP and game folder to the private server launcher - Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} "${config.genshinImpactFolder}/${await getGenshinExecName()}" "${NL_CWD}" ${config.enableKillswitch}`).catch(e => console.log(e)) + Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch}`).catch(e => console.log(e)) } async function launchLocalServer() { diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index 3224bb6..48c50b8 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -5,7 +5,7 @@ */ document.addEventListener('DOMContentLoaded', async () => { setBackgroundImage(); - displayGenshinFolder(); + displayGameFolder(); displayServerFolder(); // Set title version @@ -68,8 +68,8 @@ // Ensure we do the translation at the very end, after everything else has loaded await doTranslation() - if (!config.genshinImpactFolder) { - handleGenshinFolderNotSet() + if (!config.gamefolder) { + handleGameNotSet() } if (!config.serverFolder) { diff --git a/resources/js/translation.js b/resources/js/translation.js index 80644f9..712053d 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -32,7 +32,7 @@ async function doTranslation() { set('serverLaunch', localeObj.launchLocalServer) // File select buttons - set('genshinFolderSet', localeObj.genshinFolderSet) + set('gameFolderSet', localeObj.gameFolderSet) set('grasscutterFileSet', localeObj.grasscutterFileSet) // Private options diff --git a/resources/style/index.css b/resources/style/index.css index e7d2b6c..8f8c57d 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -304,7 +304,7 @@ body { height: 10%; } -#genshinPath, #serverPath { +#gamePath, #serverPath { color: white; font-size: 14px; } From 5f4a4b2aaeb4419691470476dd88e90b0e814aea Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 21:27:39 -0700 Subject: [PATCH 043/248] Fix incorrect command (?) --- scripts/killswitch.cmd | 10 ++++----- scripts/private_server_launch.cmd | 35 ++++++++++++++++++------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/scripts/killswitch.cmd b/scripts/killswitch.cmd index 9c1465f..af9e60e 100644 --- a/scripts/killswitch.cmd +++ b/scripts/killswitch.cmd @@ -23,10 +23,10 @@ if "%PROXY_IP%" EQU "localhost" ( :loop :: Check if the game is even running - @rem QPROCESS "%GAME_EXE_NAME%">NUL - @rem IF %ERRORLEVEL% NEQ 0 ( - @rem exit /b - @rem ) + :: tasklist /fi "ImageName eq %GAME_EXE_NAME%" /fo csv 2>NUL | find /I "%GAME_EXE_NAME%.exe">NUL + :: IF %ERRORLEVEL% NEQ 0 ( + :: exit /b + :: ) :: Check if the proxy server process is running :: https://stackoverflow.com/questions/162291/how-to-check-if-a-process-is-running-via-a-batch-script @@ -87,6 +87,6 @@ if "%PROXY_IP%" EQU "localhost" ( :: Reconnect to the WiFi netsh wlan connect name="%WIFI%" - taskkill /f /fi "WINDOWTITLE eq Administrator: PS Killswitch" + :: taskkill /f /fi "WINDOWTITLE eq Administrator: PS Killswitch" exit \ No newline at end of file diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 1a15d66..50315bf 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -1,4 +1,4 @@ -@echo off +:: @echo off :: Ensure admin >nul 2>&1 reg query "HKU\S-1-5-19" || ( @@ -32,7 +32,7 @@ start "Proxy Server" %ORIGIN%/ext/mitmdump.exe -s "%ORIGIN%/proxy/proxy.py" --ss echo Opening %GAME_PATH% -:: Allow the proxy server to create the certificates +:: Allow the proxy server to open fully ping 127.0.0.1 -n 5 > nul for %%A in ("%GAME_PATH%") do ( @@ -52,21 +52,26 @@ if "%ENABLE_KILLSWITCH%" EQU "true" ( :: On exit clean proxy stuff :EXIT -if "%PROXY%" == "" ( +echo Exiting... + +if "%PROXY%" EQU "" ( echo Proxy not started, no need to clean up. -) else ( - :: Clean proxy settings - echo Cleaning up proxy settings - reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /t REG_DWORD /d "%ORIG_PROXY_ENABLE%" /f >nul 2>nul - reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /d "%ORIG_PROXY_SERVER%" /f >nul 2>nul - :: Kill proxy server - taskkill /f /im mitmdump.exe + exit /b +) - echo Done! See you next time! +:: Clean proxy settings +echo Cleaning up proxy settings... +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /t REG_DWORD /d "%ORIG_PROXY_ENABLE%" /f >nul 2>nul +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /d "%ORIG_PROXY_SERVER%" /f >nul 2>nul - timeout /t 2 /nobreak >nul - taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" +:: Kill proxy server +taskkill /f /im mitmdump.exe - exit /b -) \ No newline at end of file +echo Done! See you next time! + +timeout /t 2 /nobreak >nul + +:: taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" + +exit /b \ No newline at end of file From 7734fbb278d8a4457529a7acab06b0181298988e Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 21:29:48 -0700 Subject: [PATCH 044/248] echo off --- scripts/private_server_launch.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 50315bf..a8a77cf 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -1,4 +1,4 @@ -:: @echo off +@echo off :: Ensure admin >nul 2>&1 reg query "HKU\S-1-5-19" || ( From e4cc000117753d3e8dd4086f2b8993d683989860 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 21:31:52 -0700 Subject: [PATCH 045/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index b589907..46e2dd1 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.4", + "version": "0.6.5", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 15fd24d..50d63c9 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.4", + "version": "0.6.5", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 66eb121..906838d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.6.4", + "version": "0.6.5", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 71652e3c712ed8bb8ae988cd4121e41159580c5b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 23 Apr 2022 21:36:39 -0700 Subject: [PATCH 046/248] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 07def0f..67d0f50 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ 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] Kill switch script (optional) * [x] Automatically run `install.cmd` when opening for the first time + * [ ] 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!) * [ ] Optional username/password creation for servers before entering (not implemented in Grasscutter yet) * [ ] Platform detection and bash scripts From 9adb023f7cea4f3892bea7c7e66017d9b6d3a496 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 00:32:17 -0700 Subject: [PATCH 047/248] specify port when connecitng --- languages/en.json | 1 + proxy/proxy.py | 9 +++++++++ resources/index.html | 1 + resources/js/index.js | 5 +++-- resources/js/translation.js | 2 ++ resources/style/index.css | 4 ++++ scripts/killswitch.cmd | 2 +- scripts/private_server_launch.cmd | 13 +++++++------ 8 files changed, 28 insertions(+), 9 deletions(-) diff --git a/languages/en.json b/languages/en.json index cbf092b..195be63 100644 --- a/languages/en.json +++ b/languages/en.json @@ -11,6 +11,7 @@ "folderNotSet": "Not set", "ipPlaceholder": "IP Address", + "portPlaceholder": "Port (optional)", "noFavorites": "No favorites set", "settingsTitle": "Settings", diff --git a/proxy/proxy.py b/proxy/proxy.py index 581b3cb..c2a0b70 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -34,9 +34,17 @@ class MlgmXyysd_Anime_Game_Proxy: help = "IP address to replace", ) + loader.add_option( + name = "port", + typespec = int, + default = 80, + help = "Port to replace", + ) + def request(self, flow: http.HTTPFlow) -> None: # This can also be replaced with another IP address. REMOTE_HOST = ctx.options.ip + REMOTE_PORT = ctx.options.port LIST_DOMAINS = [ "api-os-takumi.mihoyo.com", @@ -75,6 +83,7 @@ class MlgmXyysd_Anime_Game_Proxy: if flow.request.host in LIST_DOMAINS: flow.request.host = REMOTE_HOST + flow.request.port = REMOTE_PORT addons = [ MlgmXyysd_Anime_Game_Proxy() diff --git a/resources/index.html b/resources/index.html index 57cc2a6..123f9ac 100644 --- a/resources/index.html +++ b/resources/index.html @@ -103,6 +103,7 @@
+
diff --git a/resources/js/index.js b/resources/js/index.js index 6b68a7e..ceafa16 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -370,17 +370,18 @@ async function launchOfficial() { */ async function launchPrivate() { const ip = document.getElementById('ip').value || 'localhost' + const port = document.getElementById('port').value || '443' const config = await getCfg() - console.log('connecting to ' + ip) + console.log('connecting to ' + ip + ':' + port) // Set the last connect config.lastConnect = ip Neutralino.storage.setData('config', JSON.stringify(config)) // Pass IP and game folder to the private server launcher - Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch}`).catch(e => console.log(e)) + Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch}`).catch(e => console.log(e)) } async function launchLocalServer() { diff --git a/resources/js/translation.js b/resources/js/translation.js index 712053d..f9f6c8f 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -13,6 +13,7 @@ async function doTranslation() { } const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) + const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) localeObj = JSON.parse(localization) const set = (id, localeString) => document.getElementById(id).innerHTML = localeString || 'UNKNOWN' @@ -37,6 +38,7 @@ async function doTranslation() { // Private options document.querySelector('#ip').placeholder = localeObj.ipPlaceholder + document.querySelector('#port').placeholder = localeObj.portPlaceholder // Settings set('fullSettingsTitle', localeObj.settingsTitle) diff --git a/resources/style/index.css b/resources/style/index.css index 8f8c57d..7a33d47 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -351,6 +351,10 @@ body { display: block; } +#port { + width: 12%; +} + #secondPanel input { margin-bottom: 4px; height: 20px; diff --git a/scripts/killswitch.cmd b/scripts/killswitch.cmd index af9e60e..4c78b4f 100644 --- a/scripts/killswitch.cmd +++ b/scripts/killswitch.cmd @@ -87,6 +87,6 @@ if "%PROXY_IP%" EQU "localhost" ( :: Reconnect to the WiFi netsh wlan connect name="%WIFI%" - :: taskkill /f /fi "WINDOWTITLE eq Administrator: PS Killswitch" + taskkill /f /fi "WINDOWTITLE eq Administrator: PS Killswitch" exit \ No newline at end of file diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index a8a77cf..4993393 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -3,7 +3,7 @@ :: Ensure admin >nul 2>&1 reg query "HKU\S-1-5-19" || ( set params = %*:"="""% - cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 "%2" ""%cd%"" %4", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) + cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 "%3" ""%cd%"" %5", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) ) :: Use to force task kill @@ -12,11 +12,12 @@ title PS Launcher Script echo Starting Proxy Server set IP=%1 -set GAME_PATH=%2 +set PORT=%2 +set GAME_PATH=%3 set GAME_PATH=%GAME_PATH:"=% -set ORIGIN=%3 +set ORIGIN=%4 set ORIGIN=%ORIGIN:"=% -set ENABLE_KILLSWITCH=%4 +set ENABLE_KILLSWITCH=%5 set PROXY=true @rem Store original proxy settings @@ -28,7 +29,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 :: Start proxy server -start "Proxy Server" %ORIGIN%/ext/mitmdump.exe -s "%ORIGIN%/proxy/proxy.py" --ssl-insecure --set ip=%IP% +start "Proxy Server" %ORIGIN%/ext/mitmdump.exe -s "%ORIGIN%/proxy/proxy.py" --ssl-insecure --set ip=%IP% --set port=%PORT% echo Opening %GAME_PATH% @@ -72,6 +73,6 @@ echo Done! See you next time! timeout /t 2 /nobreak >nul -:: taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" +taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" exit /b \ No newline at end of file From a945e84439c68fbc222cc28b433c9beb94d276e1 Mon Sep 17 00:00:00 2001 From: Artem Fitiskin Date: Sun, 24 Apr 2022 12:45:29 +0300 Subject: [PATCH 048/248] #10 New Russian language --- languages/ru.json | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 languages/ru.json diff --git a/languages/ru.json b/languages/ru.json new file mode 100644 index 0000000..5905a58 --- /dev/null +++ b/languages/ru.json @@ -0,0 +1,40 @@ +{ + "fullLangName": "Русский", + "appName": "GrassClipper", + + "playOfficial": "Официальная игра", + "playPrivate": "Grasscutter", + "launchLocalServer": "Локальный сервер", + + "gameFolderSet": "Папка с игрой", + "grasscutterFileSet": "Путь до файла \"Grasscutter\" (.jar)", + "folderNotSet": "Папка не выбрана", + + "ipPlaceholder": "IP-адрес", + "portPlaceholder": "Порт (опционально)", + "noFavorites": "В избранном пусто", + + "settingsTitle": "Настройки", + "scriptsSectionTitle": "Скрипты", + "killswitchOption": "Аварийное прерывание", + "killswitchSubtitle": "Опция для тех, кто очень беспокоится по поводу банов. Снимает задачу с игрой *и разрывает ваше интернет-соединение*, когда возникают неполадки с прокси", + "proxyOption": "Прокси", + "proxySubtitle": "Запустить установочный скрипт для настройки прокси-сервера", + "updateOption": "Обновление", + "updateSubtitle": "Автоматическое обновление временно отключено. Вы можете проверить наличие обновлений на GitHub", + "languageOption": "Язык", + "languageSubtitle": "Выберите предпочитаемый язык приложения", + "enableServerLauncherOption": "Включить запуск сервера", + "enableServerLauncherSubtitle": "Использовать лаунчер для локального запуска Grasscutter", + + "introSen1": "Кажется, вы впервые запустили GrassClipper!", + "introSen2": "Добро пожаловать, мы рады вас видеть! :)", + "introSen3": "Запустить установщик прокси?", + "introSen4": "(необходим для подключения к приватным серверам)", + + "proxyInstallBtn": "Установить", + "proxyInstallDeny": "Нет, спасибо", + + "gameFolderDialog": "Выбор папки с игрой", + "grasscutterFileDialog": "Выбор пути до файла Grasscutter (.jar)" +} From 60184c30b1a71e804a3ad418574a22b604e9e10f Mon Sep 17 00:00:00 2001 From: nuoxian <56551535+nuoxianCN@users.noreply.github.com> Date: Sun, 24 Apr 2022 23:52:57 +0800 Subject: [PATCH 049/248] Modify language file --- languages/zh.json | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/languages/zh.json b/languages/zh.json index 1791328..7cea99e 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -1,39 +1,39 @@ { - "fullLangName": "Simplified Chinese (中国人)", + "fullLangName": "Chinese", "appName": "GrassClipper启动器", - "playOfficial": "游玩官方服务器", - "playPrivate": "在 Grasscutter 上播放", + "playOfficial": "启动官方服务器", + "playPrivate": "启动私人服务器", "launchLocalServer": "启动本地服务器", - "gameFolderSet": "选择 \"原神\" 文件夹", + "gameFolderSet": "选择 \"Genshin Impact Game\" 文件夹", "grasscutterFileSet": "选择 \"Grasscutter\" .jar 文件", - "folderNotSet": "没有设置原神文件夹或Grasscutter文件", + "folderNotSet": "没有选择Genshin Impact Game文件夹或Grasscutter.jar文件", - "ipPlaceholder": "IP地址", - "noFavorites": "没有收藏", + "ipPlaceholder": "服务器IP地址", + "noFavorites": "没有收藏任何IP地址", "settingsTitle": "设置", - "scriptsSectionTitle": "进程", + "scriptsSectionTitle": "程序设置", "killswitchOption": "杀死服务进程", - "killswitchSubtitle": "仅为那些害怕被封号的人准备。此选项可以结束游戏进程(还可以让你断网,如果修改了代理设置的话)。", - "proxyOption": "代理", - "proxySubtitle": "通过安装脚本安装代理服务器。", - "updateOption": "更新", + "killswitchSubtitle": "为那些害怕被封号的人准备。启用此选项可以结束游戏进程(还可以让你断网,如果修改了代理设置的话)。", + "proxyOption": "安装代理服务器", + "proxySubtitle": "通过批处理文件 (install.cmd) 以安装代理服务器。", + "updateOption": "更新启动器", "updateSubtitle": "自动更新暂时不可用。查看GitHub以获取最新的Release。", - "languageOption": "语言", - "languageSubtitle": "选择你最熟悉的语言!", + "languageOption": "设置启动器语言", + "languageSubtitle": "选择你熟悉的语言以应用GrassClipper启动器!", "enableServerLauncherOption": "启用本地服务器", - "enableServerLauncherSubtitle": "启动器内为你显示启动本地服务器选项。", + "enableServerLauncherSubtitle": "在启动器内显示启动本地服务器选项。", "introSen1": "看来这是你第一次使用GrassClipper启动器!", - "introSen2": "首先,欢迎你使用GrassClipper启动器,其次很高兴在这里见到你! :)", - "introSen3": "是否要运行代理安装程序?", - "introSen4": "(需要连接到私人服务器)", + "introSen2": "首先,欢迎你使用GrassClipper启动器,其次很高兴见到你! :)", + "introSen3": "是否要运行安装脚本来安装代理服务器?", + "introSen4": "(此选项仅提供给需要连接到私人服务器的用户)", "proxyInstallBtn": "安装", "proxyInstallDeny": "不用了,谢谢", - "gameFolderDialog": "选择原神文件夹", - "grasscutterFileDialog": "选择Grasscutter服务器jar文件" + "gameFolderDialog": "选择Genshin Impact Game文件夹", + "grasscutterFileDialog": "选择Grasscutter.jar文件" } From cd407671b3bdd249a178c9ab5bb371ee74e8f4cb Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 13:11:35 -0700 Subject: [PATCH 050/248] Add traditional chinese language --- languages/zh-tw.json | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 languages/zh-tw.json diff --git a/languages/zh-tw.json b/languages/zh-tw.json new file mode 100644 index 0000000..fb4437e --- /dev/null +++ b/languages/zh-tw.json @@ -0,0 +1,39 @@ +{ + "fullLangName": "Traditional Chinese", + "appName": "GrassClipper啟動器", + + "playOfficial": "啟動官方伺服器", + "playPrivate": "啟動私人伺服器", + "launchLocalServer": "啟動本地伺服器", + + "gameFolderSet": "設定 \"Genshin Impact game\" 資料夾", + "grasscutterFileSet": "設定 \"Grasscutter\" .jar 檔案", + "folderNotSet": "尚未設定Genshin Impact game資料夾", + + "ipPlaceholder": "IP地址", + "noFavorites": "没有收藏", + + "settingsTitle": "設定", + "scriptsSectionTitle": "進程", + "killswitchOption": "終止服務進程", + "killswitchSubtitle": "這是給對於封號非常敏感的人們,啟用此選項將會在你Proxy中發生任何錯誤時會終止你的遊戲(還有你的網路。)", + "proxyOption": "Proxy", + "proxySubtitle": "通過安裝腳本來安裝Proxy伺服器。", + "updateOption": "更新", + "updateSubtitle": "自動更新暫時不可用。查看GitHub以獲取最新的Release。", + "languageOption": "語言", + "languageSubtitle": "選擇你最熟悉的語言!", + "enableServerLauncherOption": "啟用本地伺服器", + "enableServerLauncherSubtitle": "啟動器內將會為你顯示啟動本地伺服器選項。", + + "introSen1": "看來這是你第一次使用GrassClipper啟動器!", + "introSen2": "首先,歡迎你使用GrassClipper啟動器,其次很高興在這裡見到你! :)", + "introSen3": "是否要運行Proxy安裝程序?", + "introSen4": "(需要連接到私人伺服器)", + + "proxyInstallBtn": "安装", + "proxyInstallDeny": "不用了,謝謝。", + + "gameFolderDialog": "選擇Genshin Impact game資料夾", + "grasscutterFileDialog": "選擇Grasscutter伺服器jar檔案" +} \ No newline at end of file From a395055dc55e2f9a5fb60924dc04d3d71940aec7 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 13:13:27 -0700 Subject: [PATCH 051/248] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 67d0f50..b993ed0 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,14 @@ The launcher most likely did not close correctly, and was unable to clean your p Thank you to everyone who has provided translations! <3 * ZH - nuoxianCN & Scirese +* ZH-TW - Kimi * PT-BR - na.na * VIE - labalityowo * ID - Iqrar99 * FR - linsorak & memetrollsXD * ES - memetrollsXD * ND - memetrollsXD +* RU - fitiskin # Screenshots From 3fb48582fdee6d47b03002f21129a653ccf6ca22 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 13:25:39 -0700 Subject: [PATCH 052/248] server installation watcher --- resources/js/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resources/js/index.js b/resources/js/index.js index ceafa16..d288dac 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -275,6 +275,14 @@ async function closeFirstTimePopup() { async function runInstallScript() { Neutralino.os.execCommand(`${NL_CWD}/scripts/install.cmd "${NL_CWD}"`) + // Create an interval that will check for the proxy server installation finish + const interval = setInterval(async () => { + if (await proxyIsInstalled()) { + clearInterval(interval) + enableButtons() + } + }, 1000) + closeFirstTimePopup() } From 30aeba0794ad61453015b7f277eb356bb8314322 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 16:06:25 -0700 Subject: [PATCH 053/248] full port changing support --- resources/js/index.js | 12 ++++++++++-- resources/js/options.js | 9 ++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index d288dac..12e4f64 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -164,9 +164,12 @@ async function setBackgroundImage() { */ async function handleFavoriteInput() { const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value const ipArr = await getFavIps() - if (!ip || !ipArr.includes(ip)) { + const addr = `${ip}:${port}` + + if (!ip || !ipArr.includes(addr)) { document.querySelector('#star').src = 'icons/star_empty.svg' } else { document.querySelector('#star').src = 'icons/star_filled.svg' @@ -180,13 +183,18 @@ async function handleFavoriteInput() { */ async function setIp(ip) { const ipInput = document.querySelector('#ip') + const portInput = document.querySelector('#port') + + const parseIp = ip.split(':')[0] + const parsePort = ip.split(':')[1] // Set star if (ip) { document.querySelector('#star').src = 'icons/star_filled.svg' } - ipInput.value = ip + ipInput.value = parseIp + portInput.value = parsePort } /** diff --git a/resources/js/options.js b/resources/js/options.js index 65eb8a1..43c227b 100644 --- a/resources/js/options.js +++ b/resources/js/options.js @@ -77,8 +77,11 @@ async function handleLanguageChange(elm) { */ async function setFavorite() { const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value const ipArr = await getFavIps() + const addr = `${ip}:${port}` + // Set star icon const star = document.querySelector('#star') @@ -86,13 +89,13 @@ async function handleLanguageChange(elm) { star.src = 'icons/star_empty.svg' // remove from list - ipArr.splice(ipArr.indexOf(ip), 1) + ipArr.splice(ipArr.indexOf(addr), 1) } else { star.src = 'icons/star_filled.svg' // add to list - if (ip && !ipArr.includes(ip)) { - ipArr.push(ip) + if (ip && !ipArr.includes(addr)) { + ipArr.push(addr) } } From f4bfb34f47db69534bb8ab6e3516c80dc12d6c56 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 16:17:23 -0700 Subject: [PATCH 054/248] https options --- proxy/proxy.py | 11 +++++++++++ resources/index.html | 10 ++++++++++ resources/js/helpers.js | 3 ++- resources/js/index.js | 2 ++ resources/js/options.js | 11 +++++++++++ resources/style/index.css | 2 +- 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/proxy/proxy.py b/proxy/proxy.py index c2a0b70..fc7cc25 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -41,6 +41,13 @@ class MlgmXyysd_Anime_Game_Proxy: help = "Port to replace", ) + loader.add_option( + name = "use_https", + typespec = bool, + default = True, + help = "Use HTTPS", + ) + def request(self, flow: http.HTTPFlow) -> None: # This can also be replaced with another IP address. REMOTE_HOST = ctx.options.ip @@ -82,6 +89,10 @@ class MlgmXyysd_Anime_Game_Proxy: ] if flow.request.host in LIST_DOMAINS: + if ctx.options.use_https: + flow.request.scheme = "https" + else: + flow.request.scheme = "http" flow.request.host = REMOTE_HOST flow.request.port = REMOTE_PORT diff --git a/resources/index.html b/resources/index.html index 123f9ac..708db52 100644 --- a/resources/index.html +++ b/resources/index.html @@ -77,6 +77,16 @@ Select your language!
+
+
+ Use HTTPS + + +
+ + Choose between using HTTPS or HTTP. + +
diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 6d83690..03a57a8 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -10,7 +10,8 @@ lastConnect: '', enableKillswitch: false, serverLaunchPanel: false, - language: 'en' + language: 'en', + useHttps: true, } const cfgStr = await Neutralino.storage.getData('config').catch(e => { // The data isn't set, so this is our first time opening diff --git a/resources/js/index.js b/resources/js/index.js index 12e4f64..be5639e 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -249,9 +249,11 @@ async function openSettings() { // Fill setting options with what is currently set in config const killSwitch = document.querySelector('#killswitchOption') const serverLaunch = document.querySelector('#serverLaunchOption') + const httpsCheckbox = document.querySelector('#httpsOption') killSwitch.checked = config.enableKillswitch serverLaunch.checked = config.serverLaunchPanel + httpsCheckbox.checked = config.useHttps // Load languages getLanguages() diff --git a/resources/js/options.js b/resources/js/options.js index 43c227b..9d0ec2a 100644 --- a/resources/js/options.js +++ b/resources/js/options.js @@ -69,6 +69,17 @@ async function handleLanguageChange(elm) { window.location.reload() } +/** + * Toggle the use of HTTPS + */ + async function toggleKillSwitch() { + const httpsCheckbox = document.querySelector('#httpsOption') + const config = await getCfg() + + config.useHttps = httpsCheckbox.checked + + Neutralino.storage.setData('config', JSON.stringify(config)) +} /** * Add the current value of the IP input to the favorites list diff --git a/resources/style/index.css b/resources/style/index.css index 7a33d47..0888f84 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -51,7 +51,7 @@ body { #settingsPanel { width: 35%; - height: 70%; + height: 80%; } #fullSettingsTitle { From 854e1b2242ab54cfb92adf4b62898d2cf4d423de Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 16:22:23 -0700 Subject: [PATCH 055/248] fix https setting --- proxy/proxy.py | 2 ++ resources/js/index.js | 2 +- resources/js/options.js | 2 +- scripts/private_server_launch.cmd | 11 ++++++----- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/proxy/proxy.py b/proxy/proxy.py index fc7cc25..5c4a0b8 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -52,6 +52,8 @@ class MlgmXyysd_Anime_Game_Proxy: # This can also be replaced with another IP address. REMOTE_HOST = ctx.options.ip REMOTE_PORT = ctx.options.port + + print(ctx.options.use_https) LIST_DOMAINS = [ "api-os-takumi.mihoyo.com", diff --git a/resources/js/index.js b/resources/js/index.js index be5639e..898d5d4 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -399,7 +399,7 @@ async function launchPrivate() { Neutralino.storage.setData('config', JSON.stringify(config)) // Pass IP and game folder to the private server launcher - Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch}`).catch(e => console.log(e)) + Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch}`).catch(e => console.log(e)) } async function launchLocalServer() { diff --git a/resources/js/options.js b/resources/js/options.js index 9d0ec2a..1b74f53 100644 --- a/resources/js/options.js +++ b/resources/js/options.js @@ -72,7 +72,7 @@ async function handleLanguageChange(elm) { /** * Toggle the use of HTTPS */ - async function toggleKillSwitch() { + async function toggleHttps() { const httpsCheckbox = document.querySelector('#httpsOption') const config = await getCfg() diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 4993393..834e262 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -3,7 +3,7 @@ :: Ensure admin >nul 2>&1 reg query "HKU\S-1-5-19" || ( set params = %*:"="""% - cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 "%3" ""%cd%"" %5", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) + cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) ) :: Use to force task kill @@ -13,11 +13,12 @@ echo Starting Proxy Server set IP=%1 set PORT=%2 -set GAME_PATH=%3 +set USE_HTTPS=%3 +set GAME_PATH=%4 set GAME_PATH=%GAME_PATH:"=% -set ORIGIN=%4 +set ORIGIN=%5 set ORIGIN=%ORIGIN:"=% -set ENABLE_KILLSWITCH=%5 +set ENABLE_KILLSWITCH=%6 set PROXY=true @rem Store original proxy settings @@ -29,7 +30,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 :: Start proxy server -start "Proxy Server" %ORIGIN%/ext/mitmdump.exe -s "%ORIGIN%/proxy/proxy.py" --ssl-insecure --set ip=%IP% --set port=%PORT% +start "Proxy Server" %ORIGIN%/ext/mitmdump.exe -s "%ORIGIN%/proxy/proxy.py" --ssl-insecure --set ip=%IP% --set port=%PORT% --set use_https=%USE_HTTPS% echo Opening %GAME_PATH% From d9179d6be2f03c5edfeb35e6027f5a5368fe57b8 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 16:29:59 -0700 Subject: [PATCH 056/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 46e2dd1..9fe0cae 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.5", + "version": "0.7.0", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 50d63c9..dcfc6bb 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.6.5", + "version": "0.7.0", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 906838d..030f47a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.6.5", + "version": "0.7.0", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From d8e18b4a46d94ef1e83e9950b1d2186e4f284435 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 16:36:15 -0700 Subject: [PATCH 057/248] add additional strings to english locale --- languages/en.json | 2 ++ resources/js/translation.js | 47 ++++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/languages/en.json b/languages/en.json index 195be63..f421003 100644 --- a/languages/en.json +++ b/languages/en.json @@ -26,6 +26,8 @@ "languageSubtitle": "Select your language!", "enableServerLauncherOption": "Enable Server Launcher", "enableServerLauncherSubtitle": "Enable to server launcher tile for launching a local Grasscutter instance.", + "httpsOption": "Use HTTPS", + "httpsSubtitle": "Choose between using HTTPS or HTTP.", "introSen1": "Looks like this is your first time opening GrassClipper!", "introSen2": "First of all, welcome, happy to see you here! :)", diff --git a/resources/js/translation.js b/resources/js/translation.js index f9f6c8f..6f417cc 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -14,9 +14,10 @@ async function doTranslation() { const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) + engLocaleObj = JSON.parse(engLocale) localeObj = JSON.parse(localization) - const set = (id, localeString) => document.getElementById(id).innerHTML = localeString || 'UNKNOWN' + const set = (id, localeString) => document.getElementById(id).innerHTML = localeObj[localeString] || engLocaleObj[localeString] // Begin filling in values set('titleSection', localeObj.appName) @@ -28,33 +29,35 @@ async function doTranslation() { document.querySelector('#titleSection').appendChild(verSpan) // Play buttons - set('playOfficial', localeObj.playOfficial) - set('playPrivate', localeObj.playPrivate) - set('serverLaunch', localeObj.launchLocalServer) + set('playOfficial', 'playOfficial') + set('playPrivate', 'playPrivate') + set('serverLaunch', 'launchLocalServer') // File select buttons - set('gameFolderSet', localeObj.gameFolderSet) - set('grasscutterFileSet', localeObj.grasscutterFileSet) + set('gameFolderSet', 'gameFolderSet') + set('grasscutterFileSet', 'grasscutterFileSet') // Private options document.querySelector('#ip').placeholder = localeObj.ipPlaceholder document.querySelector('#port').placeholder = localeObj.portPlaceholder // Settings - set('fullSettingsTitle', localeObj.settingsTitle) - set('scriptsTitle', localeObj.scriptsSectionTitle) - set('killswitchTitle', localeObj.killswitchOption) - set('killswitchSubtitle', localeObj.killswitchSubtitle) - set('proxyTitle', localeObj.proxyOption) - set('proxyInstall', localeObj.proxyInstallBtn) - set('proxySubtitle', localeObj.proxySubtitle) - set('updateBtn', localeObj.updateOption) - set('updateTitle', localeObj.updateOption) - set('updateSubtitle', localeObj.updateSubtitle) - set('languageTitle', localeObj.languageOption) - set('languageSubtitle', localeObj.languageSubtitle) - set('serverLaunchTitle', localeObj.enableServerLauncherOption) - set('serverSubtitle', localeObj.enableServerLauncherSubtitle) + set('fullSettingsTitle', 'settingsTitle') + set('scriptsTitle', 'scriptsSectionTitle') + set('killswitchTitle', 'killswitchOption') + set('killswitchSubtitle', 'killswitchSubtitle') + set('proxyTitle', 'proxyOption') + set('proxyInstall', 'proxyInstallBtn') + set('proxySubtitle', 'proxySubtitle') + set('updateBtn', 'updateOption') + set('updateTitle', 'updateOption') + set('updateSubtitle', 'updateSubtitle') + set('languageTitle', 'languageOption') + set('languageSubtitle', 'languageSubtitle') + set('serverLaunchTitle', 'enableServerLauncherOption') + set('serverSubtitle', 'enableServerLauncherSubtitle') + set('httpsOption', 'httpsOption') + set('httpsSubtitle', 'httpsSubtitle') // Intro popup const popup = document.getElementById('firstTimeNotice') @@ -70,6 +73,6 @@ async function doTranslation() { introSpan.innerHTML += localeObj.introSen3 + '
' introSpan.innerHTML += localeObj.introSen4 + '
' - set('firstTimeInstallBtn', localeObj.proxyInstallBtn) - set('firstTimeDenyBtn', localeObj.proxyInstallDeny) + set('firstTimeInstallBtn', 'proxyInstallBtn') + set('firstTimeDenyBtn', 'proxyInstallDeny') } \ No newline at end of file From 5e56b81032e0a4b1be9a75445b3a7de31d9b31ef Mon Sep 17 00:00:00 2001 From: nuoxian <56551535+nuoxianCN@users.noreply.github.com> Date: Mon, 25 Apr 2022 08:55:53 +0800 Subject: [PATCH 058/248] Added new translation and fixed some problems --- languages/zh.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/languages/zh.json b/languages/zh.json index 7cea99e..e1f6008 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -1,5 +1,5 @@ { - "fullLangName": "Chinese", + "fullLangName": "Simplified Chinese", "appName": "GrassClipper启动器", "playOfficial": "启动官方服务器", @@ -11,6 +11,7 @@ "folderNotSet": "没有选择Genshin Impact Game文件夹或Grasscutter.jar文件", "ipPlaceholder": "服务器IP地址", + "portPlaceholder": "端口(可选)", "noFavorites": "没有收藏任何IP地址", "settingsTitle": "设置", @@ -25,6 +26,8 @@ "languageSubtitle": "选择你熟悉的语言以应用GrassClipper启动器!", "enableServerLauncherOption": "启用本地服务器", "enableServerLauncherSubtitle": "在启动器内显示启动本地服务器选项。", + "httpsOption": "使用 HTTPS", + "httpsSubtitle": "在使用http(s)协议之间选择,此选项适用于私人服务器。", "introSen1": "看来这是你第一次使用GrassClipper启动器!", "introSen2": "首先,欢迎你使用GrassClipper启动器,其次很高兴见到你! :)", From daa2d4bf9eaafc8ed6a5435c1f1e1d57886d7674 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 20:01:52 -0700 Subject: [PATCH 059/248] fix 'Use HTTPS' being untranslate-able --- resources/js/translation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/translation.js b/resources/js/translation.js index 6f417cc..e0446f6 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -56,7 +56,7 @@ async function doTranslation() { set('languageSubtitle', 'languageSubtitle') set('serverLaunchTitle', 'enableServerLauncherOption') set('serverSubtitle', 'enableServerLauncherSubtitle') - set('httpsOption', 'httpsOption') + set('httpsTitle', 'httpsOption') set('httpsSubtitle', 'httpsSubtitle') // Intro popup From d50b4a1189f0f700c301780db27e01e01ed239f6 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 20:06:21 -0700 Subject: [PATCH 060/248] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b993ed0..c5f6cff 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,9 @@ Below are some scenarios you may encounter and their solutions. Encountering a white screen? [Ensure WebView2 is installed](https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/#download) +You may also want to run this command as administrator: +`CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy"` + ### My Discord is not letting me send messages or load images/My Youtube is acting strange! Discord/YouTube (plus surely some others) does not seem to be a fan of the proxy server. You may need to disable it by either closing mitmdump or by disabling your proxy in the Windows proxy settings. From b724b19f9424851530f39a00c0e00450e36e0f5d Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 22:03:24 -0700 Subject: [PATCH 061/248] fix bg position for chrome mode --- neutralino.config.json | 18 +++++++++++++++--- resources/style/index.css | 2 +- scripts/install.cmd | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/neutralino.config.json b/neutralino.config.json index dcfc6bb..d780cfd 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -45,9 +45,21 @@ ] }, "chrome": { - "width": 1000, - "height": 800, - "args": "--user-agent=\"Neutralinojs chrome mode\"" + "title": "GrassClipper", + "width": 1280, + "height": 720, + "minWidth": 400, + "minHeight": 200, + "fullScreen": false, + "alwaysOnTop": false, + "icon": "/resources/icons/appIcon.png", + "enableInspector": true, + "borderless": true, + "maximize": false, + "hidden": false, + "resizable": false, + "exitProcessOnClose": true, + "args": "--user-agent=\"Neutralinojs chrome mode\" --disable-web-security" } }, "cli": { diff --git a/resources/style/index.css b/resources/style/index.css index 0888f84..a3b2ec6 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -336,7 +336,7 @@ body { } #firstPanel { - background-position: -340px; + background-position: -250px; } /* Move the first official button to the position on the png */ diff --git a/scripts/install.cmd b/scripts/install.cmd index df02932..3d02dc1 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -45,6 +45,7 @@ echo Adding ceritifcate... echo Certificate install failed, ensure the script is running as Administrator and that the path "%USERPROFILE%\.mitmproxy" exists, ) + echo Done! You can now open GrassClipper.exe! pause From ba2a255a48b2324d4699bec0f25331fc78a81148 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 22:26:31 -0700 Subject: [PATCH 062/248] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index c5f6cff..a33c147 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Grasscutter launcher for easily switching between Official and Private servers * [TODO](#todo) * [Common Problems](#having-problems) * [White Screen Fix](#white-screen-fix) + * [Infinite CMD Windows](#infinite-cmd-windows) * [Broken Discord/Youtube](#my-discord-is-not-letting-me-send-messages-or-load-images-my-youtube-is-acting-strange) * [No internet](#i-have-no-internet-after-closing-everything-restarting-my-pc) * [Languages and Translation Credits](#available-languages-and-translation-credits) @@ -62,6 +63,10 @@ Encountering a white screen? [Ensure WebView2 is installed](https://developer.mi You may also want to run this command as administrator: `CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy"` +### Infinite CMD Windows + +If you are getting infinite CMD windows for any of the scripts (such as the proxy installation, or private server start), ensure you have UAC (user access control) set to any option that requires asking. Ensure your user account can open things as Admin. + ### My Discord is not letting me send messages or load images/My Youtube is acting strange! Discord/YouTube (plus surely some others) does not seem to be a fan of the proxy server. You may need to disable it by either closing mitmdump or by disabling your proxy in the Windows proxy settings. From 98acd412cec2aad25a21d687f107070bfa8c2baa Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 22:40:03 -0700 Subject: [PATCH 063/248] fix title and close tab if in browser mode --- resources/js/helpers.js | 2 ++ resources/js/translation.js | 2 +- scripts/install.cmd | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 03a57a8..7d53e14 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -87,4 +87,6 @@ async function proxyIsInstalled() { function closeWin() { console.log('close') Neutralino.app.exit() + + window.close() } diff --git a/resources/js/translation.js b/resources/js/translation.js index e0446f6..aa8fbf7 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -20,7 +20,7 @@ async function doTranslation() { const set = (id, localeString) => document.getElementById(id).innerHTML = localeObj[localeString] || engLocaleObj[localeString] // Begin filling in values - set('titleSection', localeObj.appName) + set('titleSection', 'appName') const verSpan = document.createElement('span') verSpan.id = 'version' diff --git a/scripts/install.cmd b/scripts/install.cmd index 3d02dc1..df02932 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -45,7 +45,6 @@ echo Adding ceritifcate... echo Certificate install failed, ensure the script is running as Administrator and that the path "%USERPROFILE%\.mitmproxy" exists, ) - echo Done! You can now open GrassClipper.exe! pause From 730f06b99fa53f0b75618a63011292e174db78df Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 22:44:58 -0700 Subject: [PATCH 064/248] Update README.md --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a33c147..7192fe5 100644 --- a/README.md +++ b/README.md @@ -56,22 +56,31 @@ Grasscutter launcher for easily switching between Official and Private servers Below are some scenarios you may encounter and their solutions. -### White Screen Fix +## White Screen Fix Encountering a white screen? [Ensure WebView2 is installed](https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/#download) You may also want to run this command as administrator: `CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy"` -### Infinite CMD Windows +If all else fails, you can run GrassClipper in `chrome` or `browser` mode. To do so: +* Create a shortcut to `GrassClipper.exe` +* Right click the shortcut, click `properties` +* In the `Target` box, at the very end, add ` --mode=chrome` or ` --mode=browser` + * `chrome` only works if you have Chrome installed, and will create a Chrome window + * `brower` will, you guessed it, open GrassClipper in your default browser +* Click `Ok` +* Run GrassClipper using this shortcut from now on! + +## Infinite CMD Windows If you are getting infinite CMD windows for any of the scripts (such as the proxy installation, or private server start), ensure you have UAC (user access control) set to any option that requires asking. Ensure your user account can open things as Admin. -### My Discord is not letting me send messages or load images/My Youtube is acting strange! +## My Discord is not letting me send messages or load images/My Youtube is acting strange! Discord/YouTube (plus surely some others) does not seem to be a fan of the proxy server. You may need to disable it by either closing mitmdump or by disabling your proxy in the Windows proxy settings. -### I have no internet after closing everything/restarting my PC! +## I have no internet after closing everything/restarting my PC! The launcher most likely did not close correctly, and was unable to clean your proxy settings back to what they were. Disable your proxy in the Windows proxy settings. From 6b718b849b7f0f563401852324f08bbd23008c8b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 23:38:06 -0700 Subject: [PATCH 065/248] fix top bar drag on screens with different pixel ratios --- resources/js/windowDrag.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/resources/js/windowDrag.js b/resources/js/windowDrag.js index 811ca68..b9aa3f5 100644 --- a/resources/js/windowDrag.js +++ b/resources/js/windowDrag.js @@ -1,22 +1,25 @@ // https://stackoverflow.com/questions/67971689/positioning-the-borderless-window-in-neutralino-js // had to use this since the in-built function breaks the close and minimize buttons -let dragging = false, posX, posY; +let dragging = false, ratio = 1, posX, posY; let draggable; -document.addEventListener('DOMContentLoaded', () => { +document.addEventListener('DOMContentLoaded', async () => { draggable = document.getElementById('controlBar'); // Listen to hovers draggable.onmousedown = function (e) { - posX = e.pageX, posY = e.pageY; + ratio = window.devicePixelRatio + + posX = e.pageX * ratio, posY = e.pageY * ratio; dragging = true; } - draggable.onmouseup = function (e) { + // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere + window.onmouseup = function (e) { dragging = false; } document.onmousemove = function (e) { - if (dragging) Neutralino.window.move(e.screenX - posX, e.screenY - posY); + if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY); } }) \ No newline at end of file From 2f4d5fcab23c97e50a57ab67b4c9d761d4a97f00 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 23:55:36 -0700 Subject: [PATCH 066/248] scale favorites list with pixel ratio --- resources/js/index.js | 6 +++--- resources/style/index.css | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index 898d5d4..999614e 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -230,11 +230,11 @@ async function handleFavoriteList() { const transform = window.getComputedStyle(document.querySelector('#ipList')).transform const xy = [ transform.split(',')[4], transform.split(',')[5] ] - let newY = parseInt(xy[1].replace(')', '')) - (27 * ipArr.length) + let newY = (27 * ipArr.length) * window.devicePixelRatio - if (ipArr.length === 0) newY -= 27 + if (ipArr.length === 0 || ipArr.length === 1) newY = 0 - ipList.style.transform = `translate(${xy[0]}px, ${newY}px)` + ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)` } } diff --git a/resources/style/index.css b/resources/style/index.css index a3b2ec6..0e7ba46 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -52,6 +52,7 @@ body { #settingsPanel { width: 35%; height: 80%; + overflow: hidden; } #fullSettingsTitle { @@ -336,7 +337,7 @@ body { } #firstPanel { - background-position: -250px; + background-position: -200px; } /* Move the first official button to the position on the png */ From 5f5e270edaffa3d92ff26cdd9dfa74ef50007d41 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 23:57:01 -0700 Subject: [PATCH 067/248] fix favorites offscreen at high scaling modes --- resources/style/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/style/index.css b/resources/style/index.css index 0e7ba46..e559189 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -128,7 +128,7 @@ body { position: absolute; z-index: 99; padding: 10px; - transform: translate(150px, 420px); + transform: translate(3vw, 420px); background-color: #fff; border-radius: 5px; border: 1px solid #ccc; From d53562a3a834f4fc97ee0ec031225e09de1368fa Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 24 Apr 2022 23:58:55 -0700 Subject: [PATCH 068/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 9fe0cae..f0a85b5 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.0", + "version": "0.7.1", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index d780cfd..cf8268a 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.0", + "version": "0.7.1", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 030f47a..5f200be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.7.0", + "version": "0.7.1", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 72a83065499d2fcfdb28fa109ed06be873b6fbac Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 00:02:26 -0700 Subject: [PATCH 069/248] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7192fe5..577a732 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ Grasscutter launcher for easily switching between Official and Private servers * [ ] 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) * [ ] Platform detection and bash scripts - * [ ] Fix Windows scaling issues? (partially done) * [ ] Integrated banner creator * Proxy service * [x] Local proxy server From 44a516f12f2a9b6d28df9ac0c9c4af237d907494 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 00:59:24 -0700 Subject: [PATCH 070/248] prevent logging on proxy script --- proxy/proxy.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/proxy/proxy.py b/proxy/proxy.py index 5c4a0b8..fc7cc25 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -52,8 +52,6 @@ class MlgmXyysd_Anime_Game_Proxy: # This can also be replaced with another IP address. REMOTE_HOST = ctx.options.ip REMOTE_PORT = ctx.options.port - - print(ctx.options.use_https) LIST_DOMAINS = [ "api-os-takumi.mihoyo.com", From ffd0d5dbb44a9ce7d8e8c4bbf737665bae18dcea Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 15:59:00 -0700 Subject: [PATCH 071/248] remove (optional) from port section --- languages/en.json | 2 +- languages/zh-tw.json | 13 ++++++++----- package.json | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/languages/en.json b/languages/en.json index f421003..7942c53 100644 --- a/languages/en.json +++ b/languages/en.json @@ -11,7 +11,7 @@ "folderNotSet": "Not set", "ipPlaceholder": "IP Address", - "portPlaceholder": "Port (optional)", + "portPlaceholder": "Port", "noFavorites": "No favorites set", "settingsTitle": "Settings", diff --git a/languages/zh-tw.json b/languages/zh-tw.json index fb4437e..b2604eb 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -1,5 +1,5 @@ { - "fullLangName": "Traditional Chinese", + "fullLangName": "繁體中文", "appName": "GrassClipper啟動器", "playOfficial": "啟動官方伺服器", @@ -11,20 +11,23 @@ "folderNotSet": "尚未設定Genshin Impact game資料夾", "ipPlaceholder": "IP地址", + "portPlaceholder": "端口", "noFavorites": "没有收藏", "settingsTitle": "設定", - "scriptsSectionTitle": "進程", + "scriptsSectionTitle": "程式設定", "killswitchOption": "終止服務進程", "killswitchSubtitle": "這是給對於封號非常敏感的人們,啟用此選項將會在你Proxy中發生任何錯誤時會終止你的遊戲(還有你的網路。)", "proxyOption": "Proxy", - "proxySubtitle": "通過安裝腳本來安裝Proxy伺服器。", + "proxySubtitle": "通過批次檔來安裝Proxy伺服器。", "updateOption": "更新", - "updateSubtitle": "自動更新暫時不可用。查看GitHub以獲取最新的Release。", + "updateSubtitle": "自動更新暫時無法使用。查看GitHub以獲取最新的Release。", "languageOption": "語言", "languageSubtitle": "選擇你最熟悉的語言!", "enableServerLauncherOption": "啟用本地伺服器", "enableServerLauncherSubtitle": "啟動器內將會為你顯示啟動本地伺服器選項。", + "httpsOption": "使用 HTTPS", + "httpsSubtitle": "選擇使用HTTP或HTTPS,此選項適用於私人伺服器。", "introSen1": "看來這是你第一次使用GrassClipper啟動器!", "introSen2": "首先,歡迎你使用GrassClipper啟動器,其次很高興在這裡見到你! :)", @@ -35,5 +38,5 @@ "proxyInstallDeny": "不用了,謝謝。", "gameFolderDialog": "選擇Genshin Impact game資料夾", - "grasscutterFileDialog": "選擇Grasscutter伺服器jar檔案" + "grasscutterFileDialog": "選擇Grasscutter.jar檔案" } \ No newline at end of file diff --git a/package.json b/package.json index 5f200be..9e98f16 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,6 @@ "move_files": "cp -r ./languages ./dist/GrassClipper && cp -r ./proxy ./dist/GrassClipper && cp -r ./scripts ./dist/GrassClipper", "move_bgs": "mkdir dist\\GrassClipper\\resources\\bg\\private && cp -r ./resources/bg/private ./dist/GrassClipper/resources/bg && cp -r ./resources/bg/server ./dist/GrassClipper/resources/bg", "rename_exe": "mv ./dist/GrassClipper/GrassClipper-win_x64.exe ./dist/GrassClipper/GrassClipper.exe", - "clean_dist": "rm -rf ./dist" + "clean_dist": "del /s /q .\\dist" } } From c9ffc9c8c36abed794252d277cd82df20a8a2fd7 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 16:24:32 -0700 Subject: [PATCH 072/248] windows build script --- build.sh | 0 build_win.cmd | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 build.sh create mode 100644 build_win.cmd diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..e69de29 diff --git a/build_win.cmd b/build_win.cmd new file mode 100644 index 0000000..1f92750 --- /dev/null +++ b/build_win.cmd @@ -0,0 +1,22 @@ +@echo off + +:: Clean dist folder +del /s /q /f .\dist +rd /s /q .\dist + +:: build +call neu build + +:: Copy scripts and langs +xcopy .\languages\ .\dist\GrassClipper\langauges\ /y /s +xcopy .\proxy\ .\dist\GrassClipper\proxy\ /y /s +xcopy .\scripts\ .\dist\GrassClipper\scripts\ /y /s + +:: bgs +mkdir .\dist\GrassClipper\resources\bg\private +mkdir .\dist\GrassClipper\resources\bg\server +xcopy .\resources\bg\private\ .\dist\GrassClipper\resources\bg\private\ /y /s +xcopy .\resources\bg\server\ .\dist\GrassClipper\resources\bg\server\ /y /s + +:: rename exe +move .\dist\GrassClipper\GrassClipper-win_x64.exe .\dist\GrassClipper\GrassClipper.exe \ No newline at end of file From c7f973ac61c018adbf7a9b4beba916d8ea7a467c Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 16:32:19 -0700 Subject: [PATCH 073/248] linux build script --- build.sh | 23 +++++++++++++++++++++++ build_win.cmd | 2 +- package.json | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index e69de29..8f73f6a 100644 --- a/build.sh +++ b/build.sh @@ -0,0 +1,23 @@ +# !/bin/bash + +# Clean dist +rm -rf ./dist + +# build +neu build + +# copy scripts and langs +cp -r ./scripts ./dist/GrassClipper +cp -r ./proxy ./dist/GrassClipper +cp -r ./languages ./dist/GrassClipper + +# copy backgrounds +mkdir ./dist/GrassClipper/resources/ +mkdir ./dist/GrassClipper/resources/bg +mkdir ./dist/GrassClipper/resources/bg/private +mkdir ./dist/GrassClipper/resources/bg/server +cp -r ./resources/bg/private/* ./dist/GrassClipper/resources/bg/private +cp -r ./resources/bg/server/* ./dist/GrassClipper/resources/bg/server + +# rename exe +mv ./dist/GrassClipper/GrassClipper-win_x64.exe ./dist/GrassClipper/GrassClipper.exe \ No newline at end of file diff --git a/build_win.cmd b/build_win.cmd index 1f92750..0447f82 100644 --- a/build_win.cmd +++ b/build_win.cmd @@ -8,7 +8,7 @@ rd /s /q .\dist call neu build :: Copy scripts and langs -xcopy .\languages\ .\dist\GrassClipper\langauges\ /y /s +xcopy .\languages\ .\dist\GrassClipper\languages\ /y /s xcopy .\proxy\ .\dist\GrassClipper\proxy\ /y /s xcopy .\scripts\ .\dist\GrassClipper\scripts\ /y /s diff --git a/package.json b/package.json index 9e98f16..82a01d6 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "license": "Apache-2.0", "scripts": { "dev": "neu run", + "build-win": ".\\build_win.cmd", + "build-linux": "./build.sh", "build": "npm run clean_dist && neu build && npm run move_files && npm run move_bgs && npm run rename_exe", "move_files": "cp -r ./languages ./dist/GrassClipper && cp -r ./proxy ./dist/GrassClipper && cp -r ./scripts ./dist/GrassClipper", "move_bgs": "mkdir dist\\GrassClipper\\resources\\bg\\private && cp -r ./resources/bg/private ./dist/GrassClipper/resources/bg && cp -r ./resources/bg/server ./dist/GrassClipper/resources/bg", From 7fe7d649bf2d7042b41faea191f9e44facab5b16 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 16:34:13 -0700 Subject: [PATCH 074/248] remove old build script stuff from package.json --- package.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/package.json b/package.json index 82a01d6..b8889f5 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,6 @@ "dev": "neu run", "build-win": ".\\build_win.cmd", "build-linux": "./build.sh", - "build": "npm run clean_dist && neu build && npm run move_files && npm run move_bgs && npm run rename_exe", - "move_files": "cp -r ./languages ./dist/GrassClipper && cp -r ./proxy ./dist/GrassClipper && cp -r ./scripts ./dist/GrassClipper", - "move_bgs": "mkdir dist\\GrassClipper\\resources\\bg\\private && cp -r ./resources/bg/private ./dist/GrassClipper/resources/bg && cp -r ./resources/bg/server ./dist/GrassClipper/resources/bg", - "rename_exe": "mv ./dist/GrassClipper/GrassClipper-win_x64.exe ./dist/GrassClipper/GrassClipper.exe", - "clean_dist": "del /s /q .\\dist" + "build": "echo !! Run build-win or build-linux to build for your platform !!\n" } } From 72ac08d0bd6ac7a0fb3706bb35e1433cea5de292 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 17:09:28 -0700 Subject: [PATCH 075/248] do not require admin for install script --- resources/js/index.js | 2 +- scripts/install.cmd | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index 999614e..0e9d8ae 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -283,7 +283,7 @@ async function closeFirstTimePopup() { } async function runInstallScript() { - Neutralino.os.execCommand(`${NL_CWD}/scripts/install.cmd "${NL_CWD}"`) + Neutralino.os.execCommand(`${NL_CWD}/scripts/install.cmd "${NL_CWD}" true`) // Create an interval that will check for the proxy server installation finish const interval = setInterval(async () => { diff --git a/scripts/install.cmd b/scripts/install.cmd index df02932..71d6c5c 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -2,11 +2,10 @@ set ORIGIN=%1 set ORIGIN=%ORIGIN:"=% +set OPEN_CONCUR=%2 -:: Ensure admin ->nul 2>&1 reg query "HKU\S-1-5-19" || ( - set params = %*:"="""% - cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 "%1" ", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) +if "%OPEN_CONCUR%" EQU "true" ( + cd /d "%~dp0" && ( if exist "%temp%\start.vbs" del "%temp%\start.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set SHELL = CreateObject^("Shell.Application"^) : SHELL.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 "%1" false", "", "", 1 >> "%temp%\start.vbs" && "%temp%\start.vbs" && exit /B ) ) echo Downloading proxy server... @@ -42,7 +41,8 @@ echo Adding ceritifcate... :: Ensure we are elevated for certs >nul 2>&1 certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer || ( - echo Certificate install failed, ensure the script is running as Administrator and that the path "%USERPROFILE%\.mitmproxy" exists, + echo Certificate install failed, ensure the script is running as Administrator and that the path "%USERPROFILE%\.mitmproxy" exists, + echo You can also manually run this command: certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer ) echo Done! You can now open GrassClipper.exe! From 07ec74c5b35687c737cafd247e4dcf118fe84e2a Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 17:21:35 -0700 Subject: [PATCH 076/248] do not require elevation for install and ps scripts --- resources/js/index.js | 2 +- scripts/private_server_launch.cmd | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index 0e9d8ae..6f4f4a0 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -399,7 +399,7 @@ async function launchPrivate() { Neutralino.storage.setData('config', JSON.stringify(config)) // Pass IP and game folder to the private server launcher - Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch}`).catch(e => console.log(e)) + Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) } async function launchLocalServer() { diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 834e262..d472175 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -1,9 +1,15 @@ @echo off :: Ensure admin ->nul 2>&1 reg query "HKU\S-1-5-19" || ( - set params = %*:"="""% - cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) +@REM >nul 2>&1 reg query "HKU\S-1-5-19" || ( +@REM set params = %*:"="""% +@REM cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) +@REM ) + +set OPEN_CONCUR=%7 + +if "%OPEN_CONCUR%" EQU "true" ( + cd /d "%~dp0" && ( if exist "%temp%\start.vbs" del "%temp%\start.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set SHELL = CreateObject^("Shell.Application"^) : SHELL.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "", 1 >> "%temp%\start.vbs" && "%temp%\start.vbs" && exit /B ) ) :: Use to force task kill @@ -70,7 +76,7 @@ reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v Pr :: Kill proxy server taskkill /f /im mitmdump.exe -echo Done! See you next time! +echo Done, see you next time timeout /t 2 /nobreak >nul From ea1cdd76e130f0d98c0fc3b2b0930e246a834551 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 17:38:10 -0700 Subject: [PATCH 077/248] only ask for admin when running killswitch --- scripts/private_server_launch.cmd | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index d472175..887226b 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -26,6 +26,14 @@ set ORIGIN=%5 set ORIGIN=%ORIGIN:"=% set ENABLE_KILLSWITCH=%6 +if "%ENABLE_KILLSWITCH%" EQU "true" ( + :: Restart in elevated if need be + >nul 2>&1 reg query "HKU\S-1-5-19" || ( + set params = %*:"="""% + cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%/../"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" && exit /b ) + ) +) + set PROXY=true @rem Store original proxy settings for /f "tokens=2*" %%a in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable 2^>nul') do set "ORIG_PROXY_ENABLE=%%b" @@ -52,7 +60,7 @@ echo Killswitch: %ENABLE_KILLSWITCH% if "%ENABLE_KILLSWITCH%" EQU "true" ( echo Killswitch is enabled! :: Start killswitch - start /b %ORIGIN%\scripts\killswitch.cmd "%GAME_EXE%" %IP%" + start /b %ORIGIN%\scripts\killswitch.cmd "%GAME_EXE%" %IP% ) :: Launch game @@ -80,6 +88,6 @@ echo Done, see you next time timeout /t 2 /nobreak >nul -taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" +taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" || taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" exit /b \ No newline at end of file From 82b667b83b00f3d82a889aa384bbe178308480d2 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 18:37:41 -0700 Subject: [PATCH 078/248] fix some script related issues --- resources/js/index.js | 11 +++++++---- scripts/install.cmd | 5 ----- scripts/private_server_launch.cmd | 8 +------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index 6f4f4a0..d0042a8 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -2,6 +2,9 @@ Neutralino.init(); let localeObj; const filesystem = Neutralino.filesystem +const createCmdWindow = async (command) => { + Neutralino.os.execCommand(`cmd.exe /c start ${command}`, { background: true }) +} /** * Enable play buttons @@ -283,7 +286,7 @@ async function closeFirstTimePopup() { } async function runInstallScript() { - Neutralino.os.execCommand(`${NL_CWD}/scripts/install.cmd "${NL_CWD}" true`) + createCmdWindow(`${NL_CWD}/scripts/install.cmd "${NL_CWD}" true`) // Create an interval that will check for the proxy server installation finish const interval = setInterval(async () => { @@ -380,7 +383,7 @@ async function setGrasscutterFolder() { async function launchOfficial() { const config = await getCfg() - Neutralino.os.execCommand(config.gamefolder + '/' + await getGameExecName()) + createCmdWindow(config.gamefolder + '/' + await getGameExecName()) } /** @@ -399,11 +402,11 @@ async function launchPrivate() { Neutralino.storage.setData('config', JSON.stringify(config)) // Pass IP and game folder to the private server launcher - Neutralino.os.execCommand(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) + createCmdWindow(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) } async function launchLocalServer() { const config = await getCfg() - Neutralino.os.execCommand(`${NL_CWD}/scripts/local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e)) + createCmdWindow(`${NL_CWD}/scripts/local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e)) } diff --git a/scripts/install.cmd b/scripts/install.cmd index 71d6c5c..178f1a7 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -2,11 +2,6 @@ set ORIGIN=%1 set ORIGIN=%ORIGIN:"=% -set OPEN_CONCUR=%2 - -if "%OPEN_CONCUR%" EQU "true" ( - cd /d "%~dp0" && ( if exist "%temp%\start.vbs" del "%temp%\start.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set SHELL = CreateObject^("Shell.Application"^) : SHELL.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 "%1" false", "", "", 1 >> "%temp%\start.vbs" && "%temp%\start.vbs" && exit /B ) -) echo Downloading proxy server... diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 887226b..c6e3402 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -6,12 +6,6 @@ @REM cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) @REM ) -set OPEN_CONCUR=%7 - -if "%OPEN_CONCUR%" EQU "true" ( - cd /d "%~dp0" && ( if exist "%temp%\start.vbs" del "%temp%\start.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set SHELL = CreateObject^("Shell.Application"^) : SHELL.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "", 1 >> "%temp%\start.vbs" && "%temp%\start.vbs" && exit /B ) -) - :: Use to force task kill title PS Launcher Script @@ -86,7 +80,7 @@ taskkill /f /im mitmdump.exe echo Done, see you next time -timeout /t 2 /nobreak >nul +timeout.exe /t 2 /nobreak >nul taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" || taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" From cae6043664200e217d98c441e361343a0aa5dd8f Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 18:39:43 -0700 Subject: [PATCH 079/248] use hacky timeout --- scripts/killswitch.cmd | 2 +- scripts/private_server_launch.cmd | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/killswitch.cmd b/scripts/killswitch.cmd index 4c78b4f..8fd010c 100644 --- a/scripts/killswitch.cmd +++ b/scripts/killswitch.cmd @@ -62,7 +62,7 @@ if "%PROXY_IP%" EQU "localhost" ( goto killgame ) - timeout /t 2 /NOBREAK >nul + ping 127.0.0.1 -n 2 > nul goto loop diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index c6e3402..7641cb9 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -80,7 +80,8 @@ taskkill /f /im mitmdump.exe echo Done, see you next time -timeout.exe /t 2 /nobreak >nul +:: Just in case the user has corutils installed, use this hacky timeout instead of the timeout command +ping 127.0.0.1 -n 2 > nul taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" || taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" From daf9ce477f5a9063b275aa3c9283fe10e8da82a7 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 18:51:53 -0700 Subject: [PATCH 080/248] kill server window properly --- scripts/private_server_launch.cmd | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 7641cb9..787e5a0 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -82,7 +82,9 @@ echo Done, see you next time :: Just in case the user has corutils installed, use this hacky timeout instead of the timeout command ping 127.0.0.1 -n 2 > nul - -taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" || taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" + +:: Attempt to kill either +taskkill /f /fi "WINDOWTITLE eq Administrator: PS Launcher Script" +taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" exit /b \ No newline at end of file From efd52e1ab7b45e94b4cf7120efc0e45b31dc7872 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 18:54:41 -0700 Subject: [PATCH 081/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index f0a85b5..e7f25a4 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.1", + "version": "0.7.2", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index cf8268a..6eef806 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.1", + "version": "0.7.2", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index b8889f5..91f8844 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.7.1", + "version": "0.7.2", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From a4c33584a0f6e245a3a6ab6f84545e3d3ebb3d4e Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 18:59:14 -0700 Subject: [PATCH 082/248] default 127.0.01 --- proxy/proxy.py | 2 +- resources/js/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/proxy.py b/proxy/proxy.py index fc7cc25..e6bf383 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -30,7 +30,7 @@ class MlgmXyysd_Anime_Game_Proxy: loader.add_option( name = "ip", typespec = str, - default = "localhost", + default = "127.0.0.1", help = "IP address to replace", ) diff --git a/resources/js/index.js b/resources/js/index.js index d0042a8..e99068f 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -390,7 +390,7 @@ async function launchOfficial() { * Launch the game with a proxy */ async function launchPrivate() { - const ip = document.getElementById('ip').value || 'localhost' + const ip = document.getElementById('ip').value || '127.0.0.1' const port = document.getElementById('port').value || '443' const config = await getCfg() From 603b919254104e0d2067d72ea62de6374a37bab9 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 19:32:01 -0700 Subject: [PATCH 083/248] Fix server launcher --- languages/en.json | 1 + scripts/local_server_launch.cmd | 8 +------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/languages/en.json b/languages/en.json index 7942c53..a4ce9b9 100644 --- a/languages/en.json +++ b/languages/en.json @@ -34,6 +34,7 @@ "introSen3": "Would you like to run the proxy installer?", "introSen4": "(required to connect to servers)", + "updateBtn": "Update", "proxyInstallBtn": "Install", "proxyInstallDeny": "No thanks", diff --git a/scripts/local_server_launch.cmd b/scripts/local_server_launch.cmd index 2df8358..e052d1a 100644 --- a/scripts/local_server_launch.cmd +++ b/scripts/local_server_launch.cmd @@ -13,15 +13,9 @@ goto l set "X=%X:~0,-1%" set "GRASSCUTTER_ROOT=%X%" -:: Ensure admin ->nul 2>&1 reg query "HKU\S-1-5-19" || ( - set params = %*:"="""% - cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 "%1"", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && exit /B ) -) - echo Starting local Grasscutter server... :: Change dir to server directory cd /d "%GRASSCUTTER_ROOT%" -start /b java -jar %GRASSCUTTER_JAR% \ No newline at end of file +call java -jar %GRASSCUTTER_JAR% \ No newline at end of file From 64626230cf1cedbf1aa92d72785e4bd898b8d316 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 19:33:58 -0700 Subject: [PATCH 084/248] verion bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index e7f25a4..f5e043b 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.2", + "version": "0.7.3", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 6eef806..4336cac 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.2", + "version": "0.7.3", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 91f8844..30681fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.7.2", + "version": "0.7.3", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From fff00ca8154a51d862c0d147220573d39e65370a Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 22:22:54 -0700 Subject: [PATCH 085/248] Set game exe rather than folder --- languages/en.json | 2 +- languages/es.json | 2 +- languages/fr.json | 2 +- languages/id.json | 2 +- languages/nl.json | 2 +- languages/pt-br.json | 2 +- languages/ru.json | 2 +- languages/vie.json | 2 +- languages/zh-tw.json | 2 +- languages/zh.json | 2 +- resources/index.html | 2 +- resources/js/helpers.js | 18 +----------------- resources/js/index.js | 36 ++++++++++++++++-------------------- resources/js/onLoad.js | 2 +- resources/js/translation.js | 2 +- 15 files changed, 30 insertions(+), 50 deletions(-) diff --git a/languages/en.json b/languages/en.json index a4ce9b9..b1249c3 100644 --- a/languages/en.json +++ b/languages/en.json @@ -6,7 +6,7 @@ "playPrivate": "Play on Grasscutter", "launchLocalServer": "Launch Local Server", - "gameFolderSet": "Set game folder", + "gameExeSet": "Set game executable", "grasscutterFileSet": "Set \"Grasscutter\" .jar file", "folderNotSet": "Not set", diff --git a/languages/es.json b/languages/es.json index c3cc788..9fce461 100644 --- a/languages/es.json +++ b/languages/es.json @@ -6,7 +6,7 @@ "playPrivate": "Jugar en Grasscutter", "launchLocalServer": "Iniciar servidor local", - "gameFolderSet": "Establece el folder game", + "gameExeSet": "Establece el folder game", "grasscutterFileSet": "Establece el archivo .jar de \"Grasscutter\"", "folderNotSet": "No establecido", diff --git a/languages/fr.json b/languages/fr.json index 3eb9246..485d401 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -6,7 +6,7 @@ "playPrivate": "Jouer sur Grasscutter", "launchLocalServer": "Lancer le serveur en local", - "gameFolderSet": "Définir le dossier game", + "gameExeSet": "Définir le dossier game", "grasscutterFileSet": "Définir le fichier .jar \"Grasscutter\"", "folderNotSet": "Pas encore défini", diff --git a/languages/id.json b/languages/id.json index 5c200f0..63608f9 100644 --- a/languages/id.json +++ b/languages/id.json @@ -6,7 +6,7 @@ "playPrivate": "Mainkan Grasscutter", "launchLocalServer": "Luncurkan Local Server", - "gameFolderSet": "Atur folder game", + "gameExeSet": "Atur folder game", "grasscutterFileSet": "Atur file \"Grasscutter\" .jar", "folderNotSet": "Belum diatur", diff --git a/languages/nl.json b/languages/nl.json index cdbeed2..03cdb3b 100644 --- a/languages/nl.json +++ b/languages/nl.json @@ -6,7 +6,7 @@ "playPrivate": "Op Grasscutter spelen", "launchLocalServer": "Lokale server starten", - "gameFolderSet": "Selecteer de game folder", + "gameExeSet": "Selecteer de game folder", "grasscutterFileSet": "Selecteer het \"Grasscutter\" .jar bestand", "folderNotSet": "Niet geselecteerd", diff --git a/languages/pt-br.json b/languages/pt-br.json index 23c3402..cc11e7b 100644 --- a/languages/pt-br.json +++ b/languages/pt-br.json @@ -6,7 +6,7 @@ "playPrivate": "Jogar (Grasscutter)", "launchLocalServer": "Abrir Servidor Local", - "gameFolderSet": "Definir a game pasta ", + "gameExeSet": "Definir a game pasta ", "grasscutterFileSet": "Definir o arquivo .jar de \"Grasscutter\" ", "folderNotSet": "Não Definida", diff --git a/languages/ru.json b/languages/ru.json index 5905a58..86c42c3 100644 --- a/languages/ru.json +++ b/languages/ru.json @@ -6,7 +6,7 @@ "playPrivate": "Grasscutter", "launchLocalServer": "Локальный сервер", - "gameFolderSet": "Папка с игрой", + "gameExeSet": "Папка с игрой", "grasscutterFileSet": "Путь до файла \"Grasscutter\" (.jar)", "folderNotSet": "Папка не выбрана", diff --git a/languages/vie.json b/languages/vie.json index 31800c3..a64da64 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -6,7 +6,7 @@ "playPrivate": "Grasscutter", "launchLocalServer": "Khởi động Grasscutter", - "gameFolderSet": "Chỉnh địa điểm thư mục trò chơi", + "gameExeSet": "Chỉnh địa điểm thư mục trò chơi", "grasscutterFileSet": "Chỉnh địa điểm file \"Grasscutter\"", "folderNotSet": "Chưa chỉnh file", diff --git a/languages/zh-tw.json b/languages/zh-tw.json index b2604eb..ca1984a 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -6,7 +6,7 @@ "playPrivate": "啟動私人伺服器", "launchLocalServer": "啟動本地伺服器", - "gameFolderSet": "設定 \"Genshin Impact game\" 資料夾", + "gameExeSet": "設定 \"Genshin Impact game\" 資料夾", "grasscutterFileSet": "設定 \"Grasscutter\" .jar 檔案", "folderNotSet": "尚未設定Genshin Impact game資料夾", diff --git a/languages/zh.json b/languages/zh.json index e1f6008..1e2fdba 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -6,7 +6,7 @@ "playPrivate": "启动私人服务器", "launchLocalServer": "启动本地服务器", - "gameFolderSet": "选择 \"Genshin Impact Game\" 文件夹", + "gameExeSet": "选择 \"Genshin Impact Game\" 文件夹", "grasscutterFileSet": "选择 \"Grasscutter\" .jar 文件", "folderNotSet": "没有选择Genshin Impact Game文件夹或Grasscutter.jar文件", diff --git a/resources/index.html b/resources/index.html index 708db52..3b97fb9 100644 --- a/resources/index.html +++ b/resources/index.html @@ -128,7 +128,7 @@
- +
diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 7d53e14..d4fe160 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -5,7 +5,7 @@ */ async function getCfg() { const defaultConf = { - gamefolder: '', + gameexe: '', serverFolder: '', lastConnect: '', enableKillswitch: false, @@ -57,22 +57,6 @@ async function proxyIsInstalled() { return false } -/** - * Get the name of the game executable - * - * @returns {Promise} - */ - async function getGameExecName() { - // Scan game dir - const config = await getCfg() - const gameDir = await filesystem.readDirectory(config.gamefolder) - - // Find the executable - const gameExec = gameDir.find(file => file.entry.endsWith('.exe')) - - return gameExec.entry -} - /** * Minimize the window */ diff --git a/resources/js/index.js b/resources/js/index.js index e99068f..8135997 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -75,7 +75,7 @@ async function displayGameFolder() { const elm = document.querySelector('#gamePath') const config = await getCfg() - elm.innerHTML = config.gamefolder + elm.innerHTML = config.gameexe } /** @@ -129,17 +129,17 @@ async function setBackgroundImage() { await filesystem.createDirectory(NL_CWD + '/resources/bg/official') } - if (config.gamefolder) { + if (config.gameexe) { // See if bg folder exists in parent dir - const parentDir = await filesystem.readDirectory(config.gamefolder + '/..') + const parentDir = await filesystem.readDirectory(config.gameexe + '/..') if (parentDir.find(dir => dir.entry === 'bg')) { - const officialImages = (await filesystem.readDirectory(config.gamefolder + '/../bg')).filter(file => file.type === 'FILE') + const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') if (officialImages.length > 0) { for (const bg of officialImages) { - const path = config.gamefolder.replace('\\', '/') + '/../bg/' + bg.entry + const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry // See if the file exists already const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') @@ -272,7 +272,7 @@ async function closeSettings() { settings.style.display = 'none' // In case we installed the proxy server - if (await proxyIsInstalled() && config.gamefolder) { + if (await proxyIsInstalled() && config.gameexe) { const playPriv = document.querySelector('#playPrivate') playPriv.classList.remove('disabled') @@ -335,22 +335,18 @@ async function displayServerLaunchSection() { /** * Set the game folder by opening a folder picker */ -async function setGameFolder() { - const folder = await Neutralino.os.showFolderDialog(localeObj.gameFolderDialog) +async function setGameExe() { + const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { + filters: [ + { name: 'Executable files', extensions: ['exe'] } + ] + }) // Set the folder in our configuration const config = await getCfg() - // See if the actual game folder is inside this one - const folderList = await filesystem.readDirectory(folder) - const gameFolder = folderList.filter(file => file.entry.includes('Genshin Impact Game')) - - if (gameFolder.length > 0) { - config.gamefolder = folder + '\\Genshin Impact Game' - Neutralino.storage.setData('config', JSON.stringify(config)) - } else { - config.gamefolder = folder - } + // It's an array of selections, so only get the first one + config.gameexe = gameExe[0] Neutralino.storage.setData('config', JSON.stringify(config)) @@ -383,7 +379,7 @@ async function setGrasscutterFolder() { async function launchOfficial() { const config = await getCfg() - createCmdWindow(config.gamefolder + '/' + await getGameExecName()) + Neutralino.os.execCommand(`"${config.gameexe}"`) } /** @@ -402,7 +398,7 @@ async function launchPrivate() { Neutralino.storage.setData('config', JSON.stringify(config)) // Pass IP and game folder to the private server launcher - createCmdWindow(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gamefolder}/${await getGameExecName()}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) + createCmdWindow(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) } async function launchLocalServer() { diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index 48c50b8..88bfb85 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -68,7 +68,7 @@ // Ensure we do the translation at the very end, after everything else has loaded await doTranslation() - if (!config.gamefolder) { + if (!config.gameexe) { handleGameNotSet() } diff --git a/resources/js/translation.js b/resources/js/translation.js index aa8fbf7..40f058b 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -34,7 +34,7 @@ async function doTranslation() { set('serverLaunch', 'launchLocalServer') // File select buttons - set('gameFolderSet', 'gameFolderSet') + set('gameExeSet', 'gameExeSet') set('grasscutterFileSet', 'grasscutterFileSet') // Private options From 46496b8e11ced1712bf56fd3e66a6cbdd87061c3 Mon Sep 17 00:00:00 2001 From: labalityowo <56186498+labalityowo@users.noreply.github.com> Date: Tue, 26 Apr 2022 12:33:06 +0700 Subject: [PATCH 086/248] Update vietnamese translation --- languages/vie.json | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/languages/vie.json b/languages/vie.json index a64da64..60ed8c2 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -3,14 +3,15 @@ "appName": "GrassClipper", "playOfficial": "Máy chủ chính thức", - "playPrivate": "Grasscutter", + "playPrivate": "Máy chủ thứ 3", "launchLocalServer": "Khởi động Grasscutter", - "gameExeSet": "Chỉnh địa điểm thư mục trò chơi", - "grasscutterFileSet": "Chỉnh địa điểm file \"Grasscutter\"", - "folderNotSet": "Chưa chỉnh file", + "gameExeSet": "Chọn file game", + "grasscutterFileSet": "Chọn file \"Grasscutter\"", + "folderNotSet": "Chưa chọn file", - "ipPlaceholder": "Địa chỉ IP", + "ipPlaceholder": "Địa chỉ", + "portPlaceholder": "Port", "noFavorites": "Không có máy chủ yêu thích", "settingsTitle": "Cài đặt", @@ -20,19 +21,21 @@ "proxyOption": "Proxy", "proxySubtitle": "Tải proxy", "updateOption": "Cập nhật", - "updateSubtitle": "Tạm thời chưa dùng được. Kiểm tra Github để có bản cập nhật mới", + "updateSubtitle": "Tạm thời chưa dùng được. Kiểm tra Github để biết thêm chi tiết", "languageOption": "Ngôn ngữ", "languageSubtitle": "Chọn ngôn ngữ", - "enableServerLauncherOption": "Grasscutter", - "enableServerLauncherSubtitle": "Thêm lựa chọn bật grasscutter", + "enableServerLauncherSubtitle": "Thêm lựa chọn bật máy chủ grasscutter", + "httpsOption": "Dùng HTTPS", + "httpsSubtitle": "", "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! :)", "introSen3": "Bạn có muốn tải proxy không?", "introSen4": "(dùng để vào máy chủ riêng)", - "proxyInstallBtn": "Có", + "updateBtn": "Cập nhật", + "proxyInstallBtn": "Tải", "proxyInstallDeny": "Không", "gameFolderDialog": "Chọn thư mục có chứa trò chơi", From 28ee27e50d3dd44ceeccab7918d08aab04b5d797 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 23:03:42 -0700 Subject: [PATCH 087/248] fix script paths and quotations --- resources/js/index.js | 8 ++++---- scripts/install.cmd | 8 ++++---- scripts/private_server_launch.cmd | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index 8135997..8f6415a 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -3,7 +3,7 @@ Neutralino.init(); let localeObj; const filesystem = Neutralino.filesystem const createCmdWindow = async (command) => { - Neutralino.os.execCommand(`cmd.exe /c start ${command}`, { background: true }) + Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true }) } /** @@ -286,7 +286,7 @@ async function closeFirstTimePopup() { } async function runInstallScript() { - createCmdWindow(`${NL_CWD}/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 const interval = setInterval(async () => { @@ -398,11 +398,11 @@ async function launchPrivate() { Neutralino.storage.setData('config', JSON.stringify(config)) // Pass IP and game folder to the private server launcher - createCmdWindow(`${NL_CWD}/scripts/private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) + createCmdWindow(`.\\scripts\\private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) } async function launchLocalServer() { const config = await getCfg() - createCmdWindow(`${NL_CWD}/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)) } diff --git a/scripts/install.cmd b/scripts/install.cmd index 178f1a7..f023540 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -9,22 +9,22 @@ echo Downloading proxy server... cd "%ORIGIN%" 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 -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... :: 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" echo Running proxy server in order to generate certificates... :: 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 ping 127.0.0.1 -n 6 > nul diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 787e5a0..ae0b3e6 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -38,7 +38,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 :: Start proxy server -start "Proxy Server" %ORIGIN%/ext/mitmdump.exe -s "%ORIGIN%/proxy/proxy.py" --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" --ssl-insecure --set ip=%IP% --set port=%PORT% --set use_https=%USE_HTTPS% echo Opening %GAME_PATH% From 69683baaa6991ecbf0932f0590da39a5ca837314 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 23:03:59 -0700 Subject: [PATCH 088/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index f5e043b..0337bc3 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.3", + "version": "0.7.4", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 4336cac..8de601a 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.7.3", + "version": "0.7.4", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 30681fd..aca7e4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.7.3", + "version": "0.7.4", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 11b4aa47f2c44be3e91a224e68b4a5b12418d378 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 25 Apr 2022 23:12:16 -0700 Subject: [PATCH 089/248] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 577a732..3b5d1a8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ Grasscutter launcher for easily switching between Official and Private servers [Download Here!](https://github.com/Grasscutters/GrassClipper/releases/) +*\*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!* + # Table of Contents * [Setup (for users)](#setup-for-users) From 1ecb69af38547e9489d4a879c38735634ef8de14 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 02:05:58 -0700 Subject: [PATCH 090/248] open folder icons --- languages/vie.json | 1 + resources/icons/folder.svg | 10 ++++++++++ resources/index.html | 10 ++++++++-- resources/style/index.css | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 resources/icons/folder.svg diff --git a/languages/vie.json b/languages/vie.json index a64da64..ee05433 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -23,6 +23,7 @@ "updateSubtitle": "Tạm thời chưa dùng được. Kiểm tra Github để có bản cập nhật mới", "languageOption": "Ngôn ngữ", "languageSubtitle": "Chọn ngôn ngữ", + "httpsSubtitle": "THASHIOASHTO", "enableServerLauncherOption": "Grasscutter", "enableServerLauncherSubtitle": "Thêm lựa chọn bật grasscutter", diff --git a/resources/icons/folder.svg b/resources/icons/folder.svg new file mode 100644 index 0000000..077b707 --- /dev/null +++ b/resources/icons/folder.svg @@ -0,0 +1,10 @@ + +Created with Fabric.js 1.7.22 + + + + + + + + \ No newline at end of file diff --git a/resources/index.html b/resources/index.html index 3b97fb9..ca77fe1 100644 --- a/resources/index.html +++ b/resources/index.html @@ -128,11 +128,17 @@
- +
+ + +
- +
+ + +
diff --git a/resources/style/index.css b/resources/style/index.css index e559189..e78ac6f 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -277,6 +277,18 @@ body { background: linear-gradient(#ffc61e, #ffd326); } +.openFolderIcon { + display: inline; + height: 20px; + filter: invert(97%) sepia(85%) saturate(12%) hue-rotate(184deg) brightness(103%) contrast(103%); + padding: 10px; +} + +.openFolderIcon:hover { + cursor: pointer; + filter: invert(99%) sepia(0%) saturate(1092%) hue-rotate(172deg) brightness(80%) contrast(103%); +} + #bottomBar { display: flex; justify-content: center; @@ -305,6 +317,12 @@ body { height: 10%; } +.bottomSection div div { + display: flex; + flex-direction: row; + height: 100%; +} + #gamePath, #serverPath { color: white; font-size: 14px; From 2ab0fb75f9244ff12f7a9e2346aba1d5c48ff43b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 02:12:58 -0700 Subject: [PATCH 091/248] open game and grasscutter folders from launcher --- resources/index.html | 4 ++-- resources/js/helpers.js | 14 ++++++++++++++ resources/js/index.js | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/resources/index.html b/resources/index.html index ca77fe1..ff2622c 100644 --- a/resources/index.html +++ b/resources/index.html @@ -130,14 +130,14 @@
- +
- +
diff --git a/resources/js/helpers.js b/resources/js/helpers.js index d4fe160..4701911 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -57,6 +57,20 @@ async function proxyIsInstalled() { return false } +async function openGameFolder() { + const config = await getCfg() + const folder = config.gameexe.match(/.*\\/g, '')[0] + + createCmdWindow(`explorer.exe "${folder}"`) +} + +async function openGrasscutterFolder() { + const config = await getCfg() + const folder = config.serverFolder.match(/.*\\/g, '')[0] + + createCmdWindow(`explorer.exe "${folder}"`) +} + /** * Minimize the window */ diff --git a/resources/js/index.js b/resources/js/index.js index 8f6415a..2b3d481 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -366,7 +366,7 @@ async function setGrasscutterFolder() { // Set the folder in our configuration const config = await getCfg() - config.serverFolder = folder + config.serverFolder = folder[0] Neutralino.storage.setData('config', JSON.stringify(config)) displayServerFolder() From cac04193de0fa78d513cdc34956b958a4eb6d387 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 02:26:53 -0700 Subject: [PATCH 092/248] openInExplorer function --- resources/js/helpers.js | 4 ++-- resources/js/index.js | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 4701911..1beba4a 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -61,14 +61,14 @@ async function openGameFolder() { const config = await getCfg() const folder = config.gameexe.match(/.*\\/g, '')[0] - createCmdWindow(`explorer.exe "${folder}"`) + openInExplorer(folder) } async function openGrasscutterFolder() { const config = await getCfg() const folder = config.serverFolder.match(/.*\\/g, '')[0] - createCmdWindow(`explorer.exe "${folder}"`) + openInExplorer(folder) } /** diff --git a/resources/js/index.js b/resources/js/index.js index 2b3d481..8aaf05d 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -6,6 +6,10 @@ const createCmdWindow = async (command) => { Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true }) } +const openInExplorer = async (path) => { + createCmdWindow(`explorer.exe "${path}"`) +} + /** * Enable play buttons */ From 445fa99992665a441812b6bae3f79a5928f5c50b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 02:34:54 -0700 Subject: [PATCH 093/248] update traditional chinese translation --- languages/zh-tw.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages/zh-tw.json b/languages/zh-tw.json index ca1984a..1cb1db9 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -6,7 +6,7 @@ "playPrivate": "啟動私人伺服器", "launchLocalServer": "啟動本地伺服器", - "gameExeSet": "設定 \"Genshin Impact game\" 資料夾", + "gameExeSet": "設定\"GenshinImpact\" .exe執行檔", "grasscutterFileSet": "設定 \"Grasscutter\" .jar 檔案", "folderNotSet": "尚未設定Genshin Impact game資料夾", From 2ebb4119f53da781468f1ef6d547d7dc04a6bec0 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 02:37:10 -0700 Subject: [PATCH 094/248] update traditional chinese translation (again) --- languages/zh-tw.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages/zh-tw.json b/languages/zh-tw.json index 1cb1db9..266dbeb 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -6,8 +6,8 @@ "playPrivate": "啟動私人伺服器", "launchLocalServer": "啟動本地伺服器", - "gameExeSet": "設定\"GenshinImpact\" .exe執行檔", - "grasscutterFileSet": "設定 \"Grasscutter\" .jar 檔案", + "gameExeSet": "設定\"GenshinImpact\".exe執行檔", + "grasscutterFileSet": "設定 \"Grasscutter\".jar 檔案", "folderNotSet": "尚未設定Genshin Impact game資料夾", "ipPlaceholder": "IP地址", From f0bfd46b36c44926043c64fc31b93dad5142fcba Mon Sep 17 00:00:00 2001 From: labalityowo <56186498+labalityowo@users.noreply.github.com> Date: Tue, 26 Apr 2022 17:02:55 +0700 Subject: [PATCH 095/248] Fixing some translations --- languages/vie.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/languages/vie.json b/languages/vie.json index 60ed8c2..4042732 100644 --- a/languages/vie.json +++ b/languages/vie.json @@ -6,8 +6,8 @@ "playPrivate": "Máy chủ thứ 3", "launchLocalServer": "Khởi động Grasscutter", - "gameExeSet": "Chọn file game", - "grasscutterFileSet": "Chọn file \"Grasscutter\"", + "gameExeSet": "Chọn file \"GenshinImpact.exe\"", + "grasscutterFileSet": "Chọn file \"Grasscutter.jar\"", "folderNotSet": "Chưa chọn file", "ipPlaceholder": "Địa chỉ", @@ -19,15 +19,15 @@ "killswitchOption": "Công tắc đóng", "killswitchSubtitle": "Dành cho những ai sợ bị ban. Tắt game *và mạng* nếu proxy có vấn đề.", "proxyOption": "Proxy", - "proxySubtitle": "Tải proxy", + "proxySubtitle": "Dùng để kết nối vào máy chủ thứ 3", "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", "languageOption": "Ngôn ngữ", - "languageSubtitle": "Chọn ngôn ngữ", + "languageSubtitle": " ", "enableServerLauncherOption": "Grasscutter", "enableServerLauncherSubtitle": "Thêm lựa chọn bật máy chủ grasscutter", "httpsOption": "Dùng HTTPS", - "httpsSubtitle": "", + "httpsSubtitle": " ", "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! :)", @@ -38,6 +38,6 @@ "proxyInstallBtn": "Tải", "proxyInstallDeny": "Không", - "gameFolderDialog": "Chọn thư mục có chứa trò chơi", - "grasscutterFileDialog": "Chọn file Grasscutter" - } \ No newline at end of file + "gameFolderDialog": "Chọn GenshinImpact.exe", + "grasscutterFileDialog": "Chọn Grasscutter.jar" + } From c3db99c4e7833f69ae5066d9d007d70a3d15727b Mon Sep 17 00:00:00 2001 From: ayy lmao Date: Tue, 26 Apr 2022 22:11:13 +0300 Subject: [PATCH 096/248] Add Turkish translation --- languages/tr.json | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 languages/tr.json diff --git a/languages/tr.json b/languages/tr.json new file mode 100644 index 0000000..7f8a68d --- /dev/null +++ b/languages/tr.json @@ -0,0 +1,43 @@ +{ + "fullLangName": "Türkçe", + "appName": "GrassClipper", + + "playOfficial": "Resmi sunucuda oyna", + "playPrivate": "Grasscutter sunucusunda oyna", + "launchLocalServer": "Yerel sunucuyu başlat", + + "gameExeSet": "Oyun çalıştırıcısını seç", + "grasscutterFileSet": "\"Grasscutter\" .jar dosyasını seç", + "folderNotSet": "Seçilmedi", + + "ipPlaceholder": "IP Adresi", + "portPlaceholder": "Port", + "noFavorites": "Favori sunucunuz yok.", + + "settingsTitle": "Ayarlar", + "scriptsSectionTitle": "Scriptler", + "killswitchOption": "Kill Switch", + "killswitchSubtitle": "Sadece banlanmaktan paranoyak olanlar için. Proxy'ye bir şey olduğunda oyunu kapatıp *internet bağlantınızı* keser.", + "proxyOption": "Proxy", + "proxySubtitle": "Proxy sunucusunu bir script ile kur.", + "updateOption": "Güncelle", + "updateSubtitle": "Otomatik güncellemeler geçici olarak devre dışıdır. Yeni sürümler için GitHub'ı kontrol edin.", + "languageOption": "Dil", + "languageSubtitle": "Dilinizi seçin!", + "enableServerLauncherOption": "Sunucu başlatıcısını etkinleştir", + "enableServerLauncherSubtitle": "Yerel Grasscutter sunucusunu başlatmak için kutucuğunu etkinleştirin.", + "httpsOption": "HTTPS kullan", + "httpsSubtitle": "HTTPS veya HTTP arasında geçiş yap.", + + "introSen1": "Görünüşe göre GrassClipper'ı ilk kez açıyorsunuz!", + "introSen2": "İlk olarak, hoşgeldiniz. Sizi burada görmek bizi mutlu ediyor! :)", + "introSen3": "Proxy kurucusunu çalıştırmak ister misiniz?", + "introSen4": "(sunuculara bağlanmak için gerekli)", + + "updateBtn": "Güncelle", + "proxyInstallBtn": "Kur", + "proxyInstallDeny": "Hayır, teşekkürler.", + + "gameFolderDialog": "Oyun klasörünü seç", + "grasscutterFileDialog": "Grasscutter.jar dosyasını seç" +} From 4f229b8743c327469c7008efff20528692c07f86 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 13:46:10 -0700 Subject: [PATCH 097/248] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3b5d1a8..3487c5e 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ Thank you to everyone who has provided translations! <3 * ES - memetrollsXD * ND - memetrollsXD * RU - fitiskin +* TR - lilmayofuksu # Screenshots From 2e264e053bff8ef8f3812c99ccb782f9519f6ec8 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 13:49:18 -0700 Subject: [PATCH 098/248] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3487c5e..0f77f62 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Below are some scenarios you may encounter and their solutions. ## White Screen Fix -Encountering a white screen? [Ensure WebView2 is installed](https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/#download) +Encountering a white screen? [Ensure WebView2 is installed](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download) You may also want to run this command as administrator: `CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy"` From 6050aa86f2af9ec4434225b07e0a307655ab80bf Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 17:29:34 -0700 Subject: [PATCH 099/248] html comments --- resources/index.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/resources/index.html b/resources/index.html index ff2622c..8eceeed 100644 --- a/resources/index.html +++ b/resources/index.html @@ -12,6 +12,7 @@ +
+ +
+ +
GrassClipper @@ -105,12 +110,15 @@
+
+
+
@@ -120,11 +128,13 @@
+
+
From 4abaadb2a09496231377b2aa553038fbf76d421c Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 17:55:16 -0700 Subject: [PATCH 100/248] login popup layout --- resources/index.html | 37 +++++++++++++++++++++++++++++++++++++ resources/style/index.css | 12 ++++++++++++ 2 files changed, 49 insertions(+) diff --git a/resources/index.html b/resources/index.html index 8eceeed..35e6146 100644 --- a/resources/index.html +++ b/resources/index.html @@ -22,6 +22,43 @@
+ +
+
+ + Login or Register + +
+ +
+
+
+
+ + Please enter a username and password to login or register. + +
+
+
+ + Username: + + +
+
+ + Password: + + +
+
+
+ + +
+
+
+
diff --git a/resources/js/index.js b/resources/js/index.js index 8aaf05d..4f27c7d 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -284,6 +284,24 @@ async function closeSettings() { } } +async function openLogin() { + const login = document.querySelector('#loginPanel') + const ip = document.querySelector('#ip') + const ipDisplay = document.querySelector('#loginPopupServer') + + ipDisplay.innerText = ip.value + + if (login.style.display === 'none') { + login.style.removeProperty('display') + } +} + +async function closeLogin() { + const login = document.querySelector('#loginPanel') + + login.style.display = 'none' +} + async function closeFirstTimePopup() { const firstTimePopup = document.querySelector('#firstTimeNotice') firstTimePopup.style.display = 'none' diff --git a/resources/style/index.css b/resources/style/index.css index 048435a..fb81ac7 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -44,6 +44,45 @@ body { font-weight: bold; } +#loginPopupContentBody { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +#loginPopupContentBody div { + margin: 6px; +} + +#loginPopupContentBody input { + height: 20px; + background: white; + border: none; + border-bottom: 2px solid #4d4d4d; + + /* border bottom anim */ + transition: border-bottom 0.1s ease-in-out; +} + +#loginPopupContentBody input:focus { + outline: none; + border-bottom: 2px solid #ffc61e; +} + +#loginPopupTitle img { + height: 20px; +} + +#loginPopupTitle img:hover { + filter: invert(85%) sepia(31%) saturate(560%) hue-rotate(329deg) brightness(100%) contrast(92%); + cursor: pointer; +} + +#loginPopupServer { + font-weight: bold; +} + #firstTimeNotice, #loginPanel, #settingsPanel { From 6af6ce2848554d28365f747d200548379bf91175 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 20:17:20 -0700 Subject: [PATCH 102/248] use neutralino binary with disabled web security --- setup_win.cmd | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 setup_win.cmd diff --git a/setup_win.cmd b/setup_win.cmd new file mode 100644 index 0000000..b45a354 --- /dev/null +++ b/setup_win.cmd @@ -0,0 +1,8 @@ +@echo off + +set BINARY_URL="https://github.com/SpikeHD/neutralinojs/releases/latest/download/neutralino-win_x64.exe" + +call npm install + +:: Use powershell to download the binary +powershell Invoke-WebRequest -Uri %BINARY_URL% -OutFile "./bin/neutralino-win_x64.exe" \ No newline at end of file From 767d9fd234ca86d7f30ec7283754b04a79fb5c9d Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 20:17:29 -0700 Subject: [PATCH 103/248] login functions --- README.md | 2 +- resources/index.html | 48 +++++++++++++++++++++++---- resources/js/index.js | 6 ++-- resources/js/login.js | 70 +++++++++++++++++++++++++++++++++++++++ resources/style/index.css | 42 ++++++++++++++++++++--- 5 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 resources/js/login.js diff --git a/README.md b/README.md index 0f77f62..7656519 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Grasscutter launcher for easily switching between Official and Private servers 0. Clone the repository 1. Ensure you have [NodeJS](https://nodejs.org/en/download/) installed. 2. Install the `neu` CLI tool: `npm install -g @neutralinojs/neu` -3. Install the dependencies: `npm install` AND `neu update` +3. Install the dependencies: `setup_win.cmd` 4. Compile and run: * For testing: `npm run dev` * For production: `npm run build` diff --git a/resources/index.html b/resources/index.html index dc2e221..1780835 100644 --- a/resources/index.html +++ b/resources/index.html @@ -9,6 +9,7 @@ + @@ -26,19 +27,22 @@ @@ -98,6 +105,12 @@
+ + +
diff --git a/resources/js/authAlert.js b/resources/js/authAlert.js new file mode 100644 index 0000000..9b3f462 --- /dev/null +++ b/resources/js/authAlert.js @@ -0,0 +1,50 @@ +let alertTimeout, alertCooldown = 3000 + +async function displayLoginAlert(message, type) { + const elm = document.getElementById('loginAlert'); + const text = document.getElementById('loginAlertText'); + + elm.style.removeProperty('display'); + + switch(type) { + case 'error': + elm.classList.add('error'); + break; + + case 'warn': + default: + elm.classList.add('warn'); + break; + } + + text.innerText = message; + + // Disappear after 5 seconds + alertTimeout = setTimeout(() => { + elm.style.display = 'none'; + }, alertCooldown) +} + +async function displayRegisterAlert(message, type) { + const elm = document.getElementById('registerAlert'); + + elm.style.removeProperty('display'); + + switch(type) { + case 'error': + elm.classList.add('error'); + break; + + case 'warn': + default: + elm.classList.add('warn'); + break; + } + + text.innerText = message; + + // Disappear after 5 seconds + alertTimeout = setTimeout(() => { + elm.style.display = 'none'; + }, alertCooldown) +} \ No newline at end of file diff --git a/resources/js/login.js b/resources/js/login.js index 224c507..1b13d1b 100644 --- a/resources/js/login.js +++ b/resources/js/login.js @@ -63,13 +63,12 @@ async function login() { } const { data } = await axios.post(url + '/grasscutter/login', reqBody) - const tkData = parseJwt(data.jwt) console.log(data) switch(data.message) { case 'INVALID_ACCOUNT': - // Username or password invalid + displayLoginAlert('Invalid username or password', 'error'); break; case 'NO_PASSWORD': @@ -86,6 +85,7 @@ async function login() { default: // Success! Copy the JWT token to their clipboard + const tkData = parseJwt(data.jwt) await Neutralino.clipboard.writeText(tkData.token) break; } diff --git a/resources/style/index.css b/resources/style/index.css index c330a35..a164105 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -117,6 +117,36 @@ body { margin-right: 6px; } +.error { + background: #e90000; +} + +#registerAlert .warn, +#loginAlert .warn { + +} + +#registerAlert, +#loginAlert { + display: flex; + justify-content: center; + align-items: center; + border-radius: 5px; + color: #fff; +} + +#registerAlert img, +#loginAlert img { + height: 20px; + margin: 10px; + filter: invert(100%) sepia(0%) saturate(179%) hue-rotate(253deg) brightness(105%) contrast(101%); +} + +#registerAlert span, +#loginAlert span { + margin: 10px; +} + #firstTimeNotice, #loginPanel, #settingsPanel { From 7ef3d516fa6cb31ec4a9d8f2bacafd8d449d5fe1 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 22:24:45 -0700 Subject: [PATCH 111/248] alerts and logging in --- resources/js/authAlert.js | 21 +++++++++++++++------ resources/js/login.js | 22 ++++++++++++++++++---- resources/style/index.css | 10 +++++++--- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/resources/js/authAlert.js b/resources/js/authAlert.js index 9b3f462..476f21f 100644 --- a/resources/js/authAlert.js +++ b/resources/js/authAlert.js @@ -1,6 +1,6 @@ let alertTimeout, alertCooldown = 3000 -async function displayLoginAlert(message, type) { +async function displayLoginAlert(message, type, cooldown = null) { const elm = document.getElementById('loginAlert'); const text = document.getElementById('loginAlertText'); @@ -11,6 +11,10 @@ async function displayLoginAlert(message, type) { elm.classList.add('error'); break; + case 'success': + elm.classList.add('success'); + break; + case 'warn': default: elm.classList.add('warn'); @@ -19,14 +23,15 @@ async function displayLoginAlert(message, type) { text.innerText = message; - // Disappear after 5 seconds + // Disappear after cooldown alertTimeout = setTimeout(() => { elm.style.display = 'none'; - }, alertCooldown) + }, cooldown || alertCooldown) } -async function displayRegisterAlert(message, type) { +async function displayRegisterAlert(message, type, cooldown = null) { const elm = document.getElementById('registerAlert'); + const text = document.getElementById('registerAlertText'); elm.style.removeProperty('display'); @@ -35,6 +40,10 @@ async function displayRegisterAlert(message, type) { elm.classList.add('error'); break; + case 'success': + elm.classList.add('success'); + break; + case 'warn': default: elm.classList.add('warn'); @@ -43,8 +52,8 @@ async function displayRegisterAlert(message, type) { text.innerText = message; - // Disappear after 5 seconds + // Disappear after cooldown alertTimeout = setTimeout(() => { elm.style.display = 'none'; - }, alertCooldown) + }, cooldown || alertCooldown) } \ No newline at end of file diff --git a/resources/js/login.js b/resources/js/login.js index 1b13d1b..388acba 100644 --- a/resources/js/login.js +++ b/resources/js/login.js @@ -64,8 +64,6 @@ async function login() { const { data } = await axios.post(url + '/grasscutter/login', reqBody) - console.log(data) - switch(data.message) { case 'INVALID_ACCOUNT': displayLoginAlert('Invalid username or password', 'error'); @@ -73,20 +71,25 @@ async function login() { case 'NO_PASSWORD': // No account password, create one with change password + displayLoginAlert('No password set, please change password', 'warn'); break; case 'UNKNOWN': // Unknown error, contact server owner + displayLoginAlert('Unknown error, contact server owner', 'error'); break; case 'AUTH_DISABLED': // Authentication is disabled, we can just connect the user + displayLoginAlert('Authentication is disabled, no need to log in!', 'warn'); break; default: // Success! Copy the JWT token to their clipboard const tkData = parseJwt(data.jwt) await Neutralino.clipboard.writeText(tkData.token) + + displayLoginAlert('Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000); break; } } @@ -112,23 +115,34 @@ async function register() { const { data } = await axios.post(url + '/grasscutter/register', reqBody) - console.log(data) - switch(data.message) { case 'USERNAME_TAKEN': // Username is taken + displayRegisterAlert('Username is taken', 'error'); break; case 'PASSWORD_MISMATCH': // The password and password confirmation do not match + displayRegisterAlert('Password and password confirmation do not match', 'error'); break; case 'UNKNOWN': // Unknown error, contact server owner + displayRegisterAlert('Unknown error, contact server owner', 'error'); break; case 'AUTH_DISABLED': // Authentication is disabled, we can just connect the user + displayRegisterAlert('Authentication is disabled, no need to register!', 'warn'); + break; + + default: + // Success!! Bring them to the login screen and auto-input their username + const loginUsername = document.getElementById('loginUsername'); + loginUsername.value = username; + + setLoginSection(); + displayLoginAlert('Registration successful!', 'success', 5000); break; } } diff --git a/resources/style/index.css b/resources/style/index.css index a164105..d66290f 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -34,7 +34,7 @@ body { } #loginPanel { - height: 40%; + height: 50%; width: 32%; } @@ -121,9 +121,12 @@ body { background: #e90000; } -#registerAlert .warn, -#loginAlert .warn { +.warn { + background: #ffc61e; +} +.success { + background: #00c200; } #registerAlert, @@ -133,6 +136,7 @@ body { align-items: center; border-radius: 5px; color: #fff; + text-align: center; } #registerAlert img, From 6db54958d52ca87bed6d1e27115fe533dee9c5ab Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 26 Apr 2022 22:53:55 -0700 Subject: [PATCH 112/248] only show login when it is enabled on the server --- resources/js/authAlert.js | 10 ++++++++++ resources/js/index.js | 19 ++++++++++++++++--- resources/js/login.js | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/resources/js/authAlert.js b/resources/js/authAlert.js index 476f21f..fa2bed0 100644 --- a/resources/js/authAlert.js +++ b/resources/js/authAlert.js @@ -6,6 +6,11 @@ async function displayLoginAlert(message, type, cooldown = null) { elm.style.removeProperty('display'); + // Remove classification classes + elm.classList.remove('error'); + elm.classList.remove('success'); + elm.classList.remove('warn'); + switch(type) { case 'error': elm.classList.add('error'); @@ -34,6 +39,11 @@ async function displayRegisterAlert(message, type, cooldown = null) { const text = document.getElementById('registerAlertText'); elm.style.removeProperty('display'); + + // Remove classification classes + elm.classList.remove('error'); + elm.classList.remove('success'); + elm.classList.remove('warn'); switch(type) { case 'error': diff --git a/resources/js/index.js b/resources/js/index.js index 0dee14e..fdece6c 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -286,12 +286,25 @@ async function closeSettings() { async function openLogin() { const login = document.querySelector('#loginPanel') - const ip = document.querySelector('#ip') + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value const loginIpDisplay = document.querySelector('#loginPopupServer') const registerIpDisplay = document.querySelector('#registerPopupServer') + + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`; - loginIpDisplay.innerText = ip.value - registerIpDisplay.innerText = ip.value + // Check if we even need to authenticate + const { data } = await axios.get(url + '/grasscutter/auth_status') + + if (data.message !== 'AUTH_ENABLED') { + launchPrivate() + return + } + + loginIpDisplay.innerText = ip + registerIpDisplay.innerText = ip if (login.style.display === 'none') { login.style.removeProperty('display') diff --git a/resources/js/login.js b/resources/js/login.js index 388acba..085c3af 100644 --- a/resources/js/login.js +++ b/resources/js/login.js @@ -90,6 +90,7 @@ async function login() { await Neutralino.clipboard.writeText(tkData.token) displayLoginAlert('Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000); + launchPrivate() break; } } From bf06b92fde6a3943cd04e1212d3d91ea2dcffd41 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Wed, 27 Apr 2022 01:33:53 -0700 Subject: [PATCH 113/248] WIP: decryption --- resources/index.html | 3 ++ resources/js/registry.js | 83 +++++++++++++++++++++++++++++++ scripts/private_server_launch.cmd | 3 ++ 3 files changed, 89 insertions(+) create mode 100644 resources/js/registry.js diff --git a/resources/index.html b/resources/index.html index 906230d..297f5e8 100644 --- a/resources/index.html +++ b/resources/index.html @@ -3,10 +3,13 @@ + + + diff --git a/resources/js/registry.js b/resources/js/registry.js new file mode 100644 index 0000000..9cf29bf --- /dev/null +++ b/resources/js/registry.js @@ -0,0 +1,83 @@ +async function getGameRegistryKeys() { + const command = await Neutralino.os.execCommand(`reg query "HKEY_CURRENT_USER\\Software\\miHoYo\\Genshin Impact"`) + const desCommand = await Neutralino.os.execCommand(`powershell "get-netadapter | Select 'MacAddress'"`) + const macKeys = desCommand.stdOut.split('\n').map(l => l.replace(/-|\n|\r/g, '')).filter(l => l.length === 12) + const output = command.stdOut.split('\n').filter(l => l.includes('MIHOYOSDK_ADL_PROD'))[0] + const keys = output.split(' ').filter(l => l.length > 0) + const regObj = { + key: keys[0], + type: keys[1], + value: keys[2], + } + + // Remove last two zeros from hex data + const hexData = regObj.value.substring(0, regObj.value.length - 2) + + // Convert hex to ascii + let hexConvertedToAscii = hexToAscii(hexData) + + console.log(hexConvertedToAscii) + + // Decrypt ascii data as base64 + let base64Decrypt = window.Base64.decode(hexConvertedToAscii) + + console.log(base64Decrypt) + + for (const macKey of macKeys) { + // Get first 8 letters of the key + const key = macKey.substring(0, 8) + + console.log(key) + + // Decrypt the data with the key + const decrypted = decryptDes(base64Decrypt, key) + + // Decrypt the decrypted data from b64 + const b64Decrypt = atob(decrypted) + + console.log(decrypted) + console.log(b64Decrypt) + } + + // let c = '' + // let out = '' + + // for (const char of regObj.value) { + // if (c.length == 2) { + // out += String.fromCharCode(parseInt(c, 16)) + // c = '' + // } else { + // c += char + // } + // } + + let testStr = '' + + for (var i = 0; i < hexData.length; i += 2) { + testStr += hexData.substr(i, 2) + ' ' + } + + console.log(testStr) + + console.log(macKeys) + console.log('Original: ', regObj.value) + console.log('Hex decrypt: ', out) + console.log('Base64 Decrypt: ', window.atob(out)) +} + +function decryptDes(message, key) { + let keyWords = CryptoJS.enc.Utf8.parse(key); + let ivWords = CryptoJS.lib.WordArray.create([0, 0]); + + let decrypted = CryptoJS.DES.decrypt({ciphertext: message}, keyWords, { iv: ivWords }); + + return decrypted.toString(/* CryptoJS.enc.Utf8 */); +} + +function hexToAscii(hex) { + let str = ''; + for (var i = 0; i < hex.length; i += 2) { + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + return str; +} \ No newline at end of file diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index ae0b3e6..cfc3948 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -20,6 +20,9 @@ set ORIGIN=%5 set ORIGIN=%ORIGIN:"=% set ENABLE_KILLSWITCH=%6 +:: For registry +set GAME_REG="HKEY_CURRENT_USER\Software\miHoYo\Genshin Impact" + if "%ENABLE_KILLSWITCH%" EQU "true" ( :: Restart in elevated if need be >nul 2>&1 reg query "HKU\S-1-5-19" || ( From 71c3cc7837dc80e5e3227cc00463fc73c97e7856 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Wed, 27 Apr 2022 14:02:43 -0700 Subject: [PATCH 114/248] clean alert functions --- resources/js/authAlert.js | 42 +++++++++------------------------------ 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/resources/js/authAlert.js b/resources/js/authAlert.js index fa2bed0..c6b806e 100644 --- a/resources/js/authAlert.js +++ b/resources/js/authAlert.js @@ -1,42 +1,16 @@ let alertTimeout, alertCooldown = 3000 async function displayLoginAlert(message, type, cooldown = null) { - const elm = document.getElementById('loginAlert'); - const text = document.getElementById('loginAlertText'); - - elm.style.removeProperty('display'); - - // Remove classification classes - elm.classList.remove('error'); - elm.classList.remove('success'); - elm.classList.remove('warn'); - - switch(type) { - case 'error': - elm.classList.add('error'); - break; - - case 'success': - elm.classList.add('success'); - break; - - case 'warn': - default: - elm.classList.add('warn'); - break; - } - - text.innerText = message; - - // Disappear after cooldown - alertTimeout = setTimeout(() => { - elm.style.display = 'none'; - }, cooldown || alertCooldown) + displayAlert(message, type, cooldown, 'login') } async function displayRegisterAlert(message, type, cooldown = null) { - const elm = document.getElementById('registerAlert'); - const text = document.getElementById('registerAlertText'); + displayAlert(message, type, cooldown, 'register') +} + +function displayAlert(message, type, cooldown, name) { + const elm = document.getElementById(`${name}Alert`); + const text = document.getElementById(`${name}AlertText`); elm.style.removeProperty('display'); @@ -62,6 +36,8 @@ async function displayRegisterAlert(message, type, cooldown = null) { text.innerText = message; + clearTimeout(alertTimeout) + // Disappear after cooldown alertTimeout = setTimeout(() => { elm.style.display = 'none'; From c9c768c3cbf88e31b02b09cc6cb53535c64541de Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Wed, 27 Apr 2022 14:03:48 -0700 Subject: [PATCH 115/248] handle servers without auth endpoint --- resources/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/index.js b/resources/js/index.js index fdece6c..743eb58 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -298,7 +298,7 @@ async function openLogin() { // Check if we even need to authenticate const { data } = await axios.get(url + '/grasscutter/auth_status') - if (data.message !== 'AUTH_ENABLED') { + if (data?.message !== 'AUTH_ENABLED') { launchPrivate() return } From 987a73ea05ac17c04947277bc48c2f096804718b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Wed, 27 Apr 2022 14:05:17 -0700 Subject: [PATCH 116/248] helpful comment --- resources/js/registry.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources/js/registry.js b/resources/js/registry.js index 9cf29bf..4e3fa73 100644 --- a/resources/js/registry.js +++ b/resources/js/registry.js @@ -1,3 +1,10 @@ +/** + * IF YOU ARE LOOKING AT THIS CODE RIGHT NOW: NO YOU ARE NOT. + * + * THIS CODE IS BAD AND TERRIBLE AND EXPERIMENTAL AND IT WILL BE GOOD LATER. + * + * THIS FUNCTION DOES NOT WORK. + */ async function getGameRegistryKeys() { const command = await Neutralino.os.execCommand(`reg query "HKEY_CURRENT_USER\\Software\\miHoYo\\Genshin Impact"`) const desCommand = await Neutralino.os.execCommand(`powershell "get-netadapter | Select 'MacAddress'"`) From 1d202b7a189c8e279ade717ea6c6354a0e10a983 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Wed, 27 Apr 2022 14:28:58 -0700 Subject: [PATCH 117/248] full login translations --- languages/en.json | 24 +++++++++++++++++++++++- resources/index.html | 14 +++++++------- resources/js/index.js | 8 ++++---- resources/js/login.js | 25 +++++++++++++++---------- resources/js/translation.js | 16 +++++++++++++++- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/languages/en.json b/languages/en.json index b1249c3..c0d8cf7 100644 --- a/languages/en.json +++ b/languages/en.json @@ -39,5 +39,27 @@ "proxyInstallDeny": "No thanks", "gameFolderDialog": "Select game folder", - "grasscutterFileDialog": "Select Grasscutter server jar file" + "grasscutterFileDialog": "Select Grasscutter server jar file", + + "loggingInTo": "Logging in to: ", + "registeringFor": "Registering for: ", + "authUsername": "Username: ", + "authPassword": "Password: ", + "authConfirmPassword": "Confirm Password: ", + "authLoginBtn": "Login", + "authRegisterBtn": "Register", + "authLoginTitle": "Login", + "authRegisterTitle": "Register", + "launchWithoutAuth": "Launch without Authentication", + + "alertInvalid": "Invalid username or password", + "alertNoPass": "No password set, please change password", + "alertUnknown": "Unknown error, contact server owner", + "alertAuthNoLogin": "Authentication is disabled, no need to log in!", + "alertLoginSuccess": "Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.", + + "alertUserTaken": "Username is taken", + "alertPassMismatch": "Password and password confirmation do not match", + "alertAuthNoRegister": "Authentication is disabled, no need to register!", + "alertRegisterSuccess": "Registration successful!" } diff --git a/resources/index.html b/resources/index.html index 297f5e8..c971d61 100644 --- a/resources/index.html +++ b/resources/index.html @@ -44,18 +44,18 @@
- Logging in to + Logging in to
- + Username:
- + Password: @@ -82,24 +82,24 @@ + + +
+ + + A new update is available! Newest version: + +
diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 1beba4a..f4b9139 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -57,6 +57,37 @@ async function proxyIsInstalled() { return false } +async function checkForUpdates() { + const url = 'https://api.github.com/repos/Grasscutters/GrassClipper/releases/latest' + + const { data } = await axios.get(url) + const latest = data.tag_name + + return latest +} + +async function displayUpdate(version) { + const latest = await checkForUpdates() + const versionDisplay = document.querySelector('#newestVersion') + const notif = document.querySelector('#downloadNotif') + + //if (latest === `v${NL_APPVERSION}`) return + + versionDisplay.innerText = latest + + notif.classList.add('displayed') + + setTimeout(() => { + notif.classList.remove('displayed') + }, 5000) +} + +async function openLatestDownload() { + const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' + + Neutralino.os.open(downloadLink) +} + async function openGameFolder() { const config = await getCfg() const folder = config.gameexe.match(/.*\\/g, '')[0] diff --git a/resources/style/index.css b/resources/style/index.css index d66290f..ba41cd8 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -7,6 +7,10 @@ body { font-family: Arial, Helvetica, sans-serif; } +a { + color: #fff; +} + .darken { filter: brightness(0.6); } @@ -535,4 +539,43 @@ body { #serverInput img:hover { cursor: pointer; +} + +#downloadNotif { + z-index: 99; + position: absolute; + + color: #fff; + background: #141414; + border: 1px solid #ccc; + + padding: 1em; + top: 80%; + left: 110%; + width: 20%; + border-radius: 5px; + + text-align: center; + + transition: left 0.4s ease-in-out; +} + +#downloadNotif:hover { + cursor: pointer; + border-color: #fff; +} + +#downloadNotif img { + height: 20px; + vertical-align: middle; + margin-right: 4px; + filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(16deg) brightness(103%) contrast(101%); +} + +#downloadNotif.displayed { + left: 70%; +} + +#newestVersion { + font-weight: bold; } \ No newline at end of file From f8c75c0adc37409081f7257d145d34a7de885c08 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 30 Apr 2022 01:58:58 -0700 Subject: [PATCH 139/248] translation section for update notification --- languages/en.json | 4 +++- resources/js/helpers.js | 4 ++-- resources/js/translation.js | 3 +++ resources/style/index.css | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/languages/en.json b/languages/en.json index c0d8cf7..a7ecafe 100644 --- a/languages/en.json +++ b/languages/en.json @@ -61,5 +61,7 @@ "alertUserTaken": "Username is taken", "alertPassMismatch": "Password and password confirmation do not match", "alertAuthNoRegister": "Authentication is disabled, no need to register!", - "alertRegisterSuccess": "Registration successful!" + "alertRegisterSuccess": "Registration successful!", + + "updateNotifText": "A new update is available! Newest version: " } diff --git a/resources/js/helpers.js b/resources/js/helpers.js index f4b9139..c0b31c0 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -66,12 +66,12 @@ async function checkForUpdates() { return latest } -async function displayUpdate(version) { +async function displayUpdate() { const latest = await checkForUpdates() const versionDisplay = document.querySelector('#newestVersion') const notif = document.querySelector('#downloadNotif') - //if (latest === `v${NL_APPVERSION}`) return + if (latest === `v${NL_APPVERSION}`) return versionDisplay.innerText = latest diff --git a/resources/js/translation.js b/resources/js/translation.js index 3fab70b..986b03c 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -89,4 +89,7 @@ async function doTranslation() { set('loginPopupContentBodyBtnLogin', 'authLoginBtn') set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') set('noLoginBtn', 'launchWithoutAuth') + + // update notification + set('updateNotifText', 'updateNotifText') } \ No newline at end of file diff --git a/resources/style/index.css b/resources/style/index.css index ba41cd8..24e8e7c 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -551,13 +551,13 @@ a { padding: 1em; top: 80%; - left: 110%; + left: 120%; width: 20%; border-radius: 5px; text-align: center; - transition: left 0.4s ease-in-out; + transition: left 0.5s ease-in-out; } #downloadNotif:hover { From 9d4ba33b4fa0b8a775d870c206f47050c7363465 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 30 Apr 2022 01:59:14 -0700 Subject: [PATCH 140/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 36b208e..9a46930 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.3", + "version": "0.8.4", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index bfdf4bb..27bd869 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.3", + "version": "0.8.4", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 8710f58..380fbcc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.8.3", + "version": "0.8.4", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 5051e678ce9f34ee10f66e6d053c971984740348 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 30 Apr 2022 02:51:10 -0700 Subject: [PATCH 141/248] update proxy launch based on grasscutter --- resources/js/onLoad.js | 1 + scripts/private_server_launch.cmd | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index 88bfb85..a1e8773 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -4,6 +4,7 @@ * should be done here to ensure DOM contents are loaded. */ document.addEventListener('DOMContentLoaded', async () => { + displayUpdate(); setBackgroundImage(); displayGameFolder(); displayServerFolder(); diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index cfc3948..0cc7b12 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -41,7 +41,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 :: Start proxy server -start "Proxy Server" "%ORIGIN%/ext/mitmdump.exe" -s "%ORIGIN%/proxy/proxy.py" --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% From 7d5f0f355e564565fabdd8bff56ee28188a73939 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 30 Apr 2022 02:51:57 -0700 Subject: [PATCH 142/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 9a46930..3df9a34 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.4", + "version": "0.8.5", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 27bd869..7abf636 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.4", + "version": "0.8.5", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 380fbcc..196bce7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.8.4", + "version": "0.8.5", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 51306d3ef98ce19267dd5302a7ab9bd1de2a58ec Mon Sep 17 00:00:00 2001 From: Kormi Meiko <59416791+KormiMeiko@users.noreply.github.com> Date: Sat, 30 Apr 2022 20:11:02 +0800 Subject: [PATCH 143/248] Update zh-tw.json --- languages/zh-tw.json | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/languages/zh-tw.json b/languages/zh-tw.json index 266dbeb..e63374a 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -39,4 +39,26 @@ "gameFolderDialog": "選擇Genshin Impact game資料夾", "grasscutterFileDialog": "選擇Grasscutter.jar檔案" -} \ No newline at end of file + + "loggingInTo": "登錄至:", + "registeringFor": "註冊至:", + "authUsername": "用戶名: ", + "authPassword": "密碼: ", + "authConfirmPassword": "再次確認密碼: ", + "authLoginBtn": "登錄", + "authRegisterBtn": "註冊", + "authLoginTitle": "登錄", + "authRegisterTitle": "註冊", + "launchWithoutAuth": "在未認證的情況下啟動", + + "alertInvalid": "無效的用戶名或密碼", + "alertNoPass": "未設定密碼,請先更改密碼", + "alertUnknown": "未知錯誤,請聯系服務器管理員", + "alertAuthNoLogin": "未啟用認證,無需登錄!", + "alertLoginSuccess": "登錄成功!Token 已復製至剪切板。將 Token 粘貼至用戶名處即可登錄。", + + "alertUserTaken": "用戶名已被占用", + "alertPassMismatch": "密碼與確認密碼不匹配", + "alertAuthNoRegister": "未啟用認證,無需註冊!", + "alertRegisterSuccess": "註冊成功!" +} From 9e921abac01bcdca291631947257a59ca19944cc Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 30 Apr 2022 05:48:44 -0700 Subject: [PATCH 144/248] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 979c6d1..c04879b 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ The launcher most likely did not close correctly, and was unable to clean your p Thank you to everyone who has provided translations! <3 * ZH - nuoxianCN, Scirese & MrAru -* ZH-TW - Kimi +* ZH-TW - Kimi & KormiMeiko * PT-BR - na.na * VIE - labalityowo * ID - Iqrar99 From d8eba157fd7cc005413d09180346f612426c39ae Mon Sep 17 00:00:00 2001 From: Kimi <34180607+Kimi898246@users.noreply.github.com> Date: Sun, 1 May 2022 01:30:28 +0800 Subject: [PATCH 145/248] Traditional Chinese | Translation Patches Since authentication haven't been implemented in many server yet, I can't verify what can be edited or not, will do one more PR after I can see what I can change. --- languages/zh-tw.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/languages/zh-tw.json b/languages/zh-tw.json index e63374a..d1db5d7 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -51,14 +51,16 @@ "authRegisterTitle": "註冊", "launchWithoutAuth": "在未認證的情況下啟動", - "alertInvalid": "無效的用戶名或密碼", + "alertInvalid": "用戶名或密碼不正確。", "alertNoPass": "未設定密碼,請先更改密碼", - "alertUnknown": "未知錯誤,請聯系服務器管理員", + "alertUnknown": "未知錯誤,請聯系伺服器管理員", "alertAuthNoLogin": "未啟用認證,無需登錄!", - "alertLoginSuccess": "登錄成功!Token 已復製至剪切板。將 Token 粘貼至用戶名處即可登錄。", + "alertLoginSuccess": "登錄成功!Token 已複製至剪切板。將 Token 貼上至用戶名處即可登錄。", "alertUserTaken": "用戶名已被占用", - "alertPassMismatch": "密碼與確認密碼不匹配", + "alertPassMismatch": "兩組密碼不一致", "alertAuthNoRegister": "未啟用認證,無需註冊!", "alertRegisterSuccess": "註冊成功!" + + "updateNotifText": "有新的GrassClipper更新可用! 最新版本: " } From 9eb50c68bf33183da32bb69dd7e56cd7d44e94f5 Mon Sep 17 00:00:00 2001 From: Kimi <34180607+Kimi898246@users.noreply.github.com> Date: Sun, 1 May 2022 01:35:03 +0800 Subject: [PATCH 146/248] Update zh-tw.json --- languages/zh-tw.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages/zh-tw.json b/languages/zh-tw.json index d1db5d7..d551fb9 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -55,7 +55,7 @@ "alertNoPass": "未設定密碼,請先更改密碼", "alertUnknown": "未知錯誤,請聯系伺服器管理員", "alertAuthNoLogin": "未啟用認證,無需登錄!", - "alertLoginSuccess": "登錄成功!Token 已複製至剪切板。將 Token 貼上至用戶名處即可登錄。", + "alertLoginSuccess": "登錄成功!Token 已複製至剪貼簿。將 Token 複製到用戶名處即可登錄。", "alertUserTaken": "用戶名已被占用", "alertPassMismatch": "兩組密碼不一致", From 5520a11266cecd5543644eed8fd490270733eb24 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 30 Apr 2022 23:09:52 -0700 Subject: [PATCH 147/248] scroll through settings --- resources/style/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/style/index.css b/resources/style/index.css index 24e8e7c..ff31870 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -175,7 +175,7 @@ a { #settingsPanel { width: 35%; height: 80%; - overflow: hidden; + overflow: auto; } #fullSettingsTitle { From 90a7d62536fd440a7a5361e3fa4f7106011b9018 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sat, 30 Apr 2022 23:15:57 -0700 Subject: [PATCH 148/248] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c04879b..2b89598 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,9 @@ If all else fails, you can run GrassClipper in `chrome` or `browser` mode. To do ## Error 502 -If you are getting an error 502 when attempting to log in, open your Grasscutter config and add the following to the `DispatchServer` section: +First, if you are running a local server, ensure the local server is running. Otherwise, ensure the server you are connecting to is actually running. + +If you are still getting an error 502 when attempting to log in to your own server, open your Grasscutter config and add the following to the `DispatchServer` section: ```json "PublicPort": YOUR_PORT From 0f98d90da906f56b5c97ebe069b14687a19d21e1 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 16:52:48 -0700 Subject: [PATCH 149/248] more 443 defaults --- proxy/proxy.py | 2 +- resources/js/index.js | 2 +- resources/js/options.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/proxy.py b/proxy/proxy.py index e6bf383..50da319 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -37,7 +37,7 @@ class MlgmXyysd_Anime_Game_Proxy: loader.add_option( name = "port", typespec = int, - default = 80, + default = 443, help = "Port to replace", ) diff --git a/resources/js/index.js b/resources/js/index.js index 3070a54..0a4e2ce 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -172,7 +172,7 @@ async function setBackgroundImage() { */ async function handleFavoriteInput() { const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value + const port = document.querySelector('#port').value || '443' const ipArr = await getFavIps() const addr = `${ip}:${port}` diff --git a/resources/js/options.js b/resources/js/options.js index 1b74f53..58da7f6 100644 --- a/resources/js/options.js +++ b/resources/js/options.js @@ -88,7 +88,7 @@ async function handleLanguageChange(elm) { */ async function setFavorite() { const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value + const port = document.querySelector('#port').value || '443' const ipArr = await getFavIps() const addr = `${ip}:${port}` From 8190219157ca75a50fe5014d94181d23a7c44c2b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 17:25:01 -0700 Subject: [PATCH 150/248] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b89598..075efb4 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,9 @@ If all else fails, you can run GrassClipper in `chrome` or `browser` mode. To do ## Error 502 -First, 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. If you are still getting an error 502 when attempting to log in to your own server, open your Grasscutter config and add the following to the `DispatchServer` section: From cc1cf9297040cd3491a9a01706edf728632a90b7 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 17:48:19 -0700 Subject: [PATCH 151/248] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 075efb4..4b87515 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Grasscutter launcher for easily switching between Official and Private servers * [Common Problems](#having-problems) * [White Screen Fix](#white-screen-fix) * [Error 502](#error-502) + * [Error 4206](#error-4206) * [Infinite CMD Windows](#infinite-cmd-windows) * [Broken Discord/Youtube](#my-discord-is-not-letting-me-send-messages-or-load-images-my-youtube-is-acting-strange) * [No internet](#i-have-no-internet-after-closing-everything-restarting-my-pc) @@ -88,6 +89,10 @@ If you are still getting an error 502 when attempting to log in to your own serv ``` where `YOUR_PORT` is the same port you use as the `Port` value already. This will probably be 443. +## Error 4206 + +Ensure you have the correct `keystore.p12` file that comes with your branch (`stable` or `development`). Also ensure the password is set properly in Grasscutters `config.json` (blank for `stable`, "123456" for `development`). + ## Infinite CMD Windows If you are getting infinite CMD windows for any of the scripts (such as the proxy installation, or private server start), ensure you have UAC (user access control) set to any option that requires asking. Ensure your user account can open things as Admin. From 121581e460f5f2e44543a2a4e1f43a26ed0fadeb Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:09:10 -0700 Subject: [PATCH 152/248] download script for gc --- .gitignore | 1 + resources/index.html | 1 + resources/js/gcdownloader.js | 24 ++++++++++++++++++++++++ resources/js/helpers.js | 1 + scripts/gcdownload.cmd | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 resources/js/gcdownloader.js create mode 100644 scripts/gcdownload.cmd diff --git a/.gitignore b/.gitignore index 2ccb550..66207a5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ bin/ dist/ ext/ temp/ +gc*/ resources/js/neutralino.js resources/bg/official diff --git a/resources/index.html b/resources/index.html index f59f5ea..81a7e7a 100644 --- a/resources/index.html +++ b/resources/index.html @@ -8,6 +8,7 @@ + diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js new file mode 100644 index 0000000..c1b5e1b --- /dev/null +++ b/resources/js/gcdownloader.js @@ -0,0 +1,24 @@ +async function clearGCInstallation() { + Neutralino.os.execCommand(`del /s /q "./gc"`) +} + +async function downloadGC(branch) { + const config = await getCfg() + + // If we are pulling from a new branch, delete the old installation + if (config.grasscutterBranch !== branch) await clearGCInstallation() + + // 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` + + // Run installer + createCmdWindow(`.\\scripts\\gcdownload.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + + // Set current installation in config + config.grasscutterBranch = branch + + Neutralino.storage.setData('config', JSON.stringify(config)) +} \ No newline at end of file diff --git a/resources/js/helpers.js b/resources/js/helpers.js index c0b31c0..ad313fa 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -12,6 +12,7 @@ serverLaunchPanel: false, language: 'en', useHttps: true, + grasscutterBranch: '', } const cfgStr = await Neutralino.storage.getData('config').catch(e => { // The data isn't set, so this is our first time opening diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd new file mode 100644 index 0000000..9105de2 --- /dev/null +++ b/scripts/gcdownload.cmd @@ -0,0 +1,34 @@ +@echo off + +set KEYSTORE_URL=%1 +set ARTIFACT_URL=%2 +set BRANCH=%3 +set FOLDER_NAME=".\gc-%BRANCH%" + +if not exist %FOLDER_NAME% mkdir %FOLDER_NAME% +if not exist ".\temp" mkdir ".\temp" + +echo Downloading Grasscutter prebuilt jar... + +:: Download the jar +powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" + +echo Extracting... + +powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath %FOLDER_NAME% -Force + +:: Download the keystore.p12 file + +echo Downloading keystore.p12... + +powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" + +:: Remove temp stuff +del /s /q "./temp" + +echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% + +pause + +exit /b + From e6642c897105da70153e2fa3eb5d39ae4cc310f1 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:34:10 -0700 Subject: [PATCH 153/248] fix gc downloader script --- resources/js/gcdownloader.js | 3 +++ scripts/gcdownload.cmd | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index c1b5e1b..0786abe 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -20,5 +20,8 @@ async function downloadGC(branch) { // Set current installation in config config.grasscutterBranch = branch + // Set gc path for people with launcher enabled + config.serverFolder = `${NL_CWD}\\gc-${branch}\\` + Neutralino.storage.setData('config', JSON.stringify(config)) } \ No newline at end of file diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd index 9105de2..3c6c05d 100644 --- a/scripts/gcdownload.cmd +++ b/scripts/gcdownload.cmd @@ -4,8 +4,9 @@ set KEYSTORE_URL=%1 set ARTIFACT_URL=%2 set BRANCH=%3 set FOLDER_NAME=".\gc-%BRANCH%" +set FOLDER_NAME=%FOLDER_NAME:"=% -if not exist %FOLDER_NAME% mkdir %FOLDER_NAME% +if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" if not exist ".\temp" mkdir ".\temp" echo Downloading Grasscutter prebuilt jar... @@ -15,12 +16,20 @@ powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" echo Extracting... -powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath %FOLDER_NAME% -Force +:: Delete old file if there is one there +if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar" -:: Download the keystore.p12 file +powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force + +:: Find the jar file name and rename it, just in case +for %%i in (%FOLDER_NAME%/*) do ( + :: If the extension is jar, rename the file + if %%~xi equ .jar rename "%FOLDER_NAME%\%%i" grasscutter.jar +) echo Downloading keystore.p12... +:: Download the keystore.p12 file powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" :: Remove temp stuff From 4813d413eb61c23da9421e90627df92ca20882c9 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:39:47 -0700 Subject: [PATCH 154/248] extra fixes --- resources/js/gcdownloader.js | 5 ++++- scripts/gcdownload.cmd | 4 +++- scripts/install.cmd | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 0786abe..454c7b6 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -21,7 +21,10 @@ async function downloadGC(branch) { config.grasscutterBranch = branch // Set gc path for people with launcher enabled - config.serverFolder = `${NL_CWD}\\gc-${branch}\\` + config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` Neutralino.storage.setData('config', JSON.stringify(config)) + + // Display folder after saving config + displayServerFolder() } \ No newline at end of file diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd index 3c6c05d..576d117 100644 --- a/scripts/gcdownload.cmd +++ b/scripts/gcdownload.cmd @@ -6,6 +6,8 @@ set BRANCH=%3 set FOLDER_NAME=".\gc-%BRANCH%" set FOLDER_NAME=%FOLDER_NAME:"=% +title GC Download Script + if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" if not exist ".\temp" mkdir ".\temp" @@ -39,5 +41,5 @@ echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% pause -exit /b +taskkill /f /fi "WINDOWTITLE eq GC Download Script" diff --git a/scripts/install.cmd b/scripts/install.cmd index 99e27c3..6e1f7a3 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -3,6 +3,8 @@ set ORIGIN=%1 set ORIGIN=%ORIGIN:"=% +title Grassclipper Installer + echo Downloading proxy server... :: Make sure we are in the right directory @@ -48,4 +50,4 @@ echo Done! You can now open GrassClipper.exe! pause -exit /b \ No newline at end of file +taskkill /f /fi "WINDOWTITLE eq Grassclipper Installer" \ No newline at end of file From a618ae471d4abd8beac90d57faf896382f7f7e6b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:43:57 -0700 Subject: [PATCH 155/248] fix server launcher script --- scripts/local_server_launch.cmd | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/local_server_launch.cmd b/scripts/local_server_launch.cmd index e052d1a..75dde1f 100644 --- a/scripts/local_server_launch.cmd +++ b/scripts/local_server_launch.cmd @@ -3,15 +3,23 @@ set GRASSCUTTER_JAR=%1 set GRASSCUTTER_JAR=%GRASSCUTTER_JAR:"=% +title Grasscutter + :: Get folder the jar is in set "X=%GRASSCUTTER_JAR%" :l -if "%X:~-1%"=="\" goto al -set "X=%X:~0,-1%" -goto l + set IS_SLASH=false + + if "%X:~-1%"=="\" set IS_SLASH=true + if "%X:~-1%"=="/" set IS_SLASH=true + + if %IS_SLASH% equ true goto al + + set "X=%X:~0,-1%" + goto l :al -set "X=%X:~0,-1%" -set "GRASSCUTTER_ROOT=%X%" + set "X=%X:~0,-1%" + set "GRASSCUTTER_ROOT=%X%" echo Starting local Grasscutter server... From 1430e979a0d0695a24b1a8cf6ca34cff2366d651 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 21:05:24 -0700 Subject: [PATCH 156/248] resource downloader --- resources/js/gcdownloader.js | 2 +- scripts/gcdownload.cmd | 45 ------------------------------------ 2 files changed, 1 insertion(+), 46 deletions(-) delete mode 100644 scripts/gcdownload.cmd diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 454c7b6..d20399e 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -15,7 +15,7 @@ async function downloadGC(branch) { const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip` // Run installer - createCmdWindow(`.\\scripts\\gcdownload.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) // Set current installation in config config.grasscutterBranch = branch diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd deleted file mode 100644 index 576d117..0000000 --- a/scripts/gcdownload.cmd +++ /dev/null @@ -1,45 +0,0 @@ -@echo off - -set KEYSTORE_URL=%1 -set ARTIFACT_URL=%2 -set BRANCH=%3 -set FOLDER_NAME=".\gc-%BRANCH%" -set FOLDER_NAME=%FOLDER_NAME:"=% - -title GC Download Script - -if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" -if not exist ".\temp" mkdir ".\temp" - -echo Downloading Grasscutter prebuilt jar... - -:: Download the jar -powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" - -echo Extracting... - -:: Delete old file if there is one there -if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar" - -powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force - -:: Find the jar file name and rename it, just in case -for %%i in (%FOLDER_NAME%/*) do ( - :: If the extension is jar, rename the file - if %%~xi equ .jar rename "%FOLDER_NAME%\%%i" grasscutter.jar -) - -echo Downloading keystore.p12... - -:: Download the keystore.p12 file -powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" - -:: Remove temp stuff -del /s /q "./temp" - -echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% - -pause - -taskkill /f /fi "WINDOWTITLE eq GC Download Script" - From 1e197005e3675c981cee7c66fde7a6eac477cdaf Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 21:07:09 -0700 Subject: [PATCH 157/248] resource downloader (fr this time) --- scripts/gc_download.cmd | 55 ++++++++++++++++++++++++++++++++++ scripts/resources_download.cmd | 29 ++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 scripts/gc_download.cmd create mode 100644 scripts/resources_download.cmd diff --git a/scripts/gc_download.cmd b/scripts/gc_download.cmd new file mode 100644 index 0000000..1b24f2b --- /dev/null +++ b/scripts/gc_download.cmd @@ -0,0 +1,55 @@ +@echo off + +set KEYSTORE_URL=%1 +set ARTIFACT_URL=%2 +set BRANCH=%3 +set FOLDER_NAME=".\gc-%BRANCH%" +set FOLDER_NAME=%FOLDER_NAME:"=% + +title GC Download Script + +if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" +if not exist ".\temp" mkdir ".\temp" + +echo Downloading Grasscutter prebuilt jar... + +:: Download the jar +powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" + +echo Extracting... + +:: Delete old file if there is one there +if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar" + +powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force + +:: Find the jar file name and rename it, just in case +for %%i in (%FOLDER_NAME%/*) do ( + :: If the extension is jar, rename the file + if %%~xi equ .jar rename "%FOLDER_NAME%\%%i" grasscutter.jar +) + +echo Downloading keystore.p12... + +:: Download the keystore.p12 file +powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" + +:: Allow resource downloading to be optional, since it takes a while +set REPLY=y +set /p "REPLY=Download server resources? (This can take a while) [y|n]:" +if /i not "%reply%" == "y" goto :finish + +call .\scripts\resources_download.cmd %FOLDER_NAME% + +goto :finish + +:finish + :: Remove temp stuff + del /s /q "./temp" + + echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% + + pause + + taskkill /f /fi "WINDOWTITLE eq GC Download Script" + diff --git a/scripts/resources_download.cmd b/scripts/resources_download.cmd new file mode 100644 index 0000000..f1e1574 --- /dev/null +++ b/scripts/resources_download.cmd @@ -0,0 +1,29 @@ +@echo off + +set FOLDER_NAME=%1 +set FOLDER_NAME=%FOLDER_NAME:"=% + +if not exist ".\temp" mkdir ".\temp" +if not exist ".\resources" mkdir ".\resources" + +echo Downloading resources, this can take a while... + +:: 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" + +echo Extracting... + +:: Extract resources to the folder +powershell Expand-Archive -Path "./temp/resources.zip" -DestinationPath "%FOLDER_NAME%" -Force + +:: Delete old resources folder if there is one there +del /s /q "%FOLDER_NAME%\resources">nul + +echo Moving resources to folder... + +robocopy "%FOLDER_NAME%\Grasscutter_Resources-main\Resources" "%FOLDER_NAME%\resources" /E /MOVE>nul + +:: Delete straggling files +del /s /q "%FOLDER_NAME%\Grasscutter_Resources-main" + +echo Done, resources should be properly extracted \ No newline at end of file From 5ad961d2187a42a08a8f279a6c76518b6e978746 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:19:32 -0700 Subject: [PATCH 158/248] download data and key files --- resources/js/gcdownloader.js | 47 +++++++++++++++++++++++++++++------- resources/js/helpers.js | 2 +- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index d20399e..29eb8a2 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -8,15 +8,6 @@ async function downloadGC(branch) { // If we are pulling from a new branch, delete the old installation if (config.grasscutterBranch !== branch) await clearGCInstallation() - // 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` - - // Run installer - createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) - // Set current installation in config config.grasscutterBranch = branch @@ -24,6 +15,44 @@ async function downloadGC(branch) { config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` Neutralino.storage.setData('config', JSON.stringify(config)) + + // 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 + const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) + const dataList = dataFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + + // For key files + const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) + const keyList = keyFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + + const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') + + // Download data files + for (const o of dataList) { + const folder = 'data' + Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } + + // Download each file + for (const o of keyList) { + const folder = 'keys' + Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } + + return; + + // Run installer + createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + // Display folder after saving config displayServerFolder() diff --git a/resources/js/helpers.js b/resources/js/helpers.js index ad313fa..4e3a38b 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -98,7 +98,7 @@ async function openGameFolder() { async function openGrasscutterFolder() { const config = await getCfg() - const folder = config.serverFolder.match(/.*\\/g, '')[0] + const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] openInExplorer(folder) } From a52d42538a8a8c471bcdd3d4aba0a9081356b15d Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:23:33 -0700 Subject: [PATCH 159/248] ensure folders exist --- resources/js/gcdownloader.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 29eb8a2..960a757 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -36,16 +36,21 @@ async function downloadGC(branch) { const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') + // Ensure data and key folders exist + + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) + // Download data files for (const o of dataList) { const folder = 'data' - Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) } - // Download each file + // Download key files for (const o of keyList) { const folder = 'keys' - Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) } return; From 8ed80bc55fbf2a6ce74d348739555d9451645e9d Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:24:45 -0700 Subject: [PATCH 160/248] re-enable full installer --- resources/js/gcdownloader.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 960a757..257a5f5 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -52,8 +52,6 @@ async function downloadGC(branch) { const folder = 'keys' await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) } - - return; // Run installer createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) From 8971cee64f3ede87ab5d0dbf9eb702847d7f2c2f Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:56:15 -0700 Subject: [PATCH 161/248] begin downloads panel --- resources/index.html | 27 +++++++++++++++++++++++++++ resources/js/gcdownloader.js | 1 - resources/js/index.js | 14 ++++++++++++++ resources/style/index.css | 13 +++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/resources/index.html b/resources/index.html index 81a7e7a..ed5353e 100644 --- a/resources/index.html +++ b/resources/index.html @@ -115,6 +115,28 @@
+ + + +
diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 257a5f5..f101690 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -56,7 +56,6 @@ async function downloadGC(branch) { // Run installer createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) - // Display folder after saving config displayServerFolder() } \ No newline at end of file diff --git a/resources/js/index.js b/resources/js/index.js index 0a4e2ce..b25a6e7 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -246,6 +246,20 @@ async function handleFavoriteList() { } } +async function openDownloads() { + const downloads = document.querySelector('#downloadPanel') + + if (downloads.style.display === 'none') { + downloads.style.removeProperty('display') + } +} + +async function closeDownloads() { + const downloads = document.querySelector('#downloadPanel') + + downloads.style.display = 'none' +} + async function openSettings() { const settings = document.querySelector('#settingsPanel') const config = await getCfg() diff --git a/resources/style/index.css b/resources/style/index.css index ff31870..0b16237 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -157,6 +157,7 @@ a { #firstTimeNotice, #loginPanel, +#downloadPanel, #settingsPanel { display: block; position: absolute; @@ -172,6 +173,7 @@ a { font-family: system-ui; } +#downloadPanel, #settingsPanel { width: 35%; height: 80%; @@ -184,6 +186,7 @@ a { margin-bottom: 10px; } +#downloadPanelInner, #settingsPanelInner { display: flex; flex-direction: column; @@ -192,16 +195,19 @@ a { padding: 10px 10%; } +.downloadRow, .settingsRow { width: 100%; } +.downloadTitle, .settingTitle { font-size: 1.2em; font-weight: bold; margin-bottom: 10px; } +.downloadLabel, .settingLabel { display:inline-block; font-size: 1em; @@ -209,12 +215,14 @@ a { margin: 10px 0px; } +.downloadSubtitle, .settingSubtitle { color: rgb(165, 165, 165); font-size: 0.8em; font-weight: normal; } +.downloadSection, .settingSection { display: flex; flex-direction: row; @@ -222,10 +230,12 @@ a { justify-content: space-between; } +.downloadSection .smolBtn, .settingSection .smolBtn { height: 30px; } +#downloadTitleBar #settingsTitleBar { display: flex; flex-direction: row; @@ -233,15 +243,18 @@ a { justify-content: space-between; } +#downloadClose, #settingsClose { display: inline-block; transition: filter 0.1s ease-in-out; } +#downloadClose img, #settingsClose img { height: 20px; } +#downloadClose:hover, #settingsClose:hover { filter: invert(85%) sepia(31%) saturate(560%) hue-rotate(329deg) brightness(100%) contrast(92%); cursor: pointer; From 1754638ab54ea13b4d879975e85bb261149df8a8 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:59:11 -0700 Subject: [PATCH 162/248] small styling fixes --- resources/index.html | 10 ++++------ resources/style/index.css | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/resources/index.html b/resources/index.html index ed5353e..2d63c3a 100644 --- a/resources/index.html +++ b/resources/index.html @@ -117,12 +117,10 @@ From b936a4f7b2d6f89f934aa7dc2bf28b35aac4968c Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:09:20 -0700 Subject: [PATCH 164/248] download page open/close --- resources/icons/download.svg | 11 +++++++++++ resources/index.html | 13 +++++++++++-- resources/js/index.js | 10 ++++++++++ resources/style/index.css | 4 ++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 resources/icons/download.svg diff --git a/resources/icons/download.svg b/resources/icons/download.svg new file mode 100644 index 0000000..8baf9ed --- /dev/null +++ b/resources/icons/download.svg @@ -0,0 +1,11 @@ + +Created with Fabric.js 1.7.22 + + + + + + + + + \ No newline at end of file diff --git a/resources/index.html b/resources/index.html index 41b951e..6b86265 100644 --- a/resources/index.html +++ b/resources/index.html @@ -134,7 +134,7 @@
- Download Stable Build + Download Grasscutter Stable Build
@@ -143,13 +143,22 @@
- Download Development Build + Download Grasscutter Development Build
Install Grasscutter development branch. This build sometimes has bugs, and is frequently updated. Use at your own risk.
+
+
+ Download Grasscutter Resources + +
+ + Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally. + +
diff --git a/resources/js/index.js b/resources/js/index.js index b25a6e7..20e0502 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -248,10 +248,20 @@ async function handleFavoriteList() { async function openDownloads() { const downloads = document.querySelector('#downloadPanel') + const config = await getCfg() if (downloads.style.display === 'none') { downloads.style.removeProperty('display') } + + // Disable the resource download button if a serverFolder path is not set + if (!config.serverFolder) { + document.querySelector('#resourceInstall').disabled = true + document.querySelector('#resourceInstall').classList.add('disabled') + } else { + document.querySelector('#resourceInstall').disabled = false + document.querySelector('#resourceInstall').classList.remove('disabled') + } } async function closeDownloads() { diff --git a/resources/style/index.css b/resources/style/index.css index d466177..d1e2ea6 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -216,6 +216,10 @@ a { margin: 10px 0px; } +.downloadLabel { + margin: 14px 0px; +} + .downloadSubtitle, .settingSubtitle { color: rgb(165, 165, 165); From b4ac33ebaaf2afd9eeae5adb3e937aa81558e263 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:15:04 -0700 Subject: [PATCH 165/248] organization --- resources/index.html | 6 ++++++ resources/js/onLoad.js | 22 ++++++++++++++++------ resources/style/index.css | 8 ++++---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/resources/index.html b/resources/index.html index 6b86265..f3edc5d 100644 --- a/resources/index.html +++ b/resources/index.html @@ -123,6 +123,9 @@
+
+ GrassClipper +
Installer @@ -132,6 +135,9 @@ Installs proxy and other tools. Required for Grasscutter servers.
+
+ Grasscutter +
Download Grasscutter Stable Build diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index a1e8773..bc96832 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -38,6 +38,7 @@ window.addEventListener("click", function(e) { const favList = document.querySelector('#ipList') const settingsPanel = document.querySelector('#settingsPanel') + const downloadPanel = document.querySelector('#downloadPanel') // This will close the favorites list no matter what is clicked if (favList.style.display !== 'none') { @@ -46,23 +47,32 @@ } // This will close the settings panel no matter what is clicked - let settingCheckElm = e.target + let checkElm = e.target - while(settingCheckElm.tagName !== 'BODY') { - if (settingCheckElm.id === 'settingsPanel' - || settingCheckElm.id === 'settingsBtn') { + while(checkElm.tagName !== 'BODY') { + if (checkElm.id === 'settingsPanel' + || checkElm.id === 'settingsBtn') { return } - settingCheckElm = settingCheckElm.parentElement + if (checkElm.id === 'downloadPanel' || + checkElm.id === 'downloadBtn') { + return + } + + checkElm = checkElm.parentElement } // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel - if (settingCheckElm.tagName === 'BODY') { + if (checkElm.tagName === 'BODY') { // This will close the settings panel only when something outside of it is clicked if (settingsPanel.style.display !== 'none') { settingsPanel.style.display = 'none' } + + if (downloadPanel.style.display !== 'none') { + downloadPanel.style.display = 'none' + } } }); diff --git a/resources/style/index.css b/resources/style/index.css index d1e2ea6..6bb5548 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -208,6 +208,10 @@ a { margin-bottom: 10px; } +.downloadTitle { + margin: 6px; +} + .downloadLabel, .settingLabel { display:inline-block; @@ -216,10 +220,6 @@ a { margin: 10px 0px; } -.downloadLabel { - margin: 14px 0px; -} - .downloadSubtitle, .settingSubtitle { color: rgb(165, 165, 165); From 85eba69a63eb4a969c218aefc79790513da7e3d4 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:17:23 -0700 Subject: [PATCH 166/248] disallow unset paths --- resources/js/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resources/js/index.js b/resources/js/index.js index 20e0502..acbd062 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -412,6 +412,8 @@ async function setGameExe() { ] }) + if (!gameexe[0]) return; + // Set the folder in our configuration const config = await getCfg() @@ -433,6 +435,8 @@ async function setGrasscutterFolder() { ] }) + if (!folder[0]) return; + // Set the folder in our configuration const config = await getCfg() From d6961c9335e52cf7c7e545fc5ff093eba9c93862 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:32:51 -0700 Subject: [PATCH 167/248] show when script is beginning to run --- resources/js/gcdownloader.js | 40 ++++++++++++++++++++++++++++++++++++ resources/style/index.css | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index f101690..a8523f0 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -2,6 +2,37 @@ async function clearGCInstallation() { Neutralino.os.execCommand(`del /s /q "./gc"`) } +async function setDownloadButtonsToLoading() { + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') + + stableBtn.innerText = localeObj.gcScriptRunning || 'Running...' + + devBtn.innerText = localeObj.gcScriptRunning || 'Running...' + + // Set btns to disabled + stableBtn.disabled = true + stableBtn.classList.add('disabled') + + devBtn.disabled = true + devBtn.classList.add('disabled') +} + +async function resetDownloadButtons() { + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') + + stableBtn.innerText = localeObj.stableInstall || 'Download' + devBtn.innerText = localeObj.devInstall || 'Download' + + // Set btns to enabled + stableBtn.disabled = false + stableBtn.classList.remove('disabled') + + devBtn.disabled = false + devBtn.classList.remove('disabled') +} + async function downloadGC(branch) { const config = await getCfg() @@ -14,8 +45,13 @@ async function downloadGC(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() + // Keystore for branch (since they can differ) const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12` @@ -56,6 +92,10 @@ async function downloadGC(branch) { // Run installer createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + // Fix buttons + resetDownloadButtons() + // Display folder after saving config displayServerFolder() + displayServerLaunchSection() } \ No newline at end of file diff --git a/resources/style/index.css b/resources/style/index.css index 6bb5548..f738e24 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -11,6 +11,10 @@ a { color: #fff; } +img { + height: 20px; +} + .darken { filter: brightness(0.6); } From 963866528d686d786621cd096a009fb6c2fb0e50 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:40:11 -0700 Subject: [PATCH 168/248] translation setup for downloads --- languages/en.json | 16 ++++++++++++++++ resources/index.html | 2 +- resources/js/translation.js | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/languages/en.json b/languages/en.json index a7ecafe..1fecb4d 100644 --- a/languages/en.json +++ b/languages/en.json @@ -63,5 +63,21 @@ "alertAuthNoRegister": "Authentication is disabled, no need to register!", "alertRegisterSuccess": "Registration successful!", + "downloadTitle": "Downloads", + "grassclipperTitle": "GrassClipper", + "grasscutterTitle": "Grasscutter", + "installerTitle": "Installer", + "installerSubtitle": "Installs proxy and other tools. Required for Grasscutter servers.", + "downloadStable": "Download Grasscutter Stable Build", + "stableSubtitle": "Install Grasscutter stable branch. This build usually has less bugs, but also less features.", + "downloadDev": "Download Grasscutter Development Build", + "downloadSubtitle": "Install Grasscutter development branch. This build sometimes has bugs, and is frequently updated. Use at your own risk.", + "downloadResources": "Download Grasscutter Resources", + "devSubtitle": "Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally.", + + "gcScriptRunning": "Running...", + "stableInstall": "Download", + "devInstall": "Download", + "updateNotifText": "A new update is available! Newest version: " } diff --git a/resources/index.html b/resources/index.html index f3edc5d..bb71778 100644 --- a/resources/index.html +++ b/resources/index.html @@ -135,7 +135,7 @@ Installs proxy and other tools. Required for Grasscutter servers.
-
+
Grasscutter
diff --git a/resources/js/translation.js b/resources/js/translation.js index 986b03c..2f1d17d 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -90,6 +90,21 @@ async function doTranslation() { set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') set('noLoginBtn', 'launchWithoutAuth') + // Downloads section + set('downloadTitle', 'downloadTitle') + set('grassclipperTitle', 'grassclipperTitle') + set('grasscutterTitle', 'grasscutterTitle') + set('installerTitle', 'installerTitle') + set('installerSubtitle', 'installerSubtitle') + set('downloadStable', 'downloadStable') + set('stableSubtitle', 'stableSubtitle') + set('downloadDev', 'downloadDev') + set('downloadSubtitle', 'downloadSubtitle') + set('downloadResources', 'downloadResources') + set('devSubtitle', 'devSubtitle') + set('stableInstall', 'stableInstall') + set('devInstall', 'devInstall') + // update notification set('updateNotifText', 'updateNotifText') } \ No newline at end of file From e60fa35e8d1c7146be425be623bed083703d2995 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:54:40 -0700 Subject: [PATCH 169/248] bugfix --- resources/js/index.js | 2 +- resources/js/translation.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index acbd062..a322e5a 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -412,7 +412,7 @@ async function setGameExe() { ] }) - if (!gameexe[0]) return; + if (!gameExe[0]) return; // Set the folder in our configuration const config = await getCfg() diff --git a/resources/js/translation.js b/resources/js/translation.js index 2f1d17d..dd80b83 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -99,7 +99,7 @@ async function doTranslation() { set('downloadStable', 'downloadStable') set('stableSubtitle', 'stableSubtitle') set('downloadDev', 'downloadDev') - set('downloadSubtitle', 'downloadSubtitle') + set('devSubtitle', 'downloadSubtitle') set('downloadResources', 'downloadResources') set('devSubtitle', 'devSubtitle') set('stableInstall', 'stableInstall') From 1a7a0b1dc4038d704d78d22f842448848ef4cf9b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:59:20 -0700 Subject: [PATCH 170/248] enable server button --- resources/js/gcdownloader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index a8523f0..e45a0f4 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -97,5 +97,6 @@ async function downloadGC(branch) { // Display folder after saving config displayServerFolder() + enableServerButton() displayServerLaunchSection() } \ No newline at end of file From 93148149efdc457373b756ef72050e943277511a Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 02:47:55 -0700 Subject: [PATCH 171/248] fix killswitch --- scripts/private_server_launch.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 0cc7b12..5fcbf1e 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -27,7 +27,7 @@ if "%ENABLE_KILLSWITCH%" EQU "true" ( :: Restart in elevated if need be >nul 2>&1 reg query "HKU\S-1-5-19" || ( set params = %*:"="""% - cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%/../"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" && exit /b ) + cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" && exit /b ) ) ) @@ -41,7 +41,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 :: 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% From 614a728d125b9d3d5d56dcfe8ce7aa8a1268a01b Mon Sep 17 00:00:00 2001 From: Nautilus Date: Mon, 2 May 2022 23:57:08 +0700 Subject: [PATCH 172/248] update Indonesian translation --- languages/id.json | 104 +++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/languages/id.json b/languages/id.json index 63608f9..c56e617 100644 --- a/languages/id.json +++ b/languages/id.json @@ -1,39 +1,67 @@ { - "fullLangName": "Bahasa Indonesia", - "appName": "GrassClipper", - - "playOfficial": "Mainkan Official", - "playPrivate": "Mainkan Grasscutter", - "launchLocalServer": "Luncurkan Local Server", - - "gameExeSet": "Atur folder game", - "grasscutterFileSet": "Atur file \"Grasscutter\" .jar", - "folderNotSet": "Belum diatur", - - "ipPlaceholder": "Alamat IP", - "noFavorites": "Tidak ada favorite yang diatur", - - "settingsTitle": "Pengaturan", - "scriptsSectionTitle": "Scripts", - "killswitchOption": "Matikan Switch", - "killswitchSubtitle": "Untuk kamu yang paranoid terhadap ban. Matikan proses game *dan internetmu* apabila sesuatu terjadi pada proxy nya.", - "proxyOption": "Proxy", - "proxySubtitle": "Install proxy server melalui install script", - "updateOption": "Update", - "updateSubtitle": "Update otomatis dinonaktifkan untuk sementara. Cek GitHub untuk rilis terbaru.", - "languageOption": "Bahasa", - "languageSubtitle": "Pilih bahasamu!", - "enableServerLauncherOption": "Nyalakan Server Launcher", - "enableServerLauncherSubtitle": "Nyalakan tile server launcher untuk meluncurkan instance Grasscutter secara lokal.", - - "introSen1": "Sepertinya ini pertama kalinya kamu menggunakan GrassClipper!", - "introSen2": "Pertama-tama, selamat datang, senang bertemu denganmu! :)", - "introSen3": "Apa kamu ingin menjalankan installer proxy?", - "introSen4": "(diperlukan untuk terhubung dengan private servers)", - - "proxyInstallBtn": "Install", - "proxyInstallDeny": "Tidak terima kasih", - - "gameFolderDialog": "Pilih folder game", - "grasscutterFileDialog": "Pilih file jar server Grasscutter" - } \ No newline at end of file + "fullLangName": "Bahasa Indonesia", + "appName": "GrassClipper", + + "playOfficial": "Mainkan Official", + "playPrivate": "Mainkan di Grasscutter", + "launchLocalServer": "Luncurkan Server Lokal", + + "gameExeSet": "Atur eksekusi game", + "grasscutterFileSet": "Atur file \"Grasscutter\" .jar", + "folderNotSet": "Belum diatur", + + "ipPlaceholder": "Alamat IP", + "portPlaceholder": "Port", + "noFavorites": "Tidak ada favorit yang diatur", + + "settingsTitle": "Pengaturan", + "scriptsSectionTitle": "Skrip", + "killswitchOption": "Saklar Mati", + "killswitchSubtitle": "Hanya untuk yang paranoid terhadap ban. Mematikan proses game *dan internetmu* jika terjadi sesuatu pada proxy nya.", + "proxyOption": "Proxy", + "proxySubtitle": "Pasang server proxy melalui skrip pemasangan", + "updateOption": "Pembaruan", + "updateSubtitle": "Pembaruan otomatis dinonaktifkan untuk sementara. Cek GitHub untuk rilisan terbaru.", + "languageOption": "Bahasa", + "languageSubtitle": "Pilih bahasamu!", + "enableServerLauncherOption": "Aktifkan Peluncur Server", + "enableServerLauncherSubtitle": "Aktifkan ke tile peluncur server untuk meluncurkan instance Grasscutter secara lokal.", + "httpsOption": "Gunakan HTTPS", + "httpsSubtitle": "Pilih antara menggunakan HTTPS atau HTTP.", + + "introSen1": "Sepertinya ini pertama kalinya kamu membuka GrassClipper!", + "introSen2": "Pertama-tama, selamat datang, senang bertemu denganmu disini! :)", + "introSen3": "Apakah kamu ingin menjalankan pemasangan proxy?", + "introSen4": "(diperlukan untuk menghubungkan ke server)", + + "updateBtn": "Perbarui", + "proxyInstallBtn": "Pasang", + "proxyInstallDeny": "Tidak, terima kasih", + + "gameFolderDialog": "Pilih folder game", + "grasscutterFileDialog": "Pilih file jar server Grasscutter", + + "loggingInTo": "Masuk ke: ", + "registeringFor": "Mendaftar untuk: ", + "authUsername": "Nama Pengguna: ", + "authPassword": "Kata Sandi: ", + "authConfirmPassword": "Konfirmasi Kata Sandi: ", + "authLoginBtn": "Masuk", + "authRegisterBtn": "Daftar", + "authLoginTitle": "Masuk", + "authRegisterTitle": "Daftar", + "launchWithoutAuth": "Luncurkan Tanpa Autentikasi", + + "alertInvalid": "Nama pengguna atau kata sandi tidak valid", + "alertNoPass": "Tidak ada kata sandi yang diatur, silahkan isi kata sandi", + "alertUnknown": "Kesalahan yang tidak diketahui, hubungi pemilik server", + "alertAuthNoLogin": "Autentikasi dinonaktifkan, tidak perlu masuk!", + "alertLoginSuccess": "Berhasil masuk! Token disalin ke papan klip. Tempelkan token ini ke dalam bidang nama pengguna di game untuk masuk.", + + "alertUserTaken": "Nama pengguna sudah terpakai", + "alertPassMismatch": "Kata sandi dan konfirmasi kata sandi tidak cocok", + "alertAuthNoRegister": "Autentikasi dinonaktifkan, tidak perlu mendaftar!", + "alertRegisterSuccess": "Pendaftaran berhasil!", + + "updateNotifText": "Pembaruan baru tersedia! Versi terbaru: " +} From 574b2f4f09a3e903160e2fdc1bd2d45ade23c4ed Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 19:50:49 -0700 Subject: [PATCH 173/248] change auth endpoints --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- resources/js/index.js | 5 ++--- resources/js/login.js | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/manifest.json b/manifest.json index 3df9a34..95e72a6 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.5", + "version": "0.8.6", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 7abf636..f3a3b87 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.5", + "version": "0.8.6", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 196bce7..8a336fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.8.5", + "version": "0.8.6", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", diff --git a/resources/js/index.js b/resources/js/index.js index 0a4e2ce..98b22d8 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -298,9 +298,9 @@ async function openLogin() { // Check if we even need to authenticate try { - const { data } = await axios.get(url + '/grasscutter/auth_status') + const { data } = await axios.get(url + '/authentication/type') - if (data?.message !== 'AUTH_ENABLED') { + if (!data.includes('GCAuthAuthenticationHandler')) { launchPrivate() return } @@ -309,7 +309,6 @@ async function openLogin() { return } - loginIpDisplay.innerText = ip registerIpDisplay.innerText = ip diff --git a/resources/js/login.js b/resources/js/login.js index 5fd7f8e..60188d7 100644 --- a/resources/js/login.js +++ b/resources/js/login.js @@ -62,7 +62,7 @@ async function login() { password, } - const { data } = await axios.post(url + '/grasscutter/login', reqBody) + const { data } = await axios.post(url + '/authentication/login', reqBody) switch(data.message) { case 'INVALID_ACCOUNT': @@ -117,7 +117,7 @@ async function register() { password_confirmation } - const { data } = await axios.post(url + '/grasscutter/register', reqBody) + const { data } = await axios.post(url + '/authentication/register', reqBody) switch(data.message) { case 'USERNAME_TAKEN': From 1f3632753f89fca22b1f0ac2cca6004204f6cfc5 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 21:34:53 -0700 Subject: [PATCH 174/248] fix traditional chinese translation file --- languages/zh-tw.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages/zh-tw.json b/languages/zh-tw.json index d551fb9..0d23c08 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -38,7 +38,7 @@ "proxyInstallDeny": "不用了,謝謝。", "gameFolderDialog": "選擇Genshin Impact game資料夾", - "grasscutterFileDialog": "選擇Grasscutter.jar檔案" + "grasscutterFileDialog": "選擇Grasscutter.jar檔案", "loggingInTo": "登錄至:", "registeringFor": "註冊至:", @@ -60,7 +60,7 @@ "alertUserTaken": "用戶名已被占用", "alertPassMismatch": "兩組密碼不一致", "alertAuthNoRegister": "未啟用認證,無需註冊!", - "alertRegisterSuccess": "註冊成功!" + "alertRegisterSuccess": "註冊成功!", "updateNotifText": "有新的GrassClipper更新可用! 最新版本: " } From 08cd04b134300cd5c763802cdc3f0deb2d1c8a2b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 21:35:38 -0700 Subject: [PATCH 175/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 95e72a6..2fc35a4 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.6", + "version": "0.8.7", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index f3a3b87..be4549a 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.6", + "version": "0.8.7", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 8a336fe..e5efc86 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.8.6", + "version": "0.8.7", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From e152cc3e3c806e460570905839034c88b1936c43 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 21:40:05 -0700 Subject: [PATCH 176/248] Quotes in user profile usage in scripts --- scripts/install.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/install.cmd b/scripts/install.cmd index 99e27c3..f8e14f1 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -35,12 +35,12 @@ taskkill /f /im mitmdump.exe echo Adding ceritifcate... :: Ensure we are elevated for certs ->nul 2>&1 certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer || ( +>nul 2>&1 certutil -addstore root "%USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer" || ( echo ============================================================================================================ echo !! Certificate install failed !! echo. echo Please manually run this command as Administrator: - echo certutil -addstore root %USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer + echo certutil -addstore root "%USERPROFILE%\.mitmproxy\mitmproxy-ca-cert.cer" echo ============================================================================================================ ) From 7c2f36109d7aed1bb37905b056af53c1a5b03f82 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:09:10 -0700 Subject: [PATCH 177/248] download script for gc --- .gitignore | 1 + resources/index.html | 1 + resources/js/gcdownloader.js | 24 ++++++++++++++++++++++++ resources/js/helpers.js | 1 + scripts/gcdownload.cmd | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 resources/js/gcdownloader.js create mode 100644 scripts/gcdownload.cmd diff --git a/.gitignore b/.gitignore index 2ccb550..66207a5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ bin/ dist/ ext/ temp/ +gc*/ resources/js/neutralino.js resources/bg/official diff --git a/resources/index.html b/resources/index.html index f59f5ea..81a7e7a 100644 --- a/resources/index.html +++ b/resources/index.html @@ -8,6 +8,7 @@ + diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js new file mode 100644 index 0000000..c1b5e1b --- /dev/null +++ b/resources/js/gcdownloader.js @@ -0,0 +1,24 @@ +async function clearGCInstallation() { + Neutralino.os.execCommand(`del /s /q "./gc"`) +} + +async function downloadGC(branch) { + const config = await getCfg() + + // If we are pulling from a new branch, delete the old installation + if (config.grasscutterBranch !== branch) await clearGCInstallation() + + // 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` + + // Run installer + createCmdWindow(`.\\scripts\\gcdownload.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + + // Set current installation in config + config.grasscutterBranch = branch + + Neutralino.storage.setData('config', JSON.stringify(config)) +} \ No newline at end of file diff --git a/resources/js/helpers.js b/resources/js/helpers.js index c0b31c0..ad313fa 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -12,6 +12,7 @@ serverLaunchPanel: false, language: 'en', useHttps: true, + grasscutterBranch: '', } const cfgStr = await Neutralino.storage.getData('config').catch(e => { // The data isn't set, so this is our first time opening diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd new file mode 100644 index 0000000..9105de2 --- /dev/null +++ b/scripts/gcdownload.cmd @@ -0,0 +1,34 @@ +@echo off + +set KEYSTORE_URL=%1 +set ARTIFACT_URL=%2 +set BRANCH=%3 +set FOLDER_NAME=".\gc-%BRANCH%" + +if not exist %FOLDER_NAME% mkdir %FOLDER_NAME% +if not exist ".\temp" mkdir ".\temp" + +echo Downloading Grasscutter prebuilt jar... + +:: Download the jar +powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" + +echo Extracting... + +powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath %FOLDER_NAME% -Force + +:: Download the keystore.p12 file + +echo Downloading keystore.p12... + +powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" + +:: Remove temp stuff +del /s /q "./temp" + +echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% + +pause + +exit /b + From 158e10352b1094322b54d11c8c26d3445fe52b42 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:34:10 -0700 Subject: [PATCH 178/248] fix gc downloader script --- resources/js/gcdownloader.js | 3 +++ scripts/gcdownload.cmd | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index c1b5e1b..0786abe 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -20,5 +20,8 @@ async function downloadGC(branch) { // Set current installation in config config.grasscutterBranch = branch + // Set gc path for people with launcher enabled + config.serverFolder = `${NL_CWD}\\gc-${branch}\\` + Neutralino.storage.setData('config', JSON.stringify(config)) } \ No newline at end of file diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd index 9105de2..3c6c05d 100644 --- a/scripts/gcdownload.cmd +++ b/scripts/gcdownload.cmd @@ -4,8 +4,9 @@ set KEYSTORE_URL=%1 set ARTIFACT_URL=%2 set BRANCH=%3 set FOLDER_NAME=".\gc-%BRANCH%" +set FOLDER_NAME=%FOLDER_NAME:"=% -if not exist %FOLDER_NAME% mkdir %FOLDER_NAME% +if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" if not exist ".\temp" mkdir ".\temp" echo Downloading Grasscutter prebuilt jar... @@ -15,12 +16,20 @@ powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" echo Extracting... -powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath %FOLDER_NAME% -Force +:: Delete old file if there is one there +if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar" -:: Download the keystore.p12 file +powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force + +:: Find the jar file name and rename it, just in case +for %%i in (%FOLDER_NAME%/*) do ( + :: If the extension is jar, rename the file + if %%~xi equ .jar rename "%FOLDER_NAME%\%%i" grasscutter.jar +) echo Downloading keystore.p12... +:: Download the keystore.p12 file powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" :: Remove temp stuff From bdea511d543ce310f665c152997cd80118751b78 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:39:47 -0700 Subject: [PATCH 179/248] extra fixes --- resources/js/gcdownloader.js | 5 ++++- scripts/gcdownload.cmd | 4 +++- scripts/install.cmd | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 0786abe..454c7b6 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -21,7 +21,10 @@ async function downloadGC(branch) { config.grasscutterBranch = branch // Set gc path for people with launcher enabled - config.serverFolder = `${NL_CWD}\\gc-${branch}\\` + config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` Neutralino.storage.setData('config', JSON.stringify(config)) + + // Display folder after saving config + displayServerFolder() } \ No newline at end of file diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd index 3c6c05d..576d117 100644 --- a/scripts/gcdownload.cmd +++ b/scripts/gcdownload.cmd @@ -6,6 +6,8 @@ set BRANCH=%3 set FOLDER_NAME=".\gc-%BRANCH%" set FOLDER_NAME=%FOLDER_NAME:"=% +title GC Download Script + if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" if not exist ".\temp" mkdir ".\temp" @@ -39,5 +41,5 @@ echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% pause -exit /b +taskkill /f /fi "WINDOWTITLE eq GC Download Script" diff --git a/scripts/install.cmd b/scripts/install.cmd index f8e14f1..63fbd41 100644 --- a/scripts/install.cmd +++ b/scripts/install.cmd @@ -3,6 +3,8 @@ set ORIGIN=%1 set ORIGIN=%ORIGIN:"=% +title Grassclipper Installer + echo Downloading proxy server... :: Make sure we are in the right directory @@ -48,4 +50,4 @@ echo Done! You can now open GrassClipper.exe! pause -exit /b \ No newline at end of file +taskkill /f /fi "WINDOWTITLE eq Grassclipper Installer" \ No newline at end of file From 6c0a079a41ba7399a6eabfa44b60b684b27dc4f8 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 19:43:57 -0700 Subject: [PATCH 180/248] fix server launcher script --- scripts/local_server_launch.cmd | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/local_server_launch.cmd b/scripts/local_server_launch.cmd index e052d1a..75dde1f 100644 --- a/scripts/local_server_launch.cmd +++ b/scripts/local_server_launch.cmd @@ -3,15 +3,23 @@ set GRASSCUTTER_JAR=%1 set GRASSCUTTER_JAR=%GRASSCUTTER_JAR:"=% +title Grasscutter + :: Get folder the jar is in set "X=%GRASSCUTTER_JAR%" :l -if "%X:~-1%"=="\" goto al -set "X=%X:~0,-1%" -goto l + set IS_SLASH=false + + if "%X:~-1%"=="\" set IS_SLASH=true + if "%X:~-1%"=="/" set IS_SLASH=true + + if %IS_SLASH% equ true goto al + + set "X=%X:~0,-1%" + goto l :al -set "X=%X:~0,-1%" -set "GRASSCUTTER_ROOT=%X%" + set "X=%X:~0,-1%" + set "GRASSCUTTER_ROOT=%X%" echo Starting local Grasscutter server... From ba91d9058f9909d60435a75f37132a583b7d8366 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 21:05:24 -0700 Subject: [PATCH 181/248] resource downloader --- resources/js/gcdownloader.js | 2 +- scripts/gcdownload.cmd | 45 ------------------------------------ 2 files changed, 1 insertion(+), 46 deletions(-) delete mode 100644 scripts/gcdownload.cmd diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 454c7b6..d20399e 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -15,7 +15,7 @@ async function downloadGC(branch) { const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip` // Run installer - createCmdWindow(`.\\scripts\\gcdownload.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) // Set current installation in config config.grasscutterBranch = branch diff --git a/scripts/gcdownload.cmd b/scripts/gcdownload.cmd deleted file mode 100644 index 576d117..0000000 --- a/scripts/gcdownload.cmd +++ /dev/null @@ -1,45 +0,0 @@ -@echo off - -set KEYSTORE_URL=%1 -set ARTIFACT_URL=%2 -set BRANCH=%3 -set FOLDER_NAME=".\gc-%BRANCH%" -set FOLDER_NAME=%FOLDER_NAME:"=% - -title GC Download Script - -if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" -if not exist ".\temp" mkdir ".\temp" - -echo Downloading Grasscutter prebuilt jar... - -:: Download the jar -powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" - -echo Extracting... - -:: Delete old file if there is one there -if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar" - -powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force - -:: Find the jar file name and rename it, just in case -for %%i in (%FOLDER_NAME%/*) do ( - :: If the extension is jar, rename the file - if %%~xi equ .jar rename "%FOLDER_NAME%\%%i" grasscutter.jar -) - -echo Downloading keystore.p12... - -:: Download the keystore.p12 file -powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" - -:: Remove temp stuff -del /s /q "./temp" - -echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% - -pause - -taskkill /f /fi "WINDOWTITLE eq GC Download Script" - From 8f86d5c2834432eba7e18e3cb60d59f1409252f4 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 21:07:09 -0700 Subject: [PATCH 182/248] resource downloader (fr this time) --- scripts/gc_download.cmd | 55 ++++++++++++++++++++++++++++++++++ scripts/resources_download.cmd | 29 ++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 scripts/gc_download.cmd create mode 100644 scripts/resources_download.cmd diff --git a/scripts/gc_download.cmd b/scripts/gc_download.cmd new file mode 100644 index 0000000..1b24f2b --- /dev/null +++ b/scripts/gc_download.cmd @@ -0,0 +1,55 @@ +@echo off + +set KEYSTORE_URL=%1 +set ARTIFACT_URL=%2 +set BRANCH=%3 +set FOLDER_NAME=".\gc-%BRANCH%" +set FOLDER_NAME=%FOLDER_NAME:"=% + +title GC Download Script + +if not exist "%FOLDER_NAME%" mkdir "%FOLDER_NAME%" +if not exist ".\temp" mkdir ".\temp" + +echo Downloading Grasscutter prebuilt jar... + +:: Download the jar +powershell Invoke-WebRequest -Uri %KEYSTORE_URL% -OutFile "./temp/gcjar.zip" + +echo Extracting... + +:: Delete old file if there is one there +if exist "%FOLDER_NAME%\grasscutter.jar" del "%FOLDER_NAME%\grasscutter.jar" + +powershell Expand-Archive -Path "./temp/gcjar.zip" -DestinationPath "%FOLDER_NAME%" -Force + +:: Find the jar file name and rename it, just in case +for %%i in (%FOLDER_NAME%/*) do ( + :: If the extension is jar, rename the file + if %%~xi equ .jar rename "%FOLDER_NAME%\%%i" grasscutter.jar +) + +echo Downloading keystore.p12... + +:: Download the keystore.p12 file +powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" + +:: Allow resource downloading to be optional, since it takes a while +set REPLY=y +set /p "REPLY=Download server resources? (This can take a while) [y|n]:" +if /i not "%reply%" == "y" goto :finish + +call .\scripts\resources_download.cmd %FOLDER_NAME% + +goto :finish + +:finish + :: Remove temp stuff + del /s /q "./temp" + + echo Done, latest Grasscutter %BRANCH% now downloaded in %FOLDER_NAME% + + pause + + taskkill /f /fi "WINDOWTITLE eq GC Download Script" + diff --git a/scripts/resources_download.cmd b/scripts/resources_download.cmd new file mode 100644 index 0000000..f1e1574 --- /dev/null +++ b/scripts/resources_download.cmd @@ -0,0 +1,29 @@ +@echo off + +set FOLDER_NAME=%1 +set FOLDER_NAME=%FOLDER_NAME:"=% + +if not exist ".\temp" mkdir ".\temp" +if not exist ".\resources" mkdir ".\resources" + +echo Downloading resources, this can take a while... + +:: 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" + +echo Extracting... + +:: Extract resources to the folder +powershell Expand-Archive -Path "./temp/resources.zip" -DestinationPath "%FOLDER_NAME%" -Force + +:: Delete old resources folder if there is one there +del /s /q "%FOLDER_NAME%\resources">nul + +echo Moving resources to folder... + +robocopy "%FOLDER_NAME%\Grasscutter_Resources-main\Resources" "%FOLDER_NAME%\resources" /E /MOVE>nul + +:: Delete straggling files +del /s /q "%FOLDER_NAME%\Grasscutter_Resources-main" + +echo Done, resources should be properly extracted \ No newline at end of file From f2f4179813c60dcdc74c2f75fd9eb0d47c960156 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:19:32 -0700 Subject: [PATCH 183/248] download data and key files --- resources/js/gcdownloader.js | 47 +++++++++++++++++++++++++++++------- resources/js/helpers.js | 2 +- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index d20399e..29eb8a2 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -8,15 +8,6 @@ async function downloadGC(branch) { // If we are pulling from a new branch, delete the old installation if (config.grasscutterBranch !== branch) await clearGCInstallation() - // 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` - - // Run installer - createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) - // Set current installation in config config.grasscutterBranch = branch @@ -24,6 +15,44 @@ async function downloadGC(branch) { config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` Neutralino.storage.setData('config', JSON.stringify(config)) + + // 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 + const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) + const dataList = dataFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + + // For key files + const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) + const keyList = keyFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + + const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') + + // Download data files + for (const o of dataList) { + const folder = 'data' + Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } + + // Download each file + for (const o of keyList) { + const folder = 'keys' + Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } + + return; + + // Run installer + createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + // Display folder after saving config displayServerFolder() diff --git a/resources/js/helpers.js b/resources/js/helpers.js index ad313fa..4e3a38b 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -98,7 +98,7 @@ async function openGameFolder() { async function openGrasscutterFolder() { const config = await getCfg() - const folder = config.serverFolder.match(/.*\\/g, '')[0] + const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] openInExplorer(folder) } From daef0d1724f5839a181f760f829a04dac1261c4c Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:23:33 -0700 Subject: [PATCH 184/248] ensure folders exist --- resources/js/gcdownloader.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 29eb8a2..960a757 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -36,16 +36,21 @@ async function downloadGC(branch) { const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') + // Ensure data and key folders exist + + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) + // Download data files for (const o of dataList) { const folder = 'data' - Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) } - // Download each file + // Download key files for (const o of keyList) { const folder = 'keys' - Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) } return; From a47389e38b5129adb4d1b17a63aaf0a21250f815 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:24:45 -0700 Subject: [PATCH 185/248] re-enable full installer --- resources/js/gcdownloader.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 960a757..257a5f5 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -52,8 +52,6 @@ async function downloadGC(branch) { const folder = 'keys' await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) } - - return; // Run installer createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) From 8b76778996ffc78b4505b19a21633efb915c71fd Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:56:15 -0700 Subject: [PATCH 186/248] begin downloads panel --- resources/index.html | 27 +++++++++++++++++++++++++++ resources/js/gcdownloader.js | 1 - resources/js/index.js | 14 ++++++++++++++ resources/style/index.css | 13 +++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/resources/index.html b/resources/index.html index 81a7e7a..ed5353e 100644 --- a/resources/index.html +++ b/resources/index.html @@ -115,6 +115,28 @@
+ + + +
diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index 257a5f5..f101690 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -56,7 +56,6 @@ async function downloadGC(branch) { // Run installer createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) - // Display folder after saving config displayServerFolder() } \ No newline at end of file diff --git a/resources/js/index.js b/resources/js/index.js index 98b22d8..2656464 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -246,6 +246,20 @@ async function handleFavoriteList() { } } +async function openDownloads() { + const downloads = document.querySelector('#downloadPanel') + + if (downloads.style.display === 'none') { + downloads.style.removeProperty('display') + } +} + +async function closeDownloads() { + const downloads = document.querySelector('#downloadPanel') + + downloads.style.display = 'none' +} + async function openSettings() { const settings = document.querySelector('#settingsPanel') const config = await getCfg() diff --git a/resources/style/index.css b/resources/style/index.css index ff31870..0b16237 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -157,6 +157,7 @@ a { #firstTimeNotice, #loginPanel, +#downloadPanel, #settingsPanel { display: block; position: absolute; @@ -172,6 +173,7 @@ a { font-family: system-ui; } +#downloadPanel, #settingsPanel { width: 35%; height: 80%; @@ -184,6 +186,7 @@ a { margin-bottom: 10px; } +#downloadPanelInner, #settingsPanelInner { display: flex; flex-direction: column; @@ -192,16 +195,19 @@ a { padding: 10px 10%; } +.downloadRow, .settingsRow { width: 100%; } +.downloadTitle, .settingTitle { font-size: 1.2em; font-weight: bold; margin-bottom: 10px; } +.downloadLabel, .settingLabel { display:inline-block; font-size: 1em; @@ -209,12 +215,14 @@ a { margin: 10px 0px; } +.downloadSubtitle, .settingSubtitle { color: rgb(165, 165, 165); font-size: 0.8em; font-weight: normal; } +.downloadSection, .settingSection { display: flex; flex-direction: row; @@ -222,10 +230,12 @@ a { justify-content: space-between; } +.downloadSection .smolBtn, .settingSection .smolBtn { height: 30px; } +#downloadTitleBar #settingsTitleBar { display: flex; flex-direction: row; @@ -233,15 +243,18 @@ a { justify-content: space-between; } +#downloadClose, #settingsClose { display: inline-block; transition: filter 0.1s ease-in-out; } +#downloadClose img, #settingsClose img { height: 20px; } +#downloadClose:hover, #settingsClose:hover { filter: invert(85%) sepia(31%) saturate(560%) hue-rotate(329deg) brightness(100%) contrast(92%); cursor: pointer; From f8185e5b633175e021079b53b65911173ec0456d Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 22:59:11 -0700 Subject: [PATCH 187/248] small styling fixes --- resources/index.html | 10 ++++------ resources/style/index.css | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/resources/index.html b/resources/index.html index ed5353e..2d63c3a 100644 --- a/resources/index.html +++ b/resources/index.html @@ -117,12 +117,10 @@ From ec27fd0530ced6b61a5df2378d2d94c255b021e0 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:09:20 -0700 Subject: [PATCH 189/248] download page open/close --- resources/icons/download.svg | 11 +++++++++++ resources/index.html | 13 +++++++++++-- resources/js/index.js | 10 ++++++++++ resources/style/index.css | 4 ++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 resources/icons/download.svg diff --git a/resources/icons/download.svg b/resources/icons/download.svg new file mode 100644 index 0000000..8baf9ed --- /dev/null +++ b/resources/icons/download.svg @@ -0,0 +1,11 @@ + +Created with Fabric.js 1.7.22 + + + + + + + + + \ No newline at end of file diff --git a/resources/index.html b/resources/index.html index 41b951e..6b86265 100644 --- a/resources/index.html +++ b/resources/index.html @@ -134,7 +134,7 @@
- Download Stable Build + Download Grasscutter Stable Build
@@ -143,13 +143,22 @@
- Download Development Build + Download Grasscutter Development Build
Install Grasscutter development branch. This build sometimes has bugs, and is frequently updated. Use at your own risk.
+
+
+ Download Grasscutter Resources + +
+ + Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally. + +
diff --git a/resources/js/index.js b/resources/js/index.js index 2656464..db2b550 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -248,10 +248,20 @@ async function handleFavoriteList() { async function openDownloads() { const downloads = document.querySelector('#downloadPanel') + const config = await getCfg() if (downloads.style.display === 'none') { downloads.style.removeProperty('display') } + + // Disable the resource download button if a serverFolder path is not set + if (!config.serverFolder) { + document.querySelector('#resourceInstall').disabled = true + document.querySelector('#resourceInstall').classList.add('disabled') + } else { + document.querySelector('#resourceInstall').disabled = false + document.querySelector('#resourceInstall').classList.remove('disabled') + } } async function closeDownloads() { diff --git a/resources/style/index.css b/resources/style/index.css index d466177..d1e2ea6 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -216,6 +216,10 @@ a { margin: 10px 0px; } +.downloadLabel { + margin: 14px 0px; +} + .downloadSubtitle, .settingSubtitle { color: rgb(165, 165, 165); From bc363759900bafebcb51557c8cbc3b84f410d8d6 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:15:04 -0700 Subject: [PATCH 190/248] organization --- resources/index.html | 6 ++++++ resources/js/onLoad.js | 22 ++++++++++++++++------ resources/style/index.css | 8 ++++---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/resources/index.html b/resources/index.html index 6b86265..f3edc5d 100644 --- a/resources/index.html +++ b/resources/index.html @@ -123,6 +123,9 @@
+
+ GrassClipper +
Installer @@ -132,6 +135,9 @@ Installs proxy and other tools. Required for Grasscutter servers.
+
+ Grasscutter +
Download Grasscutter Stable Build diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index a1e8773..bc96832 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -38,6 +38,7 @@ window.addEventListener("click", function(e) { const favList = document.querySelector('#ipList') const settingsPanel = document.querySelector('#settingsPanel') + const downloadPanel = document.querySelector('#downloadPanel') // This will close the favorites list no matter what is clicked if (favList.style.display !== 'none') { @@ -46,23 +47,32 @@ } // This will close the settings panel no matter what is clicked - let settingCheckElm = e.target + let checkElm = e.target - while(settingCheckElm.tagName !== 'BODY') { - if (settingCheckElm.id === 'settingsPanel' - || settingCheckElm.id === 'settingsBtn') { + while(checkElm.tagName !== 'BODY') { + if (checkElm.id === 'settingsPanel' + || checkElm.id === 'settingsBtn') { return } - settingCheckElm = settingCheckElm.parentElement + if (checkElm.id === 'downloadPanel' || + checkElm.id === 'downloadBtn') { + return + } + + checkElm = checkElm.parentElement } // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel - if (settingCheckElm.tagName === 'BODY') { + if (checkElm.tagName === 'BODY') { // This will close the settings panel only when something outside of it is clicked if (settingsPanel.style.display !== 'none') { settingsPanel.style.display = 'none' } + + if (downloadPanel.style.display !== 'none') { + downloadPanel.style.display = 'none' + } } }); diff --git a/resources/style/index.css b/resources/style/index.css index d1e2ea6..6bb5548 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -208,6 +208,10 @@ a { margin-bottom: 10px; } +.downloadTitle { + margin: 6px; +} + .downloadLabel, .settingLabel { display:inline-block; @@ -216,10 +220,6 @@ a { margin: 10px 0px; } -.downloadLabel { - margin: 14px 0px; -} - .downloadSubtitle, .settingSubtitle { color: rgb(165, 165, 165); From 092424e3108bb74a216d76808d346fc82866feb4 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:17:23 -0700 Subject: [PATCH 191/248] disallow unset paths --- resources/js/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resources/js/index.js b/resources/js/index.js index db2b550..6e14f7d 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -411,6 +411,8 @@ async function setGameExe() { ] }) + if (!gameexe[0]) return; + // Set the folder in our configuration const config = await getCfg() @@ -432,6 +434,8 @@ async function setGrasscutterFolder() { ] }) + if (!folder[0]) return; + // Set the folder in our configuration const config = await getCfg() From 42290412bae95c08f33f9e8dfce3cfb83baacfe3 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:32:51 -0700 Subject: [PATCH 192/248] show when script is beginning to run --- resources/js/gcdownloader.js | 40 ++++++++++++++++++++++++++++++++++++ resources/style/index.css | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index f101690..a8523f0 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -2,6 +2,37 @@ async function clearGCInstallation() { Neutralino.os.execCommand(`del /s /q "./gc"`) } +async function setDownloadButtonsToLoading() { + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') + + stableBtn.innerText = localeObj.gcScriptRunning || 'Running...' + + devBtn.innerText = localeObj.gcScriptRunning || 'Running...' + + // Set btns to disabled + stableBtn.disabled = true + stableBtn.classList.add('disabled') + + devBtn.disabled = true + devBtn.classList.add('disabled') +} + +async function resetDownloadButtons() { + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') + + stableBtn.innerText = localeObj.stableInstall || 'Download' + devBtn.innerText = localeObj.devInstall || 'Download' + + // Set btns to enabled + stableBtn.disabled = false + stableBtn.classList.remove('disabled') + + devBtn.disabled = false + devBtn.classList.remove('disabled') +} + async function downloadGC(branch) { const config = await getCfg() @@ -14,8 +45,13 @@ async function downloadGC(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() + // Keystore for branch (since they can differ) const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12` @@ -56,6 +92,10 @@ async function downloadGC(branch) { // Run installer createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + // Fix buttons + resetDownloadButtons() + // Display folder after saving config displayServerFolder() + displayServerLaunchSection() } \ No newline at end of file diff --git a/resources/style/index.css b/resources/style/index.css index 6bb5548..f738e24 100644 --- a/resources/style/index.css +++ b/resources/style/index.css @@ -11,6 +11,10 @@ a { color: #fff; } +img { + height: 20px; +} + .darken { filter: brightness(0.6); } From fdc3abb6008002cc58a3febda7adb9a583d28b8c Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:40:11 -0700 Subject: [PATCH 193/248] translation setup for downloads --- languages/en.json | 16 ++++++++++++++++ resources/index.html | 2 +- resources/js/translation.js | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/languages/en.json b/languages/en.json index a7ecafe..1fecb4d 100644 --- a/languages/en.json +++ b/languages/en.json @@ -63,5 +63,21 @@ "alertAuthNoRegister": "Authentication is disabled, no need to register!", "alertRegisterSuccess": "Registration successful!", + "downloadTitle": "Downloads", + "grassclipperTitle": "GrassClipper", + "grasscutterTitle": "Grasscutter", + "installerTitle": "Installer", + "installerSubtitle": "Installs proxy and other tools. Required for Grasscutter servers.", + "downloadStable": "Download Grasscutter Stable Build", + "stableSubtitle": "Install Grasscutter stable branch. This build usually has less bugs, but also less features.", + "downloadDev": "Download Grasscutter Development Build", + "downloadSubtitle": "Install Grasscutter development branch. This build sometimes has bugs, and is frequently updated. Use at your own risk.", + "downloadResources": "Download Grasscutter Resources", + "devSubtitle": "Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally.", + + "gcScriptRunning": "Running...", + "stableInstall": "Download", + "devInstall": "Download", + "updateNotifText": "A new update is available! Newest version: " } diff --git a/resources/index.html b/resources/index.html index f3edc5d..bb71778 100644 --- a/resources/index.html +++ b/resources/index.html @@ -135,7 +135,7 @@ Installs proxy and other tools. Required for Grasscutter servers.
-
+
Grasscutter
diff --git a/resources/js/translation.js b/resources/js/translation.js index 986b03c..2f1d17d 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -90,6 +90,21 @@ async function doTranslation() { set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') set('noLoginBtn', 'launchWithoutAuth') + // Downloads section + set('downloadTitle', 'downloadTitle') + set('grassclipperTitle', 'grassclipperTitle') + set('grasscutterTitle', 'grasscutterTitle') + set('installerTitle', 'installerTitle') + set('installerSubtitle', 'installerSubtitle') + set('downloadStable', 'downloadStable') + set('stableSubtitle', 'stableSubtitle') + set('downloadDev', 'downloadDev') + set('downloadSubtitle', 'downloadSubtitle') + set('downloadResources', 'downloadResources') + set('devSubtitle', 'devSubtitle') + set('stableInstall', 'stableInstall') + set('devInstall', 'devInstall') + // update notification set('updateNotifText', 'updateNotifText') } \ No newline at end of file From ff9c0f203952ecf55f0ffe98353350054cf3d570 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:54:40 -0700 Subject: [PATCH 194/248] bugfix --- resources/js/index.js | 2 +- resources/js/translation.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/index.js b/resources/js/index.js index 6e14f7d..a9a0bee 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -411,7 +411,7 @@ async function setGameExe() { ] }) - if (!gameexe[0]) return; + if (!gameExe[0]) return; // Set the folder in our configuration const config = await getCfg() diff --git a/resources/js/translation.js b/resources/js/translation.js index 2f1d17d..dd80b83 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -99,7 +99,7 @@ async function doTranslation() { set('downloadStable', 'downloadStable') set('stableSubtitle', 'stableSubtitle') set('downloadDev', 'downloadDev') - set('downloadSubtitle', 'downloadSubtitle') + set('devSubtitle', 'downloadSubtitle') set('downloadResources', 'downloadResources') set('devSubtitle', 'devSubtitle') set('stableInstall', 'stableInstall') From dc486fd83003904525076a5b2cee5ca527660718 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Sun, 1 May 2022 23:59:20 -0700 Subject: [PATCH 195/248] enable server button --- resources/js/gcdownloader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index a8523f0..e45a0f4 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -97,5 +97,6 @@ async function downloadGC(branch) { // Display folder after saving config displayServerFolder() + enableServerButton() displayServerLaunchSection() } \ No newline at end of file From 2e68da72be3192c293aef38cce05cbfd9b38c04e Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 02:47:55 -0700 Subject: [PATCH 196/248] fix killswitch --- scripts/private_server_launch.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/private_server_launch.cmd b/scripts/private_server_launch.cmd index 0cc7b12..5fcbf1e 100644 --- a/scripts/private_server_launch.cmd +++ b/scripts/private_server_launch.cmd @@ -27,7 +27,7 @@ if "%ENABLE_KILLSWITCH%" EQU "true" ( :: Restart in elevated if need be >nul 2>&1 reg query "HKU\S-1-5-19" || ( set params = %*:"="""% - cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%/../"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" && exit /b ) + cd /d "%~dp0" && ( if exist "%temp%\getadmin.vbs" del "%temp%\getadmin.vbs" ) && fsutil dirty query %systemdrive% 1>nul 2>nul || ( echo Set UAC = CreateObject^("Shell.Application"^) : UAC.ShellExecute "cmd.exe", "/k cd ""%~sdp0"" && %~s0 %1 %2 %3 "%4" ""%cd%"" %6", "", "runas", 1 >> "%temp%\getadmin.vbs" && "%temp%\getadmin.vbs" && taskkill /f /fi "WINDOWTITLE eq PS Launcher Script" && exit /b ) ) ) @@ -41,7 +41,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 :: 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% From 3379e688a68b6e33c0763d8a953feec77b9e688b Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 22:00:55 -0700 Subject: [PATCH 197/248] java version script --- scripts/javaver.cmd | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 scripts/javaver.cmd diff --git a/scripts/javaver.cmd b/scripts/javaver.cmd new file mode 100644 index 0000000..dad849f --- /dev/null +++ b/scripts/javaver.cmd @@ -0,0 +1,38 @@ +@echo off + +set BRANCH=%1 + +echo Checking java version... + +:: https://stackoverflow.com/questions/5675459/how-to-get-java-version-from-batch-script +for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do ( + @echo Output: %%g + set JAVAVER=%%g +) +set JAVAVER=%JAVAVER:"=% + +for /f "delims=. tokens=1-3" %%v in ("%JAVAVER%") do ( + set MAJOR=%%v + set MINOR=%%w + set BUILD=%%x +) + +if %BRANCH% EQU stable ( + :: Ensure java 8 + if %MAJOR% EQU 1 ( + if %MINOR% LSS 8 ( + echo Java version is less than 8, please download Java 8 + exit /b + ) + ) +) + +if %BRANCH% EQU development ( + :: Ensure java 17 + if %MAJOR% LSS 17 ( + echo Java version is less than 17, please download Java 17 + exit /b + ) +) + +echo Java version is compatible \ No newline at end of file From 66abd0feba68c216bd5e4b7ff7de2655b0803809 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 22:35:53 -0700 Subject: [PATCH 198/248] java version checking --- scripts/gc_download.cmd | 3 +++ scripts/javaver.cmd | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/scripts/gc_download.cmd b/scripts/gc_download.cmd index 1b24f2b..6d822d2 100644 --- a/scripts/gc_download.cmd +++ b/scripts/gc_download.cmd @@ -34,6 +34,9 @@ echo Downloading keystore.p12... :: Download the keystore.p12 file powershell Invoke-WebRequest -Uri %ARTIFACT_URL% -OutFile "./%FOLDER_NAME%/keystore.p12" +:: Check java version, this will automatically output some tuff +call .\scripts\javaver.cmd %BRANCH% + :: Allow resource downloading to be optional, since it takes a while set REPLY=y set /p "REPLY=Download server resources? (This can take a while) [y|n]:" diff --git a/scripts/javaver.cmd b/scripts/javaver.cmd index dad849f..fc97d4d 100644 --- a/scripts/javaver.cmd +++ b/scripts/javaver.cmd @@ -21,16 +21,30 @@ if %BRANCH% EQU stable ( :: Ensure java 8 if %MAJOR% EQU 1 ( if %MINOR% LSS 8 ( - echo Java version is less than 8, please download Java 8 + echo ======================================================================================= + echo !! Java version is less than 8 !! + echo Please download Java 8 to ensure %BRANCH% branch server launches correctly. + 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 Java version is less than 17, please download Java 17 + echo ======================================================================================= + echo !! Java version is less than 17 !! + echo Please download Java 17 to ensure %BRANCH% branch server launches correctly. + echo ======================================================================================= exit /b ) ) From f94350af735422547beac147e3ae3045428f363a Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 22:38:04 -0700 Subject: [PATCH 199/248] handle no java installed --- scripts/javaver.cmd | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/javaver.cmd b/scripts/javaver.cmd index fc97d4d..c22093a 100644 --- a/scripts/javaver.cmd +++ b/scripts/javaver.cmd @@ -4,6 +4,24 @@ set BRANCH=%1 echo Checking java version... +where java >nul 2>nul +if %errorlevel%==1 ( + echo ======================================================================================= + echo No version of Java was found! + + if %BRANCH% EQU stable ( + 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 ======================================================================================= + + exit /b +) + :: https://stackoverflow.com/questions/5675459/how-to-get-java-version-from-batch-script for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do ( @echo Output: %%g From eae6cc087b2b2baff8e3149430516568e04c4e7f Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 22:44:57 -0700 Subject: [PATCH 200/248] eslint changes --- .eslintrc.json | 29 ++ package.json | 3 + resources/js/authAlert.js | 46 +-- resources/js/gcdownloader.js | 132 ++++---- resources/js/helpers.js | 118 +++---- resources/js/hoverEvt.js | 56 ++-- resources/js/index.js | 580 +++++++++++++++++------------------ resources/js/login.js | 182 +++++------ resources/js/onLoad.js | 136 ++++---- resources/js/options.js | 114 +++---- resources/js/translation.js | 176 +++++------ resources/js/windowDrag.js | 32 +- 12 files changed, 818 insertions(+), 786 deletions(-) create mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..064214d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es2021": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 13 + }, + "rules": { + "indent": [ + "error", + 4 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "never" + ] + } +} diff --git a/package.json b/package.json index e5efc86..9c0eb1a 100644 --- a/package.json +++ b/package.json @@ -9,5 +9,8 @@ "build-win": ".\\build_win.cmd", "build-linux": "./build.sh", "build": "echo !! Run build-win or build-linux to build for your platform !!\n" + }, + "devDependencies": { + "eslint": "^8.14.0" } } diff --git a/resources/js/authAlert.js b/resources/js/authAlert.js index c6b806e..9580530 100644 --- a/resources/js/authAlert.js +++ b/resources/js/authAlert.js @@ -1,45 +1,45 @@ let alertTimeout, alertCooldown = 3000 async function displayLoginAlert(message, type, cooldown = null) { - displayAlert(message, type, cooldown, 'login') + displayAlert(message, type, cooldown, 'login') } async function displayRegisterAlert(message, type, cooldown = null) { - displayAlert(message, type, cooldown, 'register') + displayAlert(message, type, cooldown, 'register') } function displayAlert(message, type, cooldown, name) { - const elm = document.getElementById(`${name}Alert`); - const text = document.getElementById(`${name}AlertText`); + const elm = document.getElementById(`${name}Alert`) + const text = document.getElementById(`${name}AlertText`) - elm.style.removeProperty('display'); + elm.style.removeProperty('display') - // Remove classification classes - elm.classList.remove('error'); - elm.classList.remove('success'); - elm.classList.remove('warn'); + // Remove classification classes + elm.classList.remove('error') + elm.classList.remove('success') + elm.classList.remove('warn') - switch(type) { + switch(type) { case 'error': - elm.classList.add('error'); - break; + elm.classList.add('error') + break case 'success': - elm.classList.add('success'); - break; + elm.classList.add('success') + break case 'warn': default: - elm.classList.add('warn'); - break; - } + elm.classList.add('warn') + break + } - text.innerText = message; + text.innerText = message - clearTimeout(alertTimeout) + clearTimeout(alertTimeout) - // Disappear after cooldown - alertTimeout = setTimeout(() => { - elm.style.display = 'none'; - }, cooldown || alertCooldown) + // Disappear after cooldown + alertTimeout = setTimeout(() => { + elm.style.display = 'none' + }, cooldown || alertCooldown) } \ No newline at end of file diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index e45a0f4..bcc6e7a 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -1,102 +1,102 @@ async function clearGCInstallation() { - Neutralino.os.execCommand(`del /s /q "./gc"`) + Neutralino.os.execCommand('del /s /q "./gc"') } async function setDownloadButtonsToLoading() { - const stableBtn = document.querySelector('#stableInstall') - const devBtn = document.querySelector('#devInstall') + const stableBtn = document.querySelector('#stableInstall') + 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 - stableBtn.disabled = true - stableBtn.classList.add('disabled') + // Set btns to disabled + stableBtn.disabled = true + stableBtn.classList.add('disabled') - devBtn.disabled = true - devBtn.classList.add('disabled') + devBtn.disabled = true + devBtn.classList.add('disabled') } async function resetDownloadButtons() { - const stableBtn = document.querySelector('#stableInstall') - const devBtn = document.querySelector('#devInstall') + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') - stableBtn.innerText = localeObj.stableInstall || 'Download' - devBtn.innerText = localeObj.devInstall || 'Download' + stableBtn.innerText = localeObj.stableInstall || 'Download' + devBtn.innerText = localeObj.devInstall || 'Download' - // Set btns to enabled - stableBtn.disabled = false - stableBtn.classList.remove('disabled') + // Set btns to enabled + stableBtn.disabled = false + stableBtn.classList.remove('disabled') - devBtn.disabled = false - devBtn.classList.remove('disabled') + devBtn.disabled = false + devBtn.classList.remove('disabled') } async function downloadGC(branch) { - const config = await getCfg() + const config = await getCfg() - // If we are pulling from a new branch, delete the old installation - if (config.grasscutterBranch !== branch) await clearGCInstallation() + // If we are pulling from a new branch, delete the old installation + if (config.grasscutterBranch !== branch) await clearGCInstallation() - // Set current installation in config - config.grasscutterBranch = branch + // Set current installation in config + config.grasscutterBranch = branch - // Set gc path for people with launcher enabled - config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` + // Set gc path for people with launcher enabled + config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` - // Enable server launcher - config.serverLaunchPanel = true + // Enable server launcher + config.serverLaunchPanel = true - Neutralino.storage.setData('config', JSON.stringify(config)) + 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` + // 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` + // External service that allows un-authed artifact downloading + const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip` - // For data files - const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) - const dataList = dataFiles.data - .map(file => ({ path: file.path, filename: file.name })) - .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + // For data files + const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) + const dataList = dataFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) - // For key files - const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) - const keyList = keyFiles.data - .map(file => ({ path: file.path, filename: file.name })) - .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + // For key files + const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) + const keyList = keyFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) - const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') + const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') - // Ensure data and key folders exist + // Ensure data and key folders exist - await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) - await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) - // Download data files - for (const o of dataList) { - const folder = 'data' - await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) - } + // Download data files + for (const o of dataList) { + const folder = 'data' + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } - // Download key files - for (const o of keyList) { - const folder = 'keys' - await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) - } + // Download key files + for (const o of keyList) { + const folder = 'keys' + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } - // Run installer - createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + // Run installer + createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) - // Fix buttons - resetDownloadButtons() + // Fix buttons + resetDownloadButtons() - // Display folder after saving config - displayServerFolder() - enableServerButton() - displayServerLaunchSection() + // Display folder after saving config + displayServerFolder() + enableServerButton() + displayServerLaunchSection() } \ No newline at end of file diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 4e3a38b..a4f514d 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -3,28 +3,28 @@ * * @returns {Promise} */ - async function getCfg() { - const defaultConf = { - gameexe: '', - serverFolder: '', - lastConnect: '', - enableKillswitch: false, - serverLaunchPanel: false, - language: 'en', - useHttps: true, - grasscutterBranch: '', - } - const cfgStr = await Neutralino.storage.getData('config').catch(e => { +async function getCfg() { + const defaultConf = { + gameexe: '', + serverFolder: '', + lastConnect: '', + enableKillswitch: false, + serverLaunchPanel: false, + language: 'en', + useHttps: true, + grasscutterBranch: '', + } + const cfgStr = await Neutralino.storage.getData('config').catch(e => { // The data isn't set, so this is our first time opening - Neutralino.storage.setData('config', JSON.stringify(defaultConf)) + Neutralino.storage.setData('config', JSON.stringify(defaultConf)) - // Show the first time notice if there is no config - document.querySelector('#firstTimeNotice').style.display = 'block' - }) + // Show the first time notice if there is no config + document.querySelector('#firstTimeNotice').style.display = 'block' + }) - const config = cfgStr ? JSON.parse(cfgStr) : defaultConf + const config = cfgStr ? JSON.parse(cfgStr) : defaultConf - return config + return config } /** @@ -32,91 +32,91 @@ * * @returns {Promise} */ - async function getFavIps() { - const ipStr = await Neutralino.storage.getData('favorites').catch(e => { +async function getFavIps() { + const ipStr = await Neutralino.storage.getData('favorites').catch(e => { // The data isn't set, so this is our first time opening - Neutralino.storage.setData('favorites', JSON.stringify([])) - }) + Neutralino.storage.setData('favorites', JSON.stringify([])) + }) - const ipArr = ipStr ? JSON.parse(ipStr) : [] + const ipArr = ipStr ? JSON.parse(ipStr) : [] - return ipArr + return ipArr } async function proxyIsInstalled() { - // Check if the proxy server is installed - const curDirList = await filesystem.readDirectory(NL_CWD) + // Check if the proxy server is installed + const curDirList = await filesystem.readDirectory(NL_CWD) - if (curDirList.find(f => f.entry === 'ext')) { - const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') + if (curDirList.find(f => f.entry === 'ext')) { + const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') - if (extFiles.find(f => f.entry === 'mitmdump.exe')) { - return true + if (extFiles.find(f => f.entry === 'mitmdump.exe')) { + return true + } } - } - return false + return false } 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 latest = data.tag_name + const { data } = await axios.get(url) + const latest = data.tag_name - return latest + return latest } async function displayUpdate() { - const latest = await checkForUpdates() - const versionDisplay = document.querySelector('#newestVersion') - const notif = document.querySelector('#downloadNotif') + const latest = await checkForUpdates() + const versionDisplay = document.querySelector('#newestVersion') + const notif = document.querySelector('#downloadNotif') - if (latest === `v${NL_APPVERSION}`) return + if (latest === `v${NL_APPVERSION}`) return - versionDisplay.innerText = latest + versionDisplay.innerText = latest - notif.classList.add('displayed') + notif.classList.add('displayed') - setTimeout(() => { - notif.classList.remove('displayed') - }, 5000) + setTimeout(() => { + notif.classList.remove('displayed') + }, 5000) } async function openLatestDownload() { - const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' + const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' - Neutralino.os.open(downloadLink) + Neutralino.os.open(downloadLink) } async function openGameFolder() { - const config = await getCfg() - const folder = config.gameexe.match(/.*\\/g, '')[0] + const config = await getCfg() + const folder = config.gameexe.match(/.*\\/g, '')[0] - openInExplorer(folder) + openInExplorer(folder) } async function openGrasscutterFolder() { - const config = await getCfg() - const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] + const config = await getCfg() + const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] - openInExplorer(folder) + openInExplorer(folder) } /** * Minimize the window */ - function minimizeWin() { - console.log('min') - Neutralino.window.minimize() +function minimizeWin() { + console.log('min') + Neutralino.window.minimize() } /** * Close the window */ function closeWin() { - console.log('close') - Neutralino.app.exit() + console.log('close') + Neutralino.app.exit() - window.close() + window.close() } diff --git a/resources/js/hoverEvt.js b/resources/js/hoverEvt.js index 47adb2c..af98ea0 100644 --- a/resources/js/hoverEvt.js +++ b/resources/js/hoverEvt.js @@ -1,36 +1,36 @@ document.addEventListener('DOMContentLoaded', async () => { - const firstPanel = document.querySelector('#firstPanel') - const secondPanel = document.querySelector('#secondPanel') - const thirdPanel = document.querySelector('#thirdPanel') + const firstPanel = document.querySelector('#firstPanel') + const secondPanel = document.querySelector('#secondPanel') + const thirdPanel = document.querySelector('#thirdPanel') - // Listen to hovers - firstPanel.addEventListener('mouseover', () => { - secondPanel.classList.add('darken') - thirdPanel.classList.add('darken') - }) + // Listen to hovers + firstPanel.addEventListener('mouseover', () => { + secondPanel.classList.add('darken') + thirdPanel.classList.add('darken') + }) - firstPanel.addEventListener('mouseout', () => { - secondPanel.classList.remove('darken') - thirdPanel.classList.remove('darken') - }) + firstPanel.addEventListener('mouseout', () => { + secondPanel.classList.remove('darken') + thirdPanel.classList.remove('darken') + }) - secondPanel.addEventListener('mouseover', () => { - firstPanel.classList.add('darken') - thirdPanel.classList.add('darken') - }) + secondPanel.addEventListener('mouseover', () => { + firstPanel.classList.add('darken') + thirdPanel.classList.add('darken') + }) - secondPanel.addEventListener('mouseout', () => { - firstPanel.classList.remove('darken') - thirdPanel.classList.remove('darken') - }) + secondPanel.addEventListener('mouseout', () => { + firstPanel.classList.remove('darken') + thirdPanel.classList.remove('darken') + }) - thirdPanel.addEventListener('mouseover', () => { - firstPanel.classList.add('darken') - secondPanel.classList.add('darken') - }) + thirdPanel.addEventListener('mouseover', () => { + firstPanel.classList.add('darken') + secondPanel.classList.add('darken') + }) - thirdPanel.addEventListener('mouseout', () => { - firstPanel.classList.remove('darken') - secondPanel.classList.remove('darken') - }) + thirdPanel.addEventListener('mouseout', () => { + firstPanel.classList.remove('darken') + secondPanel.classList.remove('darken') + }) }) \ No newline at end of file diff --git a/resources/js/index.js b/resources/js/index.js index a9a0bee..822fb67 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -1,187 +1,187 @@ -Neutralino.init(); +Neutralino.init() -let localeObj; +let localeObj const filesystem = Neutralino.filesystem const createCmdWindow = async (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) => { - console.log(`explorer.exe "${path}"`) - createCmdWindow(`explorer.exe "${path}"`) + console.log(`explorer.exe "${path}"`) + createCmdWindow(`explorer.exe "${path}"`) } /** * Enable play buttons */ async function enableButtons() { - const offBtn = document.querySelector('#playOfficial') - const privBtn = document.querySelector('#playPrivate') + const offBtn = document.querySelector('#playOfficial') + const privBtn = document.querySelector('#playPrivate') - offBtn.classList.remove('disabled') - offBtn.disabled = false + offBtn.classList.remove('disabled') + offBtn.disabled = false - // Check if the proxy server is installed - if (await proxyIsInstalled()) { - privBtn.classList.remove('disabled') - privBtn.disabled = false - } + // Check if the proxy server is installed + if (await proxyIsInstalled()) { + privBtn.classList.remove('disabled') + privBtn.disabled = false + } } /** * Enable server launch button */ - async function enableServerButton() { - const serverBtn = document.querySelector('#serverLaunch') +async function enableServerButton() { + const serverBtn = document.querySelector('#serverLaunch') - serverBtn.classList.remove('disabled') - serverBtn.disabled = false + serverBtn.classList.remove('disabled') + serverBtn.disabled = false } /** * Disable buttons when the game folder is not set */ async function handleGameNotSet() { - // Set buttons to greyed out and disable - document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet + // Set buttons to greyed out and disable + document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet - // Set official server background to default - document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` + // Set official server background to default + document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")' - const offBtn = document.querySelector('#playOfficial') - const privBtn = document.querySelector('#playPrivate') + const offBtn = document.querySelector('#playOfficial') + const privBtn = document.querySelector('#playPrivate') - offBtn.classList.add('disabled') - offBtn.disabled = true + offBtn.classList.add('disabled') + offBtn.disabled = true - privBtn.classList.add('disabled') - privBtn.disabled = true + privBtn.classList.add('disabled') + privBtn.disabled = true - // TODO show a dialog of sorts + // TODO show a dialog of sorts } async function handleServerNotSet() { - // Set buttons to greyed out and disable - document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet + // Set buttons to greyed out and disable + document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet - // Set official server background to default - // document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` + // Set official server background to default + // document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` - const privBtn = document.querySelector('#serverLaunch') + const privBtn = document.querySelector('#serverLaunch') - privBtn.classList.add('disabled') - privBtn.disabled = true + privBtn.classList.add('disabled') + privBtn.disabled = true } /** * Show the game folder under the select button */ async function displayGameFolder() { - const elm = document.querySelector('#gamePath') - const config = await getCfg() + const elm = document.querySelector('#gamePath') + const config = await getCfg() - elm.innerHTML = config.gameexe + elm.innerHTML = config.gameexe } /** * Show the server folder under the select button */ - async function displayServerFolder() { - const elm = document.querySelector('#serverPath') - const config = await getCfg() +async function displayServerFolder() { + const elm = document.querySelector('#serverPath') + const config = await getCfg() - elm.innerHTML = config.serverFolder + elm.innerHTML = config.serverFolder } /** * Set the background images of both the private and public sections */ async function setBackgroundImage() { - const config = await getCfg() + const config = await getCfg() - const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) - const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry + const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) + const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry - const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) - const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry + const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) + const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry - // 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")` + // 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")' - // Set the private background image - document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")` + // Set the private background image + document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")` - // Set the server background image - document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")` + // Set the server background image + document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")` - return + return - // Check if resources folder exists - const mainDir = await filesystem.readDirectory(NL_CWD) - if (!mainDir.find(dir => dir.entry === 'resources')) { - await filesystem.createDirectory(NL_CWD + '/resources') - } - - // Ensure bg folder exists - const bgDir = await filesystem.readDirectory(NL_CWD + '/resources') - if (!bgDir.find(dir => dir.entry === 'bg')) { - await filesystem.createDirectory(NL_CWD + '/resources/bg') - } - - // Ensure official folder exists - const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg') - if (!officialDir.find(dir => dir.entry === 'official')) { - await filesystem.createDirectory(NL_CWD + '/resources/bg/official') - } - - if (config.gameexe) { - // See if bg folder exists in parent dir - const parentDir = await filesystem.readDirectory(config.gameexe + '/..') - - if (parentDir.find(dir => dir.entry === 'bg')) { - - const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') - - if (officialImages.length > 0) { - for (const bg of officialImages) { - const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry - - // See if the file exists already - const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') - - if (!currentBgs.find(file => file.entry === bg.entry)) { - await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => { - // TODO: Handle error - }) - } - } - - // Pick one of the images - const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE') - const image = localImg[Math.floor(Math.random() * localImg.length)].entry - - // Set background image - document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")` - } + // Check if resources folder exists + const mainDir = await filesystem.readDirectory(NL_CWD) + if (!mainDir.find(dir => dir.entry === 'resources')) { + await filesystem.createDirectory(NL_CWD + '/resources') + } + + // Ensure bg folder exists + const bgDir = await filesystem.readDirectory(NL_CWD + '/resources') + if (!bgDir.find(dir => dir.entry === 'bg')) { + await filesystem.createDirectory(NL_CWD + '/resources/bg') + } + + // Ensure official folder exists + const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg') + if (!officialDir.find(dir => dir.entry === 'official')) { + await filesystem.createDirectory(NL_CWD + '/resources/bg/official') + } + + if (config.gameexe) { + // See if bg folder exists in parent dir + const parentDir = await filesystem.readDirectory(config.gameexe + '/..') + + if (parentDir.find(dir => dir.entry === 'bg')) { + + const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') + + if (officialImages.length > 0) { + for (const bg of officialImages) { + const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry + + // See if the file exists already + const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') + + if (!currentBgs.find(file => file.entry === bg.entry)) { + await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => { + // TODO: Handle error + }) + } + } + + // Pick one of the images + const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE') + const image = localImg[Math.floor(Math.random() * localImg.length)].entry + + // Set background image + document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")` + } + } } - } } /** * When an IP is being input, check if it is part of the favorites */ async function handleFavoriteInput() { - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value || '443' - const ipArr = await getFavIps() + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value || '443' + const ipArr = await getFavIps() - const addr = `${ip}:${port}` + const addr = `${ip}:${port}` - if (!ip || !ipArr.includes(addr)) { - document.querySelector('#star').src = 'icons/star_empty.svg' - } else { - document.querySelector('#star').src = 'icons/star_filled.svg' - } + if (!ip || !ipArr.includes(addr)) { + document.querySelector('#star').src = 'icons/star_empty.svg' + } else { + document.querySelector('#star').src = 'icons/star_filled.svg' + } } /** @@ -190,182 +190,182 @@ async function handleFavoriteInput() { * @param {String} ip */ async function setIp(ip) { - const ipInput = document.querySelector('#ip') - const portInput = document.querySelector('#port') + const ipInput = document.querySelector('#ip') + const portInput = document.querySelector('#port') - const parseIp = ip.split(':')[0] - const parsePort = ip.split(':')[1] + const parseIp = ip.split(':')[0] + const parsePort = ip.split(':')[1] - // Set star - if (ip) { - document.querySelector('#star').src = 'icons/star_filled.svg' - } + // Set star + if (ip) { + document.querySelector('#star').src = 'icons/star_filled.svg' + } - ipInput.value = parseIp - portInput.value = parsePort + ipInput.value = parseIp + portInput.value = parsePort } /** * Create/hide the favorites list */ async function handleFavoriteList() { - const ipArr = await getFavIps() - const ipList = document.querySelector('#ipList') + const ipArr = await getFavIps() + const ipList = document.querySelector('#ipList') - if (ipList.style.display === 'none') { - ipList.innerHTML = '' + if (ipList.style.display === 'none') { + ipList.innerHTML = '' - const list = ipList.appendChild( - document.createElement('ul') - ) + const list = ipList.appendChild( + document.createElement('ul') + ) - if (ipArr.length < 1) { - const listItem = list.appendChild( - document.createElement('li') - ) + if (ipArr.length < 1) { + const listItem = list.appendChild( + document.createElement('li') + ) - listItem.innerHTML = localeObj.noFavorites + listItem.innerHTML = localeObj.noFavorites + } + + for (const ip of ipArr) { + const elm = document.createElement('li') + elm.innerHTML = ip + elm.addEventListener('click', () => setIp(ip)) + list.appendChild(elm) + } + + ipList.style.display = 'block' + + const transform = window.getComputedStyle(document.querySelector('#ipList')).transform + const xy = [ transform.split(',')[4], transform.split(',')[5] ] + let newY = (27 * ipArr.length) * window.devicePixelRatio + + if (ipArr.length === 0 || ipArr.length === 1) newY = 0 + + ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)` } - - for (const ip of ipArr) { - const elm = document.createElement('li') - elm.innerHTML = ip - elm.addEventListener('click', () => setIp(ip)) - list.appendChild(elm) - } - - ipList.style.display = 'block' - - const transform = window.getComputedStyle(document.querySelector('#ipList')).transform - const xy = [ transform.split(',')[4], transform.split(',')[5] ] - let newY = (27 * ipArr.length) * window.devicePixelRatio - - if (ipArr.length === 0 || ipArr.length === 1) newY = 0 - - ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)` - } } async function openDownloads() { - const downloads = document.querySelector('#downloadPanel') - const config = await getCfg() + const downloads = document.querySelector('#downloadPanel') + const config = await getCfg() - if (downloads.style.display === 'none') { - downloads.style.removeProperty('display') - } + if (downloads.style.display === 'none') { + downloads.style.removeProperty('display') + } - // Disable the resource download button if a serverFolder path is not set - if (!config.serverFolder) { - document.querySelector('#resourceInstall').disabled = true - document.querySelector('#resourceInstall').classList.add('disabled') - } else { - document.querySelector('#resourceInstall').disabled = false - document.querySelector('#resourceInstall').classList.remove('disabled') - } + // Disable the resource download button if a serverFolder path is not set + if (!config.serverFolder) { + document.querySelector('#resourceInstall').disabled = true + document.querySelector('#resourceInstall').classList.add('disabled') + } else { + document.querySelector('#resourceInstall').disabled = false + document.querySelector('#resourceInstall').classList.remove('disabled') + } } async function closeDownloads() { - const downloads = document.querySelector('#downloadPanel') + const downloads = document.querySelector('#downloadPanel') - downloads.style.display = 'none' + downloads.style.display = 'none' } async function openSettings() { - const settings = document.querySelector('#settingsPanel') - const config = await getCfg() + const settings = document.querySelector('#settingsPanel') + const config = await getCfg() - if (settings.style.display === 'none') { - settings.style.removeProperty('display') - } + if (settings.style.display === 'none') { + settings.style.removeProperty('display') + } - // Fill setting options with what is currently set in config - const killSwitch = document.querySelector('#killswitchOption') - const serverLaunch = document.querySelector('#serverLaunchOption') - const httpsCheckbox = document.querySelector('#httpsOption') + // Fill setting options with what is currently set in config + const killSwitch = document.querySelector('#killswitchOption') + const serverLaunch = document.querySelector('#serverLaunchOption') + const httpsCheckbox = document.querySelector('#httpsOption') - killSwitch.checked = config.enableKillswitch - serverLaunch.checked = config.serverLaunchPanel - httpsCheckbox.checked = config.useHttps + killSwitch.checked = config.enableKillswitch + serverLaunch.checked = config.serverLaunchPanel + httpsCheckbox.checked = config.useHttps - // Load languages - getLanguages() + // Load languages + getLanguages() - // Check for updates - //checkForUpdatesAndShow() + // Check for updates + //checkForUpdatesAndShow() } async function closeSettings() { - const settings = document.querySelector('#settingsPanel') - const config = await getCfg() + const settings = document.querySelector('#settingsPanel') + const config = await getCfg() - settings.style.display = 'none' + settings.style.display = 'none' - // In case we installed the proxy server - if (await proxyIsInstalled() && config.gameexe) { - const playPriv = document.querySelector('#playPrivate') + // In case we installed the proxy server + if (await proxyIsInstalled() && config.gameexe) { + const playPriv = document.querySelector('#playPrivate') - playPriv.classList.remove('disabled') - playPriv.disabled = false - } + playPriv.classList.remove('disabled') + playPriv.disabled = false + } } async function openLogin() { - const login = document.querySelector('#loginPanel') - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value - const loginIpDisplay = document.querySelector('#loginPopupServer') - const registerIpDisplay = document.querySelector('#registerPopupServer') + const login = document.querySelector('#loginPanel') + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value + const loginIpDisplay = document.querySelector('#loginPopupServer') + const registerIpDisplay = document.querySelector('#registerPopupServer') - const config = await getCfg() - const useHttps = config.useHttps - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`; + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - // Check if we even need to authenticate - try { - const { data } = await axios.get(url + '/authentication/type') + // Check if we even need to authenticate + try { + const { data } = await axios.get(url + '/authentication/type') - if (!data.includes('GCAuthAuthenticationHandler')) { - launchPrivate() - return + if (!data.includes('GCAuthAuthenticationHandler')) { + launchPrivate() + return + } + } catch(e) { + launchPrivate() + return } - } catch(e) { - launchPrivate() - return - } - loginIpDisplay.innerText = ip - registerIpDisplay.innerText = ip + loginIpDisplay.innerText = ip + registerIpDisplay.innerText = ip - if (login.style.display === 'none') { - login.style.removeProperty('display') - } + if (login.style.display === 'none') { + login.style.removeProperty('display') + } } async function closeLogin() { - const login = document.querySelector('#loginPanel') + const login = document.querySelector('#loginPanel') - login.style.display = 'none' + login.style.display = 'none' - setLoginSection() + setLoginSection() } async function closeFirstTimePopup() { - const firstTimePopup = document.querySelector('#firstTimeNotice') - firstTimePopup.style.display = 'none' + const firstTimePopup = document.querySelector('#firstTimeNotice') + firstTimePopup.style.display = 'none' } async function runInstallScript() { - 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 - const interval = setInterval(async () => { - if (await proxyIsInstalled()) { - clearInterval(interval) - enableButtons() - } - }, 1000) + // Create an interval that will check for the proxy server installation finish + const interval = setInterval(async () => { + if (await proxyIsInstalled()) { + clearInterval(interval) + enableButtons() + } + }, 1000) - closeFirstTimePopup() + closeFirstTimePopup() } async function updateResources() { @@ -373,109 +373,109 @@ async function updateResources() { } async function checkForUpdatesAndShow() { - const updateBtn = document.querySelector('#updateBtn') - const subtitle = document.querySelector('#updateSubtitle') - const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/' - const manifest = await Neutralino.updater.checkForUpdates(url) + const updateBtn = document.querySelector('#updateBtn') + const subtitle = document.querySelector('#updateSubtitle') + const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/' + const manifest = await Neutralino.updater.checkForUpdates(url) - // Version mismatch? Update! - if (manifest?.version !== NL_APPVERSION) { - subtitle.innerHTML = "New update available!" - updateBtn.classList.remove('disabled') - } else { - subtitle.innerHTML = "You are on the latest version! :)" - updateBtn.classList.add('disabled') - } + // Version mismatch? Update! + if (manifest?.version !== NL_APPVERSION) { + subtitle.innerHTML = 'New update available!' + updateBtn.classList.remove('disabled') + } else { + subtitle.innerHTML = 'You are on the latest version! :)' + updateBtn.classList.add('disabled') + } } async function displayServerLaunchSection() { - const serverPanel = document.querySelector('#thirdPanel') - const bottomBtnSection = document.querySelector('#serverPath').parentElement + const serverPanel = document.querySelector('#thirdPanel') + const bottomBtnSection = document.querySelector('#serverPath').parentElement - if (serverPanel.style.display === 'none') { - serverPanel.style.removeProperty('display') - bottomBtnSection.style.removeProperty('display') - } else { - serverPanel.style.display = 'none' - bottomBtnSection.style.display = 'none' - } + if (serverPanel.style.display === 'none') { + serverPanel.style.removeProperty('display') + bottomBtnSection.style.removeProperty('display') + } else { + serverPanel.style.display = 'none' + bottomBtnSection.style.display = 'none' + } } /** * Set the game folder by opening a folder picker */ async function setGameExe() { - const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { - filters: [ - { name: 'Executable files', extensions: ['exe'] } - ] - }) + const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { + filters: [ + { name: 'Executable files', extensions: ['exe'] } + ] + }) - if (!gameExe[0]) return; + if (!gameExe[0]) return - // Set the folder in our configuration - const config = await getCfg() + // Set the folder in our configuration + const config = await getCfg() - // It's an array of selections, so only get the first one - config.gameexe = gameExe[0].replace(/\//g, '\\') + // It's an array of selections, so only get the first one + config.gameexe = gameExe[0].replace(/\//g, '\\') - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) - // Refresh background and path - setBackgroundImage() - displayGameFolder() - enableButtons() + // Refresh background and path + setBackgroundImage() + displayGameFolder() + enableButtons() } async function setGrasscutterFolder() { - const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { - filters: [ - { name: 'Jar files', extensions: ['jar'] } - ] - }) + const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { + filters: [ + { name: 'Jar files', extensions: ['jar'] } + ] + }) - if (!folder[0]) return; + if (!folder[0]) return - // Set the folder in our configuration - const config = await getCfg() + // Set the folder in our configuration + const config = await getCfg() - config.serverFolder = folder[0] - Neutralino.storage.setData('config', JSON.stringify(config)) + config.serverFolder = folder[0] + Neutralino.storage.setData('config', JSON.stringify(config)) - displayServerFolder() - enableServerButton() + displayServerFolder() + enableServerButton() } /** * Launch the game with no modifications nor proxy */ async function launchOfficial() { - const config = await getCfg() + const config = await getCfg() - Neutralino.os.execCommand(`"${config.gameexe}"`) + Neutralino.os.execCommand(`"${config.gameexe}"`) } /** * Launch the game with a proxy */ async function launchPrivate() { - const ip = document.getElementById('ip').value || '127.0.0.1' - const port = document.getElementById('port').value || '443' + const ip = document.getElementById('ip').value || '127.0.0.1' + const port = document.getElementById('port').value || '443' - const config = await getCfg() + const config = await getCfg() - console.log('connecting to ' + ip + ':' + port) + console.log('connecting to ' + ip + ':' + port) - // Set the last connect - config.lastConnect = ip - Neutralino.storage.setData('config', JSON.stringify(config)) + // Set the last connect + config.lastConnect = ip + Neutralino.storage.setData('config', JSON.stringify(config)) - // 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)) + // 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)) } async function launchLocalServer() { - const config = await getCfg() + const config = await getCfg() - 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)) } diff --git a/resources/js/login.js b/resources/js/login.js index 60188d7..87c0de9 100644 --- a/resources/js/login.js +++ b/resources/js/login.js @@ -2,153 +2,153 @@ * Toggle the login section */ async function setLoginSection() { - const title = document.getElementById('loginSectionTitle'); - const altTitle = document.getElementById('registerSectionTitle'); - const loginSection = document.getElementById('loginPopupContentBody'); - const registerSection = document.getElementById('registerPopupContentBody'); + const title = document.getElementById('loginSectionTitle') + const altTitle = document.getElementById('registerSectionTitle') + const loginSection = document.getElementById('loginPopupContentBody') + const registerSection = document.getElementById('registerPopupContentBody') - title.classList.add('selectedTitle') - altTitle.classList.remove('selectedTitle') + title.classList.add('selectedTitle') + altTitle.classList.remove('selectedTitle') - loginSection.style.removeProperty('display'); - registerSection.style.display = 'none'; + loginSection.style.removeProperty('display') + registerSection.style.display = 'none' } /** * Toggle the register section */ async function setRegisterSection(fromLogin = false) { - const title = document.getElementById('registerSectionTitle'); - const altTitle = document.getElementById('loginSectionTitle'); - const loginSection = document.getElementById('loginPopupContentBody'); - const registerSection = document.getElementById('registerPopupContentBody'); + const title = document.getElementById('registerSectionTitle') + const altTitle = document.getElementById('loginSectionTitle') + const loginSection = document.getElementById('loginPopupContentBody') + const registerSection = document.getElementById('registerPopupContentBody') - title.classList.add('selectedTitle') - altTitle.classList.remove('selectedTitle') + title.classList.add('selectedTitle') + altTitle.classList.remove('selectedTitle') - loginSection.style.display = 'none'; - registerSection.style.removeProperty('display'); + loginSection.style.display = 'none' + registerSection.style.removeProperty('display') - if (fromLogin) { + if (fromLogin) { // Take the values from the login section and put them in the register section - const loginUsername = document.getElementById('loginUsername').value; - const loginPassword = document.getElementById('loginPassword').value; + const loginUsername = document.getElementById('loginUsername').value + const loginPassword = document.getElementById('loginPassword').value - document.getElementById('registerUsername').value = loginUsername; - document.getElementById('registerPassword').value = loginPassword; - } + document.getElementById('registerUsername').value = loginUsername + document.getElementById('registerPassword').value = loginPassword + } } function parseJwt(token) { - const base64Url = token.split('.')[1]; - const base64 = base64Url.replace('-', '+').replace('_', '/'); - return JSON.parse(window.atob(base64)); + const base64Url = token.split('.')[1] + const base64 = base64Url.replace('-', '+').replace('_', '/') + return JSON.parse(window.atob(base64)) } /** * Attempt login and launch game */ async function login() { - const username = document.getElementById('loginUsername').value; - const password = document.getElementById('loginPassword').value; - const ip = document.getElementById('ip').value; - const port = document.getElementById('port').value || '443'; - const config = await getCfg(); - const useHttps = config.useHttps; - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`; + const username = document.getElementById('loginUsername').value + const password = document.getElementById('loginPassword').value + const ip = document.getElementById('ip').value + const port = document.getElementById('port').value || '443' + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - const reqBody = { - username, - password, - } + const reqBody = { + username, + password, + } - const { data } = await axios.post(url + '/authentication/login', reqBody) + const { data } = await axios.post(url + '/authentication/login', reqBody) - switch(data.message) { + switch(data.message) { case 'INVALID_ACCOUNT': - displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error'); - break; + displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error') + break case 'NO_PASSWORD': - // No account password, create one with change password - displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn'); - break; + // No account password, create one with change password + displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn') + break case 'UNKNOWN': - // Unknown error, contact server owner - displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error'); - break; + // Unknown error, contact server owner + displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') + break case undefined: case null: case 'AUTH_DISABLED': - // Authentication is disabled, we can just connect the user - displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn'); - launchPrivate(); - break; + // Authentication is disabled, we can just connect the user + displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn') + launchPrivate() + break default: - // Success! Copy the JWT token to their clipboard - const tkData = parseJwt(data.jwt) - await Neutralino.clipboard.writeText(tkData.token) + // Success! Copy the JWT token to their clipboard + const tkData = parseJwt(data.jwt) + await Neutralino.clipboard.writeText(tkData.token) - 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() - break; - } + 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() + break + } } /** * Attempt registration, do not launch game */ async function register() { - const username = document.getElementById('registerUsername').value; - const password = document.getElementById('registerPassword').value; - const password_confirmation = document.getElementById('registerPasswordConfirm').value; - const ip = document.getElementById('ip').value; - const port = document.getElementById('port').value || '443'; - const config = await getCfg(); - const useHttps = config.useHttps; - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`; + const username = document.getElementById('registerUsername').value + const password = document.getElementById('registerPassword').value + const password_confirmation = document.getElementById('registerPasswordConfirm').value + const ip = document.getElementById('ip').value + const port = document.getElementById('port').value || '443' + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - const reqBody = { - username, - password, - password_confirmation - } + const reqBody = { + username, + password, + password_confirmation + } - const { data } = await axios.post(url + '/authentication/register', reqBody) + const { data } = await axios.post(url + '/authentication/register', reqBody) - switch(data.message) { + switch(data.message) { case 'USERNAME_TAKEN': - // Username is taken - displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error'); - break; + // Username is taken + displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error') + break case 'PASSWORD_MISMATCH': - // The password and password confirmation do not match - displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error'); - break; + // The password and password confirmation do not match + displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error') + break case 'UNKNOWN': - // Unknown error, contact server owner - displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error'); - break; + // Unknown error, contact server owner + displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') + break case undefined: case null: case 'AUTH_DISABLED': - // Authentication is disabled, we can just connect the user - displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn'); - break; + // Authentication is disabled, we can just connect the user + displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn') + break default: - // Success!! Bring them to the login screen and auto-input their username - const loginUsername = document.getElementById('loginUsername'); - loginUsername.value = username; + // Success!! Bring them to the login screen and auto-input their username + const loginUsername = document.getElementById('loginUsername') + loginUsername.value = username - setLoginSection(); - displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000); - break; - } + setLoginSection() + displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000) + break + } } diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index bc96832..e1942c8 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -3,87 +3,87 @@ * Every autofill, such as backgrounds and the game folder, * should be done here to ensure DOM contents are loaded. */ - document.addEventListener('DOMContentLoaded', async () => { - displayUpdate(); - setBackgroundImage(); - displayGameFolder(); - displayServerFolder(); +document.addEventListener('DOMContentLoaded', async () => { + displayUpdate() + setBackgroundImage() + displayGameFolder() + displayServerFolder() - // Set title version - document.querySelector('#version').innerHTML = NL_APPVERSION + // Set title version + document.querySelector('#version').innerHTML = NL_APPVERSION - const config = await getCfg() - const ipArr = await getFavIps() + const config = await getCfg() + const ipArr = await getFavIps() - if (config.serverLaunchPanel) { - displayServerLaunchSection() - } - - // Set last connect - document.querySelector('#ip').value = config.lastConnect - - if (ipArr.includes(config.lastConnect)) { - document.querySelector('#star').src = 'icons/star_filled.svg' - } - - // Disable private game launch if proxy IP or proxy server is not found - const playPriv = document.querySelector('#playPrivate') - - if (!(await proxyIsInstalled())) { - playPriv.classList.add('disabled') - playPriv.disabled = true - } - - // Exit favorites list and settings panel when clicking outside of it - window.addEventListener("click", function(e) { - const favList = document.querySelector('#ipList') - const settingsPanel = document.querySelector('#settingsPanel') - const downloadPanel = document.querySelector('#downloadPanel') - - // This will close the favorites list no matter what is clicked - if (favList.style.display !== 'none') { - favList.style.display = 'none' - favList.style.transform = '' + if (config.serverLaunchPanel) { + displayServerLaunchSection() } - // This will close the settings panel no matter what is clicked - let checkElm = e.target + // Set last connect + document.querySelector('#ip').value = config.lastConnect - while(checkElm.tagName !== 'BODY') { - if (checkElm.id === 'settingsPanel' + if (ipArr.includes(config.lastConnect)) { + document.querySelector('#star').src = 'icons/star_filled.svg' + } + + // Disable private game launch if proxy IP or proxy server is not found + const playPriv = document.querySelector('#playPrivate') + + if (!(await proxyIsInstalled())) { + playPriv.classList.add('disabled') + playPriv.disabled = true + } + + // Exit favorites list and settings panel when clicking outside of it + window.addEventListener('click', function(e) { + const favList = document.querySelector('#ipList') + const settingsPanel = document.querySelector('#settingsPanel') + const downloadPanel = document.querySelector('#downloadPanel') + + // This will close the favorites list no matter what is clicked + if (favList.style.display !== 'none') { + favList.style.display = 'none' + favList.style.transform = '' + } + + // This will close the settings panel no matter what is clicked + let checkElm = e.target + + while(checkElm.tagName !== 'BODY') { + if (checkElm.id === 'settingsPanel' || checkElm.id === 'settingsBtn') { - return - } + return + } - if (checkElm.id === 'downloadPanel' || + if (checkElm.id === 'downloadPanel' || checkElm.id === 'downloadBtn') { - return - } + return + } - checkElm = checkElm.parentElement - } + checkElm = checkElm.parentElement + } - // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel - if (checkElm.tagName === 'BODY') { - // This will close the settings panel only when something outside of it is clicked - if (settingsPanel.style.display !== 'none') { - settingsPanel.style.display = 'none' - } + // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel + if (checkElm.tagName === 'BODY') { + // This will close the settings panel only when something outside of it is clicked + if (settingsPanel.style.display !== 'none') { + settingsPanel.style.display = 'none' + } - if (downloadPanel.style.display !== 'none') { - downloadPanel.style.display = 'none' - } - } - }); + if (downloadPanel.style.display !== 'none') { + downloadPanel.style.display = 'none' + } + } + }) - // Ensure we do the translation at the very end, after everything else has loaded - await doTranslation() + // Ensure we do the translation at the very end, after everything else has loaded + await doTranslation() - if (!config.gameexe) { - handleGameNotSet() - } + if (!config.gameexe) { + handleGameNotSet() + } - if (!config.serverFolder) { - handleServerNotSet() - } + if (!config.serverFolder) { + handleServerNotSet() + } }) diff --git a/resources/js/options.js b/resources/js/options.js index 58da7f6..a42f899 100644 --- a/resources/js/options.js +++ b/resources/js/options.js @@ -2,54 +2,54 @@ * Toggle the killswitch script */ async function toggleKillSwitch() { - const killSwitch = document.querySelector('#killswitchOption') - const config = await getCfg() + const killSwitch = document.querySelector('#killswitchOption') + const config = await getCfg() - config.enableKillswitch = killSwitch.checked + config.enableKillswitch = killSwitch.checked - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) } /** * Toggles the server launching panel */ async function toggleServerLaunchSection() { - const config = await getCfg() + const config = await getCfg() - displayServerLaunchSection() + displayServerLaunchSection() - // Save setting - config.serverLaunchPanel = !config.serverLaunchPanel - Neutralino.storage.setData('config', JSON.stringify(config)) + // Save setting + config.serverLaunchPanel = !config.serverLaunchPanel + Neutralino.storage.setData('config', JSON.stringify(config)) } /** * Get all languages for the language selector */ async function getLanguages() { - const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) - const config = await getCfg() + const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) + const config = await getCfg() - // Clear language options - const languageSelect = document.querySelector('#languageSelect') - languageSelect.innerHTML = '' + // Clear language options + const languageSelect = document.querySelector('#languageSelect') + languageSelect.innerHTML = '' - // Load all languages as options - for (const file of languageFiles) { - const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName - const lang = file.entry.split('.json')[0] + // Load all languages as options + for (const file of languageFiles) { + const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName + const lang = file.entry.split('.json')[0] - const option = document.createElement('option') - option.value = lang - option.innerHTML = fullLanguageName + const option = document.createElement('option') + option.value = lang + option.innerHTML = fullLanguageName - // Set language selected to config language - if (lang === config.language) { - option.selected = true - } + // Set language selected to config language + if (lang === config.language) { + option.selected = true + } - document.querySelector('#languageSelect').appendChild(option) - } + document.querySelector('#languageSelect').appendChild(option) + } } /** @@ -58,27 +58,27 @@ async function getLanguages() { * @param {DOMElement} elm */ async function handleLanguageChange(elm) { - const list = elm - const config = await getCfg() + const list = elm + const config = await getCfg() - // Set language in config - config.language = list.value - Neutralino.storage.setData('config', JSON.stringify(config)) + // Set language in config + config.language = list.value + Neutralino.storage.setData('config', JSON.stringify(config)) - // Force refresh of application, no need for restart! - window.location.reload() + // Force refresh of application, no need for restart! + window.location.reload() } /** * Toggle the use of HTTPS */ - async function toggleHttps() { - const httpsCheckbox = document.querySelector('#httpsOption') - const config = await getCfg() +async function toggleHttps() { + const httpsCheckbox = document.querySelector('#httpsOption') + const config = await getCfg() - config.useHttps = httpsCheckbox.checked + config.useHttps = httpsCheckbox.checked - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) } /** @@ -86,29 +86,29 @@ async function handleLanguageChange(elm) { * OR * Remove the current value of the IP input from the favorites list */ - async function setFavorite() { - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value || '443' - const ipArr = await getFavIps() +async function setFavorite() { + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value || '443' + const ipArr = await getFavIps() - const addr = `${ip}:${port}` + const addr = `${ip}:${port}` - // Set star icon - const star = document.querySelector('#star') + // Set star icon + const star = document.querySelector('#star') - if (star.src.includes('filled') && ip) { - star.src = 'icons/star_empty.svg' + if (star.src.includes('filled') && ip) { + star.src = 'icons/star_empty.svg' - // remove from list - ipArr.splice(ipArr.indexOf(addr), 1) - } else { - star.src = 'icons/star_filled.svg' + // remove from list + ipArr.splice(ipArr.indexOf(addr), 1) + } else { + star.src = 'icons/star_filled.svg' - // add to list - if (ip && !ipArr.includes(addr)) { - ipArr.push(addr) + // add to list + if (ip && !ipArr.includes(addr)) { + ipArr.push(addr) + } } - } - Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) + Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) } diff --git a/resources/js/translation.js b/resources/js/translation.js index dd80b83..47f0eb0 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -1,110 +1,110 @@ async function doTranslation() { - const config = await getCfg() + const config = await getCfg() - // See if the localization file exists - const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`) + // See if the localization file exists + const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`) - // Use english if the selected file does not exist - const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`) + // Use english if the selected file does not exist + const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`) - // Use english if the selected file does not exist - if (!selectedLanguage) { - config.language = 'en' - } + // Use english if the selected file does not exist + if (!selectedLanguage) { + config.language = 'en' + } - const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) - const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) - engLocaleObj = JSON.parse(engLocale) - localeObj = JSON.parse(localization) + const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) + const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) + engLocaleObj = JSON.parse(engLocale) + localeObj = JSON.parse(localization) - const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString] + const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString] - // Begin filling in values - set('titleSection', 'appName') + // Begin filling in values + set('titleSection', 'appName') - const verSpan = document.createElement('span') - verSpan.id = 'version' - verSpan.innerHTML = ` v${NL_APPVERSION}` + const verSpan = document.createElement('span') + verSpan.id = 'version' + verSpan.innerHTML = ` v${NL_APPVERSION}` - document.querySelector('#titleSection').appendChild(verSpan) + document.querySelector('#titleSection').appendChild(verSpan) - // Play buttons - set('playOfficial', 'playOfficial') - set('playPrivate', 'playPrivate') - set('serverLaunch', 'launchLocalServer') + // Play buttons + set('playOfficial', 'playOfficial') + set('playPrivate', 'playPrivate') + set('serverLaunch', 'launchLocalServer') - // File select buttons - set('gameExeSet', 'gameExeSet') - set('grasscutterFileSet', 'grasscutterFileSet') + // File select buttons + set('gameExeSet', 'gameExeSet') + set('grasscutterFileSet', 'grasscutterFileSet') - // Private options - document.querySelector('#ip').placeholder = localeObj.ipPlaceholder - document.querySelector('#port').placeholder = localeObj.portPlaceholder + // Private options + document.querySelector('#ip').placeholder = localeObj.ipPlaceholder + document.querySelector('#port').placeholder = localeObj.portPlaceholder - // Settings - set('fullSettingsTitle', 'settingsTitle') - set('scriptsTitle', 'scriptsSectionTitle') - set('killswitchTitle', 'killswitchOption') - set('killswitchSubtitle', 'killswitchSubtitle') - set('proxyTitle', 'proxyOption') - set('proxyInstall', 'proxyInstallBtn') - set('proxySubtitle', 'proxySubtitle') - set('updateBtn', 'updateOption') - set('updateTitle', 'updateOption') - set('updateSubtitle', 'updateSubtitle') - set('languageTitle', 'languageOption') - set('languageSubtitle', 'languageSubtitle') - set('serverLaunchTitle', 'enableServerLauncherOption') - set('serverSubtitle', 'enableServerLauncherSubtitle') - set('httpsTitle', 'httpsOption') - set('httpsSubtitle', 'httpsSubtitle') + // Settings + set('fullSettingsTitle', 'settingsTitle') + set('scriptsTitle', 'scriptsSectionTitle') + set('killswitchTitle', 'killswitchOption') + set('killswitchSubtitle', 'killswitchSubtitle') + set('proxyTitle', 'proxyOption') + set('proxyInstall', 'proxyInstallBtn') + set('proxySubtitle', 'proxySubtitle') + set('updateBtn', 'updateOption') + set('updateTitle', 'updateOption') + set('updateSubtitle', 'updateSubtitle') + set('languageTitle', 'languageOption') + set('languageSubtitle', 'languageSubtitle') + set('serverLaunchTitle', 'enableServerLauncherOption') + set('serverSubtitle', 'enableServerLauncherSubtitle') + set('httpsTitle', 'httpsOption') + set('httpsSubtitle', 'httpsSubtitle') - // Intro popup - const popup = document.getElementById('firstTimeNotice') - const introSpan = popup.querySelector('span') - const boldIntroSpan = document.createElement('span') + // Intro popup + const popup = document.getElementById('firstTimeNotice') + const introSpan = popup.querySelector('span') + const boldIntroSpan = document.createElement('span') - boldIntroSpan.innerHTML = localeObj.introSen1 + '\n' - boldIntroSpan.classList.add('boldTitle') + boldIntroSpan.innerHTML = localeObj.introSen1 + '\n' + boldIntroSpan.classList.add('boldTitle') - introSpan.appendChild(boldIntroSpan) + introSpan.appendChild(boldIntroSpan) - introSpan.innerHTML += localeObj.introSen2 + '
' - introSpan.innerHTML += localeObj.introSen3 + '
' - introSpan.innerHTML += localeObj.introSen4 + '
' + introSpan.innerHTML += localeObj.introSen2 + '
' + introSpan.innerHTML += localeObj.introSen3 + '
' + introSpan.innerHTML += localeObj.introSen4 + '
' - set('firstTimeInstallBtn', 'proxyInstallBtn') - set('firstTimeDenyBtn', 'proxyInstallDeny') + set('firstTimeInstallBtn', 'proxyInstallBtn') + set('firstTimeDenyBtn', 'proxyInstallDeny') - // Login section - set('loginSectionTitle', 'authLoginTitle') - set('registerSectionTitle', 'authRegisterTitle') - set('loggingInToIndicator', 'loggingInTo') - set('registeringToIndicator', 'registeringFor') - set('loginUsernameIndicator', 'authUsername') - set('loginPasswordIndicator', 'authPassword') - set('registerUsernameIndicator', 'authUsername') - set('registerPasswordIndicator', 'authPassword') - set('registerConfirmIndicator', 'authConfirmPassword') - set('loginPopupContentBodyBtnLogin', 'authLoginBtn') - set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') - set('noLoginBtn', 'launchWithoutAuth') + // Login section + set('loginSectionTitle', 'authLoginTitle') + set('registerSectionTitle', 'authRegisterTitle') + set('loggingInToIndicator', 'loggingInTo') + set('registeringToIndicator', 'registeringFor') + set('loginUsernameIndicator', 'authUsername') + set('loginPasswordIndicator', 'authPassword') + set('registerUsernameIndicator', 'authUsername') + set('registerPasswordIndicator', 'authPassword') + set('registerConfirmIndicator', 'authConfirmPassword') + set('loginPopupContentBodyBtnLogin', 'authLoginBtn') + set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') + set('noLoginBtn', 'launchWithoutAuth') - // Downloads section - set('downloadTitle', 'downloadTitle') - set('grassclipperTitle', 'grassclipperTitle') - set('grasscutterTitle', 'grasscutterTitle') - set('installerTitle', 'installerTitle') - set('installerSubtitle', 'installerSubtitle') - set('downloadStable', 'downloadStable') - set('stableSubtitle', 'stableSubtitle') - set('downloadDev', 'downloadDev') - set('devSubtitle', 'downloadSubtitle') - set('downloadResources', 'downloadResources') - set('devSubtitle', 'devSubtitle') - set('stableInstall', 'stableInstall') - set('devInstall', 'devInstall') + // Downloads section + set('downloadTitle', 'downloadTitle') + set('grassclipperTitle', 'grassclipperTitle') + set('grasscutterTitle', 'grasscutterTitle') + set('installerTitle', 'installerTitle') + set('installerSubtitle', 'installerSubtitle') + set('downloadStable', 'downloadStable') + set('stableSubtitle', 'stableSubtitle') + set('downloadDev', 'downloadDev') + set('devSubtitle', 'downloadSubtitle') + set('downloadResources', 'downloadResources') + set('devSubtitle', 'devSubtitle') + set('stableInstall', 'stableInstall') + set('devInstall', 'devInstall') - // update notification - set('updateNotifText', 'updateNotifText') + // update notification + set('updateNotifText', 'updateNotifText') } \ No newline at end of file diff --git a/resources/js/windowDrag.js b/resources/js/windowDrag.js index b9aa3f5..e8d8704 100644 --- a/resources/js/windowDrag.js +++ b/resources/js/windowDrag.js @@ -1,25 +1,25 @@ // https://stackoverflow.com/questions/67971689/positioning-the-borderless-window-in-neutralino-js // had to use this since the in-built function breaks the close and minimize buttons -let dragging = false, ratio = 1, posX, posY; -let draggable; +let dragging = false, ratio = 1, posX, posY +let draggable document.addEventListener('DOMContentLoaded', async () => { - draggable = document.getElementById('controlBar'); + draggable = document.getElementById('controlBar') - // Listen to hovers - draggable.onmousedown = function (e) { - ratio = window.devicePixelRatio + // Listen to hovers + draggable.onmousedown = function (e) { + ratio = window.devicePixelRatio - posX = e.pageX * ratio, posY = e.pageY * ratio; - dragging = true; - } + posX = e.pageX * ratio, posY = e.pageY * ratio + dragging = true + } - // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere - window.onmouseup = function (e) { - dragging = false; - } + // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere + window.onmouseup = function (e) { + dragging = false + } - document.onmousemove = function (e) { - if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY); - } + document.onmousemove = function (e) { + if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY) + } }) \ No newline at end of file From 4141d349f48937fe242f493e75482d616653d24a Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 22:48:03 -0700 Subject: [PATCH 201/248] more auto eslint fixes --- .eslintrc.json | 10 +- resources/js/authAlert.js | 54 ++-- resources/js/gcdownloader.js | 132 ++++----- resources/js/helpers.js | 112 +++---- resources/js/hoverEvt.js | 56 ++-- resources/js/index.js | 552 +++++++++++++++++------------------ resources/js/login.js | 210 ++++++------- resources/js/onLoad.js | 126 ++++---- resources/js/options.js | 110 +++---- resources/js/translation.js | 176 +++++------ resources/js/windowDrag.js | 28 +- 11 files changed, 783 insertions(+), 783 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 064214d..c1cd848 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,13 +9,13 @@ "ecmaVersion": 13 }, "rules": { + "no-undef": 0, + "no-unused-vars": 0, + "no-case-declarations": 0, + "indent": [ "error", - 4 - ], - "linebreak-style": [ - "error", - "unix" + 2 ], "quotes": [ "error", diff --git a/resources/js/authAlert.js b/resources/js/authAlert.js index 9580530..8af7959 100644 --- a/resources/js/authAlert.js +++ b/resources/js/authAlert.js @@ -1,45 +1,45 @@ let alertTimeout, alertCooldown = 3000 async function displayLoginAlert(message, type, cooldown = null) { - displayAlert(message, type, cooldown, 'login') + displayAlert(message, type, cooldown, 'login') } async function displayRegisterAlert(message, type, cooldown = null) { - displayAlert(message, type, cooldown, 'register') + displayAlert(message, type, cooldown, 'register') } function displayAlert(message, type, cooldown, name) { - const elm = document.getElementById(`${name}Alert`) - const text = document.getElementById(`${name}AlertText`) + const elm = document.getElementById(`${name}Alert`) + const text = document.getElementById(`${name}AlertText`) - elm.style.removeProperty('display') + elm.style.removeProperty('display') - // Remove classification classes - elm.classList.remove('error') - elm.classList.remove('success') - elm.classList.remove('warn') + // Remove classification classes + elm.classList.remove('error') + elm.classList.remove('success') + elm.classList.remove('warn') - switch(type) { - case 'error': - elm.classList.add('error') - break + switch(type) { + case 'error': + elm.classList.add('error') + break - case 'success': - elm.classList.add('success') - break + case 'success': + elm.classList.add('success') + break - case 'warn': - default: - elm.classList.add('warn') - break - } + case 'warn': + default: + elm.classList.add('warn') + break + } - text.innerText = message + text.innerText = message - clearTimeout(alertTimeout) + clearTimeout(alertTimeout) - // Disappear after cooldown - alertTimeout = setTimeout(() => { - elm.style.display = 'none' - }, cooldown || alertCooldown) + // Disappear after cooldown + alertTimeout = setTimeout(() => { + elm.style.display = 'none' + }, cooldown || alertCooldown) } \ No newline at end of file diff --git a/resources/js/gcdownloader.js b/resources/js/gcdownloader.js index bcc6e7a..e461cfd 100644 --- a/resources/js/gcdownloader.js +++ b/resources/js/gcdownloader.js @@ -1,102 +1,102 @@ async function clearGCInstallation() { - Neutralino.os.execCommand('del /s /q "./gc"') + Neutralino.os.execCommand('del /s /q "./gc"') } async function setDownloadButtonsToLoading() { - const stableBtn = document.querySelector('#stableInstall') - const devBtn = document.querySelector('#devInstall') + const stableBtn = document.querySelector('#stableInstall') + 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 - stableBtn.disabled = true - stableBtn.classList.add('disabled') + // Set btns to disabled + stableBtn.disabled = true + stableBtn.classList.add('disabled') - devBtn.disabled = true - devBtn.classList.add('disabled') + devBtn.disabled = true + devBtn.classList.add('disabled') } async function resetDownloadButtons() { - const stableBtn = document.querySelector('#stableInstall') - const devBtn = document.querySelector('#devInstall') + const stableBtn = document.querySelector('#stableInstall') + const devBtn = document.querySelector('#devInstall') - stableBtn.innerText = localeObj.stableInstall || 'Download' - devBtn.innerText = localeObj.devInstall || 'Download' + stableBtn.innerText = localeObj.stableInstall || 'Download' + devBtn.innerText = localeObj.devInstall || 'Download' - // Set btns to enabled - stableBtn.disabled = false - stableBtn.classList.remove('disabled') + // Set btns to enabled + stableBtn.disabled = false + stableBtn.classList.remove('disabled') - devBtn.disabled = false - devBtn.classList.remove('disabled') + devBtn.disabled = false + devBtn.classList.remove('disabled') } async function downloadGC(branch) { - const config = await getCfg() + const config = await getCfg() - // If we are pulling from a new branch, delete the old installation - if (config.grasscutterBranch !== branch) await clearGCInstallation() + // If we are pulling from a new branch, delete the old installation + if (config.grasscutterBranch !== branch) await clearGCInstallation() - // Set current installation in config - config.grasscutterBranch = branch + // Set current installation in config + config.grasscutterBranch = branch - // Set gc path for people with launcher enabled - config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` + // Set gc path for people with launcher enabled + config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` - // Enable server launcher - config.serverLaunchPanel = true + // Enable server launcher + config.serverLaunchPanel = true - Neutralino.storage.setData('config', JSON.stringify(config)) + 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` + // 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` + // External service that allows un-authed artifact downloading + const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip` - // For data files - const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) - const dataList = dataFiles.data - .map(file => ({ path: file.path, filename: file.name })) - .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + // For data files + const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) + const dataList = dataFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) - // For key files - const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) - const keyList = keyFiles.data - .map(file => ({ path: file.path, filename: file.name })) - .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) + // For key files + const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) + const keyList = keyFiles.data + .map(file => ({ path: file.path, filename: file.name })) + .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) - const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') + const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') - // Ensure data and key folders exist + // Ensure data and key folders exist - await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) - await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) + await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) - // Download data files - for (const o of dataList) { - const folder = 'data' - await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) - } + // Download data files + for (const o of dataList) { + const folder = 'data' + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } - // Download key files - for (const o of keyList) { - const folder = 'keys' - await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) - } + // Download key files + for (const o of keyList) { + const folder = 'keys' + await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) + } - // Run installer - createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) + // Run installer + createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) - // Fix buttons - resetDownloadButtons() + // Fix buttons + resetDownloadButtons() - // Display folder after saving config - displayServerFolder() - enableServerButton() - displayServerLaunchSection() + // Display folder after saving config + displayServerFolder() + enableServerButton() + displayServerLaunchSection() } \ No newline at end of file diff --git a/resources/js/helpers.js b/resources/js/helpers.js index a4f514d..8fe28c2 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -4,27 +4,27 @@ * @returns {Promise} */ async function getCfg() { - const defaultConf = { - gameexe: '', - serverFolder: '', - lastConnect: '', - enableKillswitch: false, - serverLaunchPanel: false, - language: 'en', - useHttps: true, - grasscutterBranch: '', - } - const cfgStr = await Neutralino.storage.getData('config').catch(e => { + const defaultConf = { + gameexe: '', + serverFolder: '', + lastConnect: '', + enableKillswitch: false, + serverLaunchPanel: false, + language: 'en', + useHttps: true, + grasscutterBranch: '', + } + const cfgStr = await Neutralino.storage.getData('config').catch(e => { // The data isn't set, so this is our first time opening - Neutralino.storage.setData('config', JSON.stringify(defaultConf)) + Neutralino.storage.setData('config', JSON.stringify(defaultConf)) - // Show the first time notice if there is no config - document.querySelector('#firstTimeNotice').style.display = 'block' - }) + // Show the first time notice if there is no config + document.querySelector('#firstTimeNotice').style.display = 'block' + }) - const config = cfgStr ? JSON.parse(cfgStr) : defaultConf + const config = cfgStr ? JSON.parse(cfgStr) : defaultConf - return config + return config } /** @@ -33,90 +33,90 @@ async function getCfg() { * @returns {Promise} */ 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 - Neutralino.storage.setData('favorites', JSON.stringify([])) - }) + Neutralino.storage.setData('favorites', JSON.stringify([])) + }) - const ipArr = ipStr ? JSON.parse(ipStr) : [] + const ipArr = ipStr ? JSON.parse(ipStr) : [] - return ipArr + return ipArr } async function proxyIsInstalled() { - // Check if the proxy server is installed - const curDirList = await filesystem.readDirectory(NL_CWD) + // Check if the proxy server is installed + const curDirList = await filesystem.readDirectory(NL_CWD) - if (curDirList.find(f => f.entry === 'ext')) { - const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') + if (curDirList.find(f => f.entry === 'ext')) { + const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') - if (extFiles.find(f => f.entry === 'mitmdump.exe')) { - return true - } + if (extFiles.find(f => f.entry === 'mitmdump.exe')) { + return true } + } - return false + return false } 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 latest = data.tag_name + const { data } = await axios.get(url) + const latest = data.tag_name - return latest + return latest } async function displayUpdate() { - const latest = await checkForUpdates() - const versionDisplay = document.querySelector('#newestVersion') - const notif = document.querySelector('#downloadNotif') + const latest = await checkForUpdates() + const versionDisplay = document.querySelector('#newestVersion') + const notif = document.querySelector('#downloadNotif') - if (latest === `v${NL_APPVERSION}`) return + if (latest === `v${NL_APPVERSION}`) return - versionDisplay.innerText = latest + versionDisplay.innerText = latest - notif.classList.add('displayed') + notif.classList.add('displayed') - setTimeout(() => { - notif.classList.remove('displayed') - }, 5000) + setTimeout(() => { + notif.classList.remove('displayed') + }, 5000) } async function openLatestDownload() { - const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' + const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' - Neutralino.os.open(downloadLink) + Neutralino.os.open(downloadLink) } async function openGameFolder() { - const config = await getCfg() - const folder = config.gameexe.match(/.*\\/g, '')[0] + const config = await getCfg() + const folder = config.gameexe.match(/.*\\/g, '')[0] - openInExplorer(folder) + openInExplorer(folder) } async function openGrasscutterFolder() { - const config = await getCfg() - const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] + const config = await getCfg() + const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] - openInExplorer(folder) + openInExplorer(folder) } /** * Minimize the window */ function minimizeWin() { - console.log('min') - Neutralino.window.minimize() + console.log('min') + Neutralino.window.minimize() } /** * Close the window */ function closeWin() { - console.log('close') - Neutralino.app.exit() + console.log('close') + Neutralino.app.exit() - window.close() + window.close() } diff --git a/resources/js/hoverEvt.js b/resources/js/hoverEvt.js index af98ea0..47adb2c 100644 --- a/resources/js/hoverEvt.js +++ b/resources/js/hoverEvt.js @@ -1,36 +1,36 @@ document.addEventListener('DOMContentLoaded', async () => { - const firstPanel = document.querySelector('#firstPanel') - const secondPanel = document.querySelector('#secondPanel') - const thirdPanel = document.querySelector('#thirdPanel') + const firstPanel = document.querySelector('#firstPanel') + const secondPanel = document.querySelector('#secondPanel') + const thirdPanel = document.querySelector('#thirdPanel') - // Listen to hovers - firstPanel.addEventListener('mouseover', () => { - secondPanel.classList.add('darken') - thirdPanel.classList.add('darken') - }) + // Listen to hovers + firstPanel.addEventListener('mouseover', () => { + secondPanel.classList.add('darken') + thirdPanel.classList.add('darken') + }) - firstPanel.addEventListener('mouseout', () => { - secondPanel.classList.remove('darken') - thirdPanel.classList.remove('darken') - }) + firstPanel.addEventListener('mouseout', () => { + secondPanel.classList.remove('darken') + thirdPanel.classList.remove('darken') + }) - secondPanel.addEventListener('mouseover', () => { - firstPanel.classList.add('darken') - thirdPanel.classList.add('darken') - }) + secondPanel.addEventListener('mouseover', () => { + firstPanel.classList.add('darken') + thirdPanel.classList.add('darken') + }) - secondPanel.addEventListener('mouseout', () => { - firstPanel.classList.remove('darken') - thirdPanel.classList.remove('darken') - }) + secondPanel.addEventListener('mouseout', () => { + firstPanel.classList.remove('darken') + thirdPanel.classList.remove('darken') + }) - thirdPanel.addEventListener('mouseover', () => { - firstPanel.classList.add('darken') - secondPanel.classList.add('darken') - }) + thirdPanel.addEventListener('mouseover', () => { + firstPanel.classList.add('darken') + secondPanel.classList.add('darken') + }) - thirdPanel.addEventListener('mouseout', () => { - firstPanel.classList.remove('darken') - secondPanel.classList.remove('darken') - }) + thirdPanel.addEventListener('mouseout', () => { + firstPanel.classList.remove('darken') + secondPanel.classList.remove('darken') + }) }) \ No newline at end of file diff --git a/resources/js/index.js b/resources/js/index.js index 822fb67..15523cc 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -3,185 +3,185 @@ Neutralino.init() let localeObj const filesystem = Neutralino.filesystem const createCmdWindow = async (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) => { - console.log(`explorer.exe "${path}"`) - createCmdWindow(`explorer.exe "${path}"`) + console.log(`explorer.exe "${path}"`) + createCmdWindow(`explorer.exe "${path}"`) } /** * Enable play buttons */ async function enableButtons() { - const offBtn = document.querySelector('#playOfficial') - const privBtn = document.querySelector('#playPrivate') + const offBtn = document.querySelector('#playOfficial') + const privBtn = document.querySelector('#playPrivate') - offBtn.classList.remove('disabled') - offBtn.disabled = false + offBtn.classList.remove('disabled') + offBtn.disabled = false - // Check if the proxy server is installed - if (await proxyIsInstalled()) { - privBtn.classList.remove('disabled') - privBtn.disabled = false - } + // Check if the proxy server is installed + if (await proxyIsInstalled()) { + privBtn.classList.remove('disabled') + privBtn.disabled = false + } } /** * Enable server launch button */ async function enableServerButton() { - const serverBtn = document.querySelector('#serverLaunch') + const serverBtn = document.querySelector('#serverLaunch') - serverBtn.classList.remove('disabled') - serverBtn.disabled = false + serverBtn.classList.remove('disabled') + serverBtn.disabled = false } /** * Disable buttons when the game folder is not set */ async function handleGameNotSet() { - // Set buttons to greyed out and disable - document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet + // Set buttons to greyed out and disable + document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet - // Set official server background to default - document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")' + // Set official server background to default + document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")' - const offBtn = document.querySelector('#playOfficial') - const privBtn = document.querySelector('#playPrivate') + const offBtn = document.querySelector('#playOfficial') + const privBtn = document.querySelector('#playPrivate') - offBtn.classList.add('disabled') - offBtn.disabled = true + offBtn.classList.add('disabled') + offBtn.disabled = true - privBtn.classList.add('disabled') - privBtn.disabled = true + privBtn.classList.add('disabled') + privBtn.disabled = true - // TODO show a dialog of sorts + // TODO show a dialog of sorts } async function handleServerNotSet() { - // Set buttons to greyed out and disable - document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet + // Set buttons to greyed out and disable + document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet - // Set official server background to default - // document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` + // Set official server background to default + // document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` - const privBtn = document.querySelector('#serverLaunch') + const privBtn = document.querySelector('#serverLaunch') - privBtn.classList.add('disabled') - privBtn.disabled = true + privBtn.classList.add('disabled') + privBtn.disabled = true } /** * Show the game folder under the select button */ async function displayGameFolder() { - const elm = document.querySelector('#gamePath') - const config = await getCfg() + const elm = document.querySelector('#gamePath') + const config = await getCfg() - elm.innerHTML = config.gameexe + elm.innerHTML = config.gameexe } /** * Show the server folder under the select button */ async function displayServerFolder() { - const elm = document.querySelector('#serverPath') - const config = await getCfg() + const elm = document.querySelector('#serverPath') + const config = await getCfg() - elm.innerHTML = config.serverFolder + elm.innerHTML = config.serverFolder } /** * Set the background images of both the private and public sections */ async function setBackgroundImage() { - const config = await getCfg() + const config = await getCfg() - const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) - const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry + const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) + const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry - const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) - const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry + const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) + const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry - // 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")' + // 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")' - // Set the private background image - document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")` + // Set the private background image + document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")` - // Set the server background image - document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")` + // Set the server background image + document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")` - return + return - // Check if resources folder exists - const mainDir = await filesystem.readDirectory(NL_CWD) - if (!mainDir.find(dir => dir.entry === 'resources')) { - await filesystem.createDirectory(NL_CWD + '/resources') - } + // Check if resources folder exists + const mainDir = await filesystem.readDirectory(NL_CWD) + if (!mainDir.find(dir => dir.entry === 'resources')) { + await filesystem.createDirectory(NL_CWD + '/resources') + } - // Ensure bg folder exists - const bgDir = await filesystem.readDirectory(NL_CWD + '/resources') - if (!bgDir.find(dir => dir.entry === 'bg')) { - await filesystem.createDirectory(NL_CWD + '/resources/bg') - } + // Ensure bg folder exists + const bgDir = await filesystem.readDirectory(NL_CWD + '/resources') + if (!bgDir.find(dir => dir.entry === 'bg')) { + await filesystem.createDirectory(NL_CWD + '/resources/bg') + } - // Ensure official folder exists - const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg') - if (!officialDir.find(dir => dir.entry === 'official')) { - await filesystem.createDirectory(NL_CWD + '/resources/bg/official') - } + // Ensure official folder exists + const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg') + if (!officialDir.find(dir => dir.entry === 'official')) { + await filesystem.createDirectory(NL_CWD + '/resources/bg/official') + } - if (config.gameexe) { + if (config.gameexe) { // See if bg folder exists in parent dir - const parentDir = await filesystem.readDirectory(config.gameexe + '/..') + const parentDir = await filesystem.readDirectory(config.gameexe + '/..') - if (parentDir.find(dir => dir.entry === 'bg')) { + if (parentDir.find(dir => dir.entry === 'bg')) { - const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') + const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') - if (officialImages.length > 0) { - for (const bg of officialImages) { - const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry + if (officialImages.length > 0) { + for (const bg of officialImages) { + const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry - // See if the file exists already - const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') + // See if the file exists already + const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') - if (!currentBgs.find(file => file.entry === bg.entry)) { - await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => { - // TODO: Handle error - }) - } - } - - // Pick one of the images - const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE') - const image = localImg[Math.floor(Math.random() * localImg.length)].entry - - // Set background image - document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")` - } + if (!currentBgs.find(file => file.entry === bg.entry)) { + await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => { + // TODO: Handle error + }) + } } + + // Pick one of the images + const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE') + const image = localImg[Math.floor(Math.random() * localImg.length)].entry + + // Set background image + document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")` + } } + } } /** * When an IP is being input, check if it is part of the favorites */ async function handleFavoriteInput() { - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value || '443' - const ipArr = await getFavIps() + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value || '443' + const ipArr = await getFavIps() - const addr = `${ip}:${port}` + const addr = `${ip}:${port}` - if (!ip || !ipArr.includes(addr)) { - document.querySelector('#star').src = 'icons/star_empty.svg' - } else { - document.querySelector('#star').src = 'icons/star_filled.svg' - } + if (!ip || !ipArr.includes(addr)) { + document.querySelector('#star').src = 'icons/star_empty.svg' + } else { + document.querySelector('#star').src = 'icons/star_filled.svg' + } } /** @@ -190,182 +190,182 @@ async function handleFavoriteInput() { * @param {String} ip */ async function setIp(ip) { - const ipInput = document.querySelector('#ip') - const portInput = document.querySelector('#port') + const ipInput = document.querySelector('#ip') + const portInput = document.querySelector('#port') - const parseIp = ip.split(':')[0] - const parsePort = ip.split(':')[1] + const parseIp = ip.split(':')[0] + const parsePort = ip.split(':')[1] - // Set star - if (ip) { - document.querySelector('#star').src = 'icons/star_filled.svg' - } + // Set star + if (ip) { + document.querySelector('#star').src = 'icons/star_filled.svg' + } - ipInput.value = parseIp - portInput.value = parsePort + ipInput.value = parseIp + portInput.value = parsePort } /** * Create/hide the favorites list */ async function handleFavoriteList() { - const ipArr = await getFavIps() - const ipList = document.querySelector('#ipList') + const ipArr = await getFavIps() + const ipList = document.querySelector('#ipList') - if (ipList.style.display === 'none') { - ipList.innerHTML = '' + if (ipList.style.display === 'none') { + ipList.innerHTML = '' - const list = ipList.appendChild( - document.createElement('ul') - ) + const list = ipList.appendChild( + document.createElement('ul') + ) - if (ipArr.length < 1) { - const listItem = list.appendChild( - document.createElement('li') - ) + if (ipArr.length < 1) { + const listItem = list.appendChild( + document.createElement('li') + ) - listItem.innerHTML = localeObj.noFavorites - } - - for (const ip of ipArr) { - const elm = document.createElement('li') - elm.innerHTML = ip - elm.addEventListener('click', () => setIp(ip)) - list.appendChild(elm) - } - - ipList.style.display = 'block' - - const transform = window.getComputedStyle(document.querySelector('#ipList')).transform - const xy = [ transform.split(',')[4], transform.split(',')[5] ] - let newY = (27 * ipArr.length) * window.devicePixelRatio - - if (ipArr.length === 0 || ipArr.length === 1) newY = 0 - - ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)` + listItem.innerHTML = localeObj.noFavorites } + + for (const ip of ipArr) { + const elm = document.createElement('li') + elm.innerHTML = ip + elm.addEventListener('click', () => setIp(ip)) + list.appendChild(elm) + } + + ipList.style.display = 'block' + + const transform = window.getComputedStyle(document.querySelector('#ipList')).transform + const xy = [ transform.split(',')[4], transform.split(',')[5] ] + let newY = (27 * ipArr.length) * window.devicePixelRatio + + if (ipArr.length === 0 || ipArr.length === 1) newY = 0 + + ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)` + } } async function openDownloads() { - const downloads = document.querySelector('#downloadPanel') - const config = await getCfg() + const downloads = document.querySelector('#downloadPanel') + const config = await getCfg() - if (downloads.style.display === 'none') { - downloads.style.removeProperty('display') - } + if (downloads.style.display === 'none') { + downloads.style.removeProperty('display') + } - // Disable the resource download button if a serverFolder path is not set - if (!config.serverFolder) { - document.querySelector('#resourceInstall').disabled = true - document.querySelector('#resourceInstall').classList.add('disabled') - } else { - document.querySelector('#resourceInstall').disabled = false - document.querySelector('#resourceInstall').classList.remove('disabled') - } + // Disable the resource download button if a serverFolder path is not set + if (!config.serverFolder) { + document.querySelector('#resourceInstall').disabled = true + document.querySelector('#resourceInstall').classList.add('disabled') + } else { + document.querySelector('#resourceInstall').disabled = false + document.querySelector('#resourceInstall').classList.remove('disabled') + } } async function closeDownloads() { - const downloads = document.querySelector('#downloadPanel') + const downloads = document.querySelector('#downloadPanel') - downloads.style.display = 'none' + downloads.style.display = 'none' } async function openSettings() { - const settings = document.querySelector('#settingsPanel') - const config = await getCfg() + const settings = document.querySelector('#settingsPanel') + const config = await getCfg() - if (settings.style.display === 'none') { - settings.style.removeProperty('display') - } + if (settings.style.display === 'none') { + settings.style.removeProperty('display') + } - // Fill setting options with what is currently set in config - const killSwitch = document.querySelector('#killswitchOption') - const serverLaunch = document.querySelector('#serverLaunchOption') - const httpsCheckbox = document.querySelector('#httpsOption') + // Fill setting options with what is currently set in config + const killSwitch = document.querySelector('#killswitchOption') + const serverLaunch = document.querySelector('#serverLaunchOption') + const httpsCheckbox = document.querySelector('#httpsOption') - killSwitch.checked = config.enableKillswitch - serverLaunch.checked = config.serverLaunchPanel - httpsCheckbox.checked = config.useHttps + killSwitch.checked = config.enableKillswitch + serverLaunch.checked = config.serverLaunchPanel + httpsCheckbox.checked = config.useHttps - // Load languages - getLanguages() + // Load languages + getLanguages() - // Check for updates - //checkForUpdatesAndShow() + // Check for updates + //checkForUpdatesAndShow() } async function closeSettings() { - const settings = document.querySelector('#settingsPanel') - const config = await getCfg() + const settings = document.querySelector('#settingsPanel') + const config = await getCfg() - settings.style.display = 'none' + settings.style.display = 'none' - // In case we installed the proxy server - if (await proxyIsInstalled() && config.gameexe) { - const playPriv = document.querySelector('#playPrivate') + // In case we installed the proxy server + if (await proxyIsInstalled() && config.gameexe) { + const playPriv = document.querySelector('#playPrivate') - playPriv.classList.remove('disabled') - playPriv.disabled = false - } + playPriv.classList.remove('disabled') + playPriv.disabled = false + } } async function openLogin() { - const login = document.querySelector('#loginPanel') - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value - const loginIpDisplay = document.querySelector('#loginPopupServer') - const registerIpDisplay = document.querySelector('#registerPopupServer') + const login = document.querySelector('#loginPanel') + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value + const loginIpDisplay = document.querySelector('#loginPopupServer') + const registerIpDisplay = document.querySelector('#registerPopupServer') - const config = await getCfg() - const useHttps = config.useHttps - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - // Check if we even need to authenticate - try { - const { data } = await axios.get(url + '/authentication/type') + // Check if we even need to authenticate + try { + const { data } = await axios.get(url + '/authentication/type') - if (!data.includes('GCAuthAuthenticationHandler')) { - launchPrivate() - return - } - } catch(e) { - launchPrivate() - return + if (!data.includes('GCAuthAuthenticationHandler')) { + launchPrivate() + return } + } catch(e) { + launchPrivate() + return + } - loginIpDisplay.innerText = ip - registerIpDisplay.innerText = ip + loginIpDisplay.innerText = ip + registerIpDisplay.innerText = ip - if (login.style.display === 'none') { - login.style.removeProperty('display') - } + if (login.style.display === 'none') { + login.style.removeProperty('display') + } } async function closeLogin() { - const login = document.querySelector('#loginPanel') + const login = document.querySelector('#loginPanel') - login.style.display = 'none' + login.style.display = 'none' - setLoginSection() + setLoginSection() } async function closeFirstTimePopup() { - const firstTimePopup = document.querySelector('#firstTimeNotice') - firstTimePopup.style.display = 'none' + const firstTimePopup = document.querySelector('#firstTimeNotice') + firstTimePopup.style.display = 'none' } async function runInstallScript() { - 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 - const interval = setInterval(async () => { - if (await proxyIsInstalled()) { - clearInterval(interval) - enableButtons() - } - }, 1000) + // Create an interval that will check for the proxy server installation finish + const interval = setInterval(async () => { + if (await proxyIsInstalled()) { + clearInterval(interval) + enableButtons() + } + }, 1000) - closeFirstTimePopup() + closeFirstTimePopup() } async function updateResources() { @@ -373,109 +373,109 @@ async function updateResources() { } async function checkForUpdatesAndShow() { - const updateBtn = document.querySelector('#updateBtn') - const subtitle = document.querySelector('#updateSubtitle') - const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/' - const manifest = await Neutralino.updater.checkForUpdates(url) + const updateBtn = document.querySelector('#updateBtn') + const subtitle = document.querySelector('#updateSubtitle') + const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/' + const manifest = await Neutralino.updater.checkForUpdates(url) - // Version mismatch? Update! - if (manifest?.version !== NL_APPVERSION) { - subtitle.innerHTML = 'New update available!' - updateBtn.classList.remove('disabled') - } else { - subtitle.innerHTML = 'You are on the latest version! :)' - updateBtn.classList.add('disabled') - } + // Version mismatch? Update! + if (manifest?.version !== NL_APPVERSION) { + subtitle.innerHTML = 'New update available!' + updateBtn.classList.remove('disabled') + } else { + subtitle.innerHTML = 'You are on the latest version! :)' + updateBtn.classList.add('disabled') + } } async function displayServerLaunchSection() { - const serverPanel = document.querySelector('#thirdPanel') - const bottomBtnSection = document.querySelector('#serverPath').parentElement + const serverPanel = document.querySelector('#thirdPanel') + const bottomBtnSection = document.querySelector('#serverPath').parentElement - if (serverPanel.style.display === 'none') { - serverPanel.style.removeProperty('display') - bottomBtnSection.style.removeProperty('display') - } else { - serverPanel.style.display = 'none' - bottomBtnSection.style.display = 'none' - } + if (serverPanel.style.display === 'none') { + serverPanel.style.removeProperty('display') + bottomBtnSection.style.removeProperty('display') + } else { + serverPanel.style.display = 'none' + bottomBtnSection.style.display = 'none' + } } /** * Set the game folder by opening a folder picker */ async function setGameExe() { - const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { - filters: [ - { name: 'Executable files', extensions: ['exe'] } - ] - }) + const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { + filters: [ + { name: 'Executable files', extensions: ['exe'] } + ] + }) - if (!gameExe[0]) return + if (!gameExe[0]) return - // Set the folder in our configuration - const config = await getCfg() + // Set the folder in our configuration + const config = await getCfg() - // It's an array of selections, so only get the first one - config.gameexe = gameExe[0].replace(/\//g, '\\') + // It's an array of selections, so only get the first one + config.gameexe = gameExe[0].replace(/\//g, '\\') - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) - // Refresh background and path - setBackgroundImage() - displayGameFolder() - enableButtons() + // Refresh background and path + setBackgroundImage() + displayGameFolder() + enableButtons() } async function setGrasscutterFolder() { - const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { - filters: [ - { name: 'Jar files', extensions: ['jar'] } - ] - }) + const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { + filters: [ + { name: 'Jar files', extensions: ['jar'] } + ] + }) - if (!folder[0]) return + if (!folder[0]) return - // Set the folder in our configuration - const config = await getCfg() + // Set the folder in our configuration + const config = await getCfg() - config.serverFolder = folder[0] - Neutralino.storage.setData('config', JSON.stringify(config)) + config.serverFolder = folder[0] + Neutralino.storage.setData('config', JSON.stringify(config)) - displayServerFolder() - enableServerButton() + displayServerFolder() + enableServerButton() } /** * Launch the game with no modifications nor proxy */ async function launchOfficial() { - const config = await getCfg() + const config = await getCfg() - Neutralino.os.execCommand(`"${config.gameexe}"`) + Neutralino.os.execCommand(`"${config.gameexe}"`) } /** * Launch the game with a proxy */ async function launchPrivate() { - const ip = document.getElementById('ip').value || '127.0.0.1' - const port = document.getElementById('port').value || '443' + const ip = document.getElementById('ip').value || '127.0.0.1' + const port = document.getElementById('port').value || '443' - const config = await getCfg() + const config = await getCfg() - console.log('connecting to ' + ip + ':' + port) + console.log('connecting to ' + ip + ':' + port) - // Set the last connect - config.lastConnect = ip - Neutralino.storage.setData('config', JSON.stringify(config)) + // Set the last connect + config.lastConnect = ip + Neutralino.storage.setData('config', JSON.stringify(config)) - // 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)) + // 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)) } async function launchLocalServer() { - const config = await getCfg() + const config = await getCfg() - 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)) } diff --git a/resources/js/login.js b/resources/js/login.js index 87c0de9..0982456 100644 --- a/resources/js/login.js +++ b/resources/js/login.js @@ -2,153 +2,153 @@ * Toggle the login section */ async function setLoginSection() { - const title = document.getElementById('loginSectionTitle') - const altTitle = document.getElementById('registerSectionTitle') - const loginSection = document.getElementById('loginPopupContentBody') - const registerSection = document.getElementById('registerPopupContentBody') + const title = document.getElementById('loginSectionTitle') + const altTitle = document.getElementById('registerSectionTitle') + const loginSection = document.getElementById('loginPopupContentBody') + const registerSection = document.getElementById('registerPopupContentBody') - title.classList.add('selectedTitle') - altTitle.classList.remove('selectedTitle') + title.classList.add('selectedTitle') + altTitle.classList.remove('selectedTitle') - loginSection.style.removeProperty('display') - registerSection.style.display = 'none' + loginSection.style.removeProperty('display') + registerSection.style.display = 'none' } /** * Toggle the register section */ async function setRegisterSection(fromLogin = false) { - const title = document.getElementById('registerSectionTitle') - const altTitle = document.getElementById('loginSectionTitle') - const loginSection = document.getElementById('loginPopupContentBody') - const registerSection = document.getElementById('registerPopupContentBody') + const title = document.getElementById('registerSectionTitle') + const altTitle = document.getElementById('loginSectionTitle') + const loginSection = document.getElementById('loginPopupContentBody') + const registerSection = document.getElementById('registerPopupContentBody') - title.classList.add('selectedTitle') - altTitle.classList.remove('selectedTitle') + title.classList.add('selectedTitle') + altTitle.classList.remove('selectedTitle') - loginSection.style.display = 'none' - registerSection.style.removeProperty('display') + loginSection.style.display = 'none' + registerSection.style.removeProperty('display') - if (fromLogin) { + if (fromLogin) { // Take the values from the login section and put them in the register section - const loginUsername = document.getElementById('loginUsername').value - const loginPassword = document.getElementById('loginPassword').value + const loginUsername = document.getElementById('loginUsername').value + const loginPassword = document.getElementById('loginPassword').value - document.getElementById('registerUsername').value = loginUsername - document.getElementById('registerPassword').value = loginPassword - } + document.getElementById('registerUsername').value = loginUsername + document.getElementById('registerPassword').value = loginPassword + } } function parseJwt(token) { - const base64Url = token.split('.')[1] - const base64 = base64Url.replace('-', '+').replace('_', '/') - return JSON.parse(window.atob(base64)) + const base64Url = token.split('.')[1] + const base64 = base64Url.replace('-', '+').replace('_', '/') + return JSON.parse(window.atob(base64)) } /** * Attempt login and launch game */ async function login() { - const username = document.getElementById('loginUsername').value - const password = document.getElementById('loginPassword').value - const ip = document.getElementById('ip').value - const port = document.getElementById('port').value || '443' - const config = await getCfg() - const useHttps = config.useHttps - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` + const username = document.getElementById('loginUsername').value + const password = document.getElementById('loginPassword').value + const ip = document.getElementById('ip').value + const port = document.getElementById('port').value || '443' + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - const reqBody = { - username, - password, - } + const reqBody = { + username, + password, + } - const { data } = await axios.post(url + '/authentication/login', reqBody) + const { data } = await axios.post(url + '/authentication/login', reqBody) - switch(data.message) { - case 'INVALID_ACCOUNT': - displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error') - break + switch(data.message) { + case 'INVALID_ACCOUNT': + displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error') + break - case 'NO_PASSWORD': - // No account password, create one with change password - displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn') - break + case 'NO_PASSWORD': + // No account password, create one with change password + displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn') + break - case 'UNKNOWN': - // Unknown error, contact server owner - displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') - break + case 'UNKNOWN': + // Unknown error, contact server owner + displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') + break - case undefined: - case null: - case 'AUTH_DISABLED': - // Authentication is disabled, we can just connect the user - displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn') - launchPrivate() - break + case undefined: + case null: + case 'AUTH_DISABLED': + // Authentication is disabled, we can just connect the user + displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn') + launchPrivate() + break - default: - // Success! Copy the JWT token to their clipboard - const tkData = parseJwt(data.jwt) - await Neutralino.clipboard.writeText(tkData.token) + default: + // Success! Copy the JWT token to their clipboard + const tkData = parseJwt(data.jwt) + await Neutralino.clipboard.writeText(tkData.token) - 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() - break - } + 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() + break + } } /** * Attempt registration, do not launch game */ async function register() { - const username = document.getElementById('registerUsername').value - const password = document.getElementById('registerPassword').value - const password_confirmation = document.getElementById('registerPasswordConfirm').value - const ip = document.getElementById('ip').value - const port = document.getElementById('port').value || '443' - const config = await getCfg() - const useHttps = config.useHttps - const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` + const username = document.getElementById('registerUsername').value + const password = document.getElementById('registerPassword').value + const password_confirmation = document.getElementById('registerPasswordConfirm').value + const ip = document.getElementById('ip').value + const port = document.getElementById('port').value || '443' + const config = await getCfg() + const useHttps = config.useHttps + const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` - const reqBody = { - username, - password, - password_confirmation - } + const reqBody = { + username, + password, + password_confirmation + } - const { data } = await axios.post(url + '/authentication/register', reqBody) + const { data } = await axios.post(url + '/authentication/register', reqBody) - switch(data.message) { - case 'USERNAME_TAKEN': - // Username is taken - displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error') - break + switch(data.message) { + case 'USERNAME_TAKEN': + // Username is taken + displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error') + break - case 'PASSWORD_MISMATCH': - // The password and password confirmation do not match - displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error') - break + case 'PASSWORD_MISMATCH': + // The password and password confirmation do not match + displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error') + break - case 'UNKNOWN': - // Unknown error, contact server owner - displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') - break + case 'UNKNOWN': + // Unknown error, contact server owner + displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') + break - case undefined: - case null: - case 'AUTH_DISABLED': - // Authentication is disabled, we can just connect the user - displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn') - break + case undefined: + case null: + case 'AUTH_DISABLED': + // Authentication is disabled, we can just connect the user + displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn') + break - default: - // Success!! Bring them to the login screen and auto-input their username - const loginUsername = document.getElementById('loginUsername') - loginUsername.value = username + default: + // Success!! Bring them to the login screen and auto-input their username + const loginUsername = document.getElementById('loginUsername') + loginUsername.value = username - setLoginSection() - displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000) - break - } + setLoginSection() + displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000) + break + } } diff --git a/resources/js/onLoad.js b/resources/js/onLoad.js index e1942c8..2065d5e 100644 --- a/resources/js/onLoad.js +++ b/resources/js/onLoad.js @@ -4,86 +4,86 @@ * should be done here to ensure DOM contents are loaded. */ document.addEventListener('DOMContentLoaded', async () => { - displayUpdate() - setBackgroundImage() - displayGameFolder() - displayServerFolder() + displayUpdate() + setBackgroundImage() + displayGameFolder() + displayServerFolder() - // Set title version - document.querySelector('#version').innerHTML = NL_APPVERSION + // Set title version + document.querySelector('#version').innerHTML = NL_APPVERSION - const config = await getCfg() - const ipArr = await getFavIps() + const config = await getCfg() + const ipArr = await getFavIps() - if (config.serverLaunchPanel) { - displayServerLaunchSection() - } + if (config.serverLaunchPanel) { + displayServerLaunchSection() + } - // Set last connect - document.querySelector('#ip').value = config.lastConnect + // Set last connect + document.querySelector('#ip').value = config.lastConnect - if (ipArr.includes(config.lastConnect)) { - document.querySelector('#star').src = 'icons/star_filled.svg' - } + if (ipArr.includes(config.lastConnect)) { + document.querySelector('#star').src = 'icons/star_filled.svg' + } - // Disable private game launch if proxy IP or proxy server is not found - const playPriv = document.querySelector('#playPrivate') + // Disable private game launch if proxy IP or proxy server is not found + const playPriv = document.querySelector('#playPrivate') - if (!(await proxyIsInstalled())) { - playPriv.classList.add('disabled') - playPriv.disabled = true + if (!(await proxyIsInstalled())) { + playPriv.classList.add('disabled') + playPriv.disabled = true + } + + // Exit favorites list and settings panel when clicking outside of it + window.addEventListener('click', function(e) { + const favList = document.querySelector('#ipList') + const settingsPanel = document.querySelector('#settingsPanel') + const downloadPanel = document.querySelector('#downloadPanel') + + // This will close the favorites list no matter what is clicked + if (favList.style.display !== 'none') { + favList.style.display = 'none' + favList.style.transform = '' } - // Exit favorites list and settings panel when clicking outside of it - window.addEventListener('click', function(e) { - const favList = document.querySelector('#ipList') - const settingsPanel = document.querySelector('#settingsPanel') - const downloadPanel = document.querySelector('#downloadPanel') + // This will close the settings panel no matter what is clicked + let checkElm = e.target - // This will close the favorites list no matter what is clicked - if (favList.style.display !== 'none') { - favList.style.display = 'none' - favList.style.transform = '' - } - - // This will close the settings panel no matter what is clicked - let checkElm = e.target - - while(checkElm.tagName !== 'BODY') { - if (checkElm.id === 'settingsPanel' + while(checkElm.tagName !== 'BODY') { + if (checkElm.id === 'settingsPanel' || checkElm.id === 'settingsBtn') { - return - } + return + } - if (checkElm.id === 'downloadPanel' || + if (checkElm.id === 'downloadPanel' || checkElm.id === 'downloadBtn') { - return - } + return + } - checkElm = checkElm.parentElement - } + checkElm = checkElm.parentElement + } - // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel - if (checkElm.tagName === 'BODY') { - // This will close the settings panel only when something outside of it is clicked - if (settingsPanel.style.display !== 'none') { - settingsPanel.style.display = 'none' - } + // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel + if (checkElm.tagName === 'BODY') { + // This will close the settings panel only when something outside of it is clicked + if (settingsPanel.style.display !== 'none') { + settingsPanel.style.display = 'none' + } - if (downloadPanel.style.display !== 'none') { - downloadPanel.style.display = 'none' - } - } - }) + if (downloadPanel.style.display !== 'none') { + downloadPanel.style.display = 'none' + } + } + }) - // Ensure we do the translation at the very end, after everything else has loaded - await doTranslation() + // Ensure we do the translation at the very end, after everything else has loaded + await doTranslation() - if (!config.gameexe) { - handleGameNotSet() - } + if (!config.gameexe) { + handleGameNotSet() + } - if (!config.serverFolder) { - handleServerNotSet() - } + if (!config.serverFolder) { + handleServerNotSet() + } }) diff --git a/resources/js/options.js b/resources/js/options.js index a42f899..5004108 100644 --- a/resources/js/options.js +++ b/resources/js/options.js @@ -2,54 +2,54 @@ * Toggle the killswitch script */ async function toggleKillSwitch() { - const killSwitch = document.querySelector('#killswitchOption') - const config = await getCfg() + const killSwitch = document.querySelector('#killswitchOption') + const config = await getCfg() - config.enableKillswitch = killSwitch.checked + config.enableKillswitch = killSwitch.checked - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) } /** * Toggles the server launching panel */ async function toggleServerLaunchSection() { - const config = await getCfg() + const config = await getCfg() - displayServerLaunchSection() + displayServerLaunchSection() - // Save setting - config.serverLaunchPanel = !config.serverLaunchPanel - Neutralino.storage.setData('config', JSON.stringify(config)) + // Save setting + config.serverLaunchPanel = !config.serverLaunchPanel + Neutralino.storage.setData('config', JSON.stringify(config)) } /** * Get all languages for the language selector */ async function getLanguages() { - const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) - const config = await getCfg() + const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) + const config = await getCfg() - // Clear language options - const languageSelect = document.querySelector('#languageSelect') - languageSelect.innerHTML = '' + // Clear language options + const languageSelect = document.querySelector('#languageSelect') + languageSelect.innerHTML = '' - // Load all languages as options - for (const file of languageFiles) { - const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName - const lang = file.entry.split('.json')[0] + // Load all languages as options + for (const file of languageFiles) { + const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName + const lang = file.entry.split('.json')[0] - const option = document.createElement('option') - option.value = lang - option.innerHTML = fullLanguageName + const option = document.createElement('option') + option.value = lang + option.innerHTML = fullLanguageName - // Set language selected to config language - if (lang === config.language) { - option.selected = true - } - - document.querySelector('#languageSelect').appendChild(option) + // Set language selected to config language + if (lang === config.language) { + option.selected = true } + + document.querySelector('#languageSelect').appendChild(option) + } } /** @@ -58,27 +58,27 @@ async function getLanguages() { * @param {DOMElement} elm */ async function handleLanguageChange(elm) { - const list = elm - const config = await getCfg() + const list = elm + const config = await getCfg() - // Set language in config - config.language = list.value - Neutralino.storage.setData('config', JSON.stringify(config)) + // Set language in config + config.language = list.value + Neutralino.storage.setData('config', JSON.stringify(config)) - // Force refresh of application, no need for restart! - window.location.reload() + // Force refresh of application, no need for restart! + window.location.reload() } /** * Toggle the use of HTTPS */ async function toggleHttps() { - const httpsCheckbox = document.querySelector('#httpsOption') - const config = await getCfg() + const httpsCheckbox = document.querySelector('#httpsOption') + const config = await getCfg() - config.useHttps = httpsCheckbox.checked + config.useHttps = httpsCheckbox.checked - Neutralino.storage.setData('config', JSON.stringify(config)) + Neutralino.storage.setData('config', JSON.stringify(config)) } /** @@ -87,28 +87,28 @@ async function toggleHttps() { * Remove the current value of the IP input from the favorites list */ async function setFavorite() { - const ip = document.querySelector('#ip').value - const port = document.querySelector('#port').value || '443' - const ipArr = await getFavIps() + const ip = document.querySelector('#ip').value + const port = document.querySelector('#port').value || '443' + const ipArr = await getFavIps() - const addr = `${ip}:${port}` + const addr = `${ip}:${port}` - // Set star icon - const star = document.querySelector('#star') + // Set star icon + const star = document.querySelector('#star') - if (star.src.includes('filled') && ip) { - star.src = 'icons/star_empty.svg' + if (star.src.includes('filled') && ip) { + star.src = 'icons/star_empty.svg' - // remove from list - ipArr.splice(ipArr.indexOf(addr), 1) - } else { - star.src = 'icons/star_filled.svg' + // remove from list + ipArr.splice(ipArr.indexOf(addr), 1) + } else { + star.src = 'icons/star_filled.svg' - // add to list - if (ip && !ipArr.includes(addr)) { - ipArr.push(addr) - } + // add to list + if (ip && !ipArr.includes(addr)) { + ipArr.push(addr) } + } - Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) + Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) } diff --git a/resources/js/translation.js b/resources/js/translation.js index 47f0eb0..dd80b83 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -1,110 +1,110 @@ async function doTranslation() { - const config = await getCfg() + const config = await getCfg() - // See if the localization file exists - const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`) + // See if the localization file exists + const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`) - // Use english if the selected file does not exist - const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`) + // Use english if the selected file does not exist + const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`) - // Use english if the selected file does not exist - if (!selectedLanguage) { - config.language = 'en' - } + // Use english if the selected file does not exist + if (!selectedLanguage) { + config.language = 'en' + } - const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) - const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) - engLocaleObj = JSON.parse(engLocale) - localeObj = JSON.parse(localization) + const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) + const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) + engLocaleObj = JSON.parse(engLocale) + localeObj = JSON.parse(localization) - const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString] + const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString] - // Begin filling in values - set('titleSection', 'appName') + // Begin filling in values + set('titleSection', 'appName') - const verSpan = document.createElement('span') - verSpan.id = 'version' - verSpan.innerHTML = ` v${NL_APPVERSION}` + const verSpan = document.createElement('span') + verSpan.id = 'version' + verSpan.innerHTML = ` v${NL_APPVERSION}` - document.querySelector('#titleSection').appendChild(verSpan) + document.querySelector('#titleSection').appendChild(verSpan) - // Play buttons - set('playOfficial', 'playOfficial') - set('playPrivate', 'playPrivate') - set('serverLaunch', 'launchLocalServer') + // Play buttons + set('playOfficial', 'playOfficial') + set('playPrivate', 'playPrivate') + set('serverLaunch', 'launchLocalServer') - // File select buttons - set('gameExeSet', 'gameExeSet') - set('grasscutterFileSet', 'grasscutterFileSet') + // File select buttons + set('gameExeSet', 'gameExeSet') + set('grasscutterFileSet', 'grasscutterFileSet') - // Private options - document.querySelector('#ip').placeholder = localeObj.ipPlaceholder - document.querySelector('#port').placeholder = localeObj.portPlaceholder + // Private options + document.querySelector('#ip').placeholder = localeObj.ipPlaceholder + document.querySelector('#port').placeholder = localeObj.portPlaceholder - // Settings - set('fullSettingsTitle', 'settingsTitle') - set('scriptsTitle', 'scriptsSectionTitle') - set('killswitchTitle', 'killswitchOption') - set('killswitchSubtitle', 'killswitchSubtitle') - set('proxyTitle', 'proxyOption') - set('proxyInstall', 'proxyInstallBtn') - set('proxySubtitle', 'proxySubtitle') - set('updateBtn', 'updateOption') - set('updateTitle', 'updateOption') - set('updateSubtitle', 'updateSubtitle') - set('languageTitle', 'languageOption') - set('languageSubtitle', 'languageSubtitle') - set('serverLaunchTitle', 'enableServerLauncherOption') - set('serverSubtitle', 'enableServerLauncherSubtitle') - set('httpsTitle', 'httpsOption') - set('httpsSubtitle', 'httpsSubtitle') + // Settings + set('fullSettingsTitle', 'settingsTitle') + set('scriptsTitle', 'scriptsSectionTitle') + set('killswitchTitle', 'killswitchOption') + set('killswitchSubtitle', 'killswitchSubtitle') + set('proxyTitle', 'proxyOption') + set('proxyInstall', 'proxyInstallBtn') + set('proxySubtitle', 'proxySubtitle') + set('updateBtn', 'updateOption') + set('updateTitle', 'updateOption') + set('updateSubtitle', 'updateSubtitle') + set('languageTitle', 'languageOption') + set('languageSubtitle', 'languageSubtitle') + set('serverLaunchTitle', 'enableServerLauncherOption') + set('serverSubtitle', 'enableServerLauncherSubtitle') + set('httpsTitle', 'httpsOption') + set('httpsSubtitle', 'httpsSubtitle') - // Intro popup - const popup = document.getElementById('firstTimeNotice') - const introSpan = popup.querySelector('span') - const boldIntroSpan = document.createElement('span') + // Intro popup + const popup = document.getElementById('firstTimeNotice') + const introSpan = popup.querySelector('span') + const boldIntroSpan = document.createElement('span') - boldIntroSpan.innerHTML = localeObj.introSen1 + '\n' - boldIntroSpan.classList.add('boldTitle') + boldIntroSpan.innerHTML = localeObj.introSen1 + '\n' + boldIntroSpan.classList.add('boldTitle') - introSpan.appendChild(boldIntroSpan) + introSpan.appendChild(boldIntroSpan) - introSpan.innerHTML += localeObj.introSen2 + '
' - introSpan.innerHTML += localeObj.introSen3 + '
' - introSpan.innerHTML += localeObj.introSen4 + '
' + introSpan.innerHTML += localeObj.introSen2 + '
' + introSpan.innerHTML += localeObj.introSen3 + '
' + introSpan.innerHTML += localeObj.introSen4 + '
' - set('firstTimeInstallBtn', 'proxyInstallBtn') - set('firstTimeDenyBtn', 'proxyInstallDeny') + set('firstTimeInstallBtn', 'proxyInstallBtn') + set('firstTimeDenyBtn', 'proxyInstallDeny') - // Login section - set('loginSectionTitle', 'authLoginTitle') - set('registerSectionTitle', 'authRegisterTitle') - set('loggingInToIndicator', 'loggingInTo') - set('registeringToIndicator', 'registeringFor') - set('loginUsernameIndicator', 'authUsername') - set('loginPasswordIndicator', 'authPassword') - set('registerUsernameIndicator', 'authUsername') - set('registerPasswordIndicator', 'authPassword') - set('registerConfirmIndicator', 'authConfirmPassword') - set('loginPopupContentBodyBtnLogin', 'authLoginBtn') - set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') - set('noLoginBtn', 'launchWithoutAuth') + // Login section + set('loginSectionTitle', 'authLoginTitle') + set('registerSectionTitle', 'authRegisterTitle') + set('loggingInToIndicator', 'loggingInTo') + set('registeringToIndicator', 'registeringFor') + set('loginUsernameIndicator', 'authUsername') + set('loginPasswordIndicator', 'authPassword') + set('registerUsernameIndicator', 'authUsername') + set('registerPasswordIndicator', 'authPassword') + set('registerConfirmIndicator', 'authConfirmPassword') + set('loginPopupContentBodyBtnLogin', 'authLoginBtn') + set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') + set('noLoginBtn', 'launchWithoutAuth') - // Downloads section - set('downloadTitle', 'downloadTitle') - set('grassclipperTitle', 'grassclipperTitle') - set('grasscutterTitle', 'grasscutterTitle') - set('installerTitle', 'installerTitle') - set('installerSubtitle', 'installerSubtitle') - set('downloadStable', 'downloadStable') - set('stableSubtitle', 'stableSubtitle') - set('downloadDev', 'downloadDev') - set('devSubtitle', 'downloadSubtitle') - set('downloadResources', 'downloadResources') - set('devSubtitle', 'devSubtitle') - set('stableInstall', 'stableInstall') - set('devInstall', 'devInstall') + // Downloads section + set('downloadTitle', 'downloadTitle') + set('grassclipperTitle', 'grassclipperTitle') + set('grasscutterTitle', 'grasscutterTitle') + set('installerTitle', 'installerTitle') + set('installerSubtitle', 'installerSubtitle') + set('downloadStable', 'downloadStable') + set('stableSubtitle', 'stableSubtitle') + set('downloadDev', 'downloadDev') + set('devSubtitle', 'downloadSubtitle') + set('downloadResources', 'downloadResources') + set('devSubtitle', 'devSubtitle') + set('stableInstall', 'stableInstall') + set('devInstall', 'devInstall') - // update notification - set('updateNotifText', 'updateNotifText') + // update notification + set('updateNotifText', 'updateNotifText') } \ No newline at end of file diff --git a/resources/js/windowDrag.js b/resources/js/windowDrag.js index e8d8704..642b0f3 100644 --- a/resources/js/windowDrag.js +++ b/resources/js/windowDrag.js @@ -4,22 +4,22 @@ let dragging = false, ratio = 1, posX, posY let draggable document.addEventListener('DOMContentLoaded', async () => { - draggable = document.getElementById('controlBar') + draggable = document.getElementById('controlBar') - // Listen to hovers - draggable.onmousedown = function (e) { - ratio = window.devicePixelRatio + // Listen to hovers + draggable.onmousedown = function (e) { + ratio = window.devicePixelRatio - posX = e.pageX * ratio, posY = e.pageY * ratio - dragging = true - } + posX = e.pageX * ratio, posY = e.pageY * ratio + dragging = true + } - // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere - window.onmouseup = function (e) { - dragging = false - } + // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere + window.onmouseup = function (e) { + dragging = false + } - document.onmousemove = function (e) { - if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY) - } + document.onmousemove = function (e) { + if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY) + } }) \ No newline at end of file From d63f403a92b961727f73a7a5d041f5febdabe933 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Mon, 2 May 2022 22:49:22 -0700 Subject: [PATCH 202/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 2fc35a4..77d9e27 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.7", + "version": "0.9.0", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index be4549a..0bdb3dd 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.8.7", + "version": "0.9.0", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 9c0eb1a..764fed5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.8.7", + "version": "0.9.0", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 19c017f78e4a1b8ffef189bc0c20ed4a1b61d3d6 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 00:19:56 -0700 Subject: [PATCH 203/248] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4b87515..0179d73 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ Encountering a white screen? [Ensure WebView2 is installed](https://developer.mi You may also want to run this command as administrator: `CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy"` +If you have Chinese characters in your file path, this may crash it too! I am working on a fix. + If all else fails, you can run GrassClipper in `chrome` or `browser` mode. To do so: * Create a shortcut to `GrassClipper.exe` * Right click the shortcut, click `properties` From 4db691b56d111f9c7afde54f90c666f5be985052 Mon Sep 17 00:00:00 2001 From: Nautilus Date: Tue, 3 May 2022 14:24:38 +0700 Subject: [PATCH 204/248] add download section for Indonesian translation --- languages/id.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/languages/id.json b/languages/id.json index c56e617..61f81ce 100644 --- a/languages/id.json +++ b/languages/id.json @@ -63,5 +63,21 @@ "alertAuthNoRegister": "Autentikasi dinonaktifkan, tidak perlu mendaftar!", "alertRegisterSuccess": "Pendaftaran berhasil!", + "downloadTitle": "Unduhan", + "grassclipperTitle": "GrassClipper", + "grasscutterTitle": "Grasscutter", + "installerTitle": "Pemasang", + "installerSubtitle": "Pasang proxy dan alat lainnya. Diperlukan untuk server Grasscutter.", + "downloadStable": "Unduh Versi Stabil Grasscutter", + "stableSubtitle": "Pasang versi stabil Grasscutter. Versi ini biasanya tidak punya banyak bug, tetapi juga fiturnya lebih sedikit.", + "downloadDev": "Unduh Versi Pengembangan Grasscutter", + "downloadSubtitle": "Pasang versi pengembangan Grasscutter. Versi ini biasanya mempunyai banyak bug dan sering diperbarui. Gunakan dengan resikomu sendiri.", + "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.", + + "gcScriptRunning": "Menjalankan...", + "stableInstall": "Unduh", + "devInstall": "Unduh", + "updateNotifText": "Pembaruan baru tersedia! Versi terbaru: " } From ecff5fc02122d3a2e4515daf80d2dede93d7db0d Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 00:34:30 -0700 Subject: [PATCH 205/248] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0179d73..05219ef 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ Thank you to everyone who has provided translations! <3 * ZH-TW - Kimi & KormiMeiko * PT-BR - na.na * VIE - labalityowo -* ID - Iqrar99 +* ID - Iqrar99 & nautilust * FR - linsorak & memetrollsXD * ES - memetrollsXD * ND - memetrollsXD From 9716a3d79db8e2489e131703604e5ab3a734aaed Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 01:09:22 -0700 Subject: [PATCH 206/248] fix naming mixup (names will be fixed later) --- build_win.cmd | 2 +- resources/js/translation.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/build_win.cmd b/build_win.cmd index a093c04..d0f18d7 100644 --- a/build_win.cmd +++ b/build_win.cmd @@ -5,7 +5,7 @@ set SSL_BINARY_URL="https://github.com/SpikeHD/neutralinojs/releases/download/v4 set NON_SSL_BINARY_URL="https://github.com/SpikeHD/neutralinojs/releases/download/v1337.0.0/neutralino-win_x64.exe" :: Clean dist folder -del /s /q /f .\dist +del /s /q /f .\dist>nul rd /s /q .\dist :: Get the SSL-secure version of the binary diff --git a/resources/js/translation.js b/resources/js/translation.js index dd80b83..374357b 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -101,7 +101,6 @@ async function doTranslation() { set('downloadDev', 'downloadDev') set('devSubtitle', 'downloadSubtitle') set('downloadResources', 'downloadResources') - set('devSubtitle', 'devSubtitle') set('stableInstall', 'stableInstall') set('devInstall', 'devInstall') From d8230ff00e5c7f3aa770b7b51353ee05f8cc101c Mon Sep 17 00:00:00 2001 From: Kimi <34180607+Kimi898246@users.noreply.github.com> Date: Tue, 3 May 2022 16:22:18 +0800 Subject: [PATCH 207/248] Traditional Chinese | New Translations Might required some fixes, but it's here. --- languages/zh-tw.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/languages/zh-tw.json b/languages/zh-tw.json index 0d23c08..7737f49 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -34,7 +34,8 @@ "introSen3": "是否要運行Proxy安裝程序?", "introSen4": "(需要連接到私人伺服器)", - "proxyInstallBtn": "安装", + "updateBtn": "更新", + "proxyInstallBtn": "安裝", "proxyInstallDeny": "不用了,謝謝。", "gameFolderDialog": "選擇Genshin Impact game資料夾", @@ -62,5 +63,21 @@ "alertAuthNoRegister": "未啟用認證,無需註冊!", "alertRegisterSuccess": "註冊成功!", + "downloadTitle": "安裝清單", + "grassclipperTitle": "GrassClipper", + "grasscutterTitle": "Grasscutter", + "installerTitle": "安裝程式", + "installerSubtitle": "安裝Proxy和其他工具。 Grasscutter伺服器連接時需要。", + "downloadStable": "安裝 Stable 構建", + "stableSubtitle": "安裝 Stable 分支. 此構建通常具有較少的錯誤,但功能也很少。", + "downloadDev": "安裝 Development 構建", + "downloadSubtitle": "安裝 Development 分支. 此版本有時存在錯誤,並且經常更新。 使用此版本風險自負。", + "downloadResources": "下載 resources 資料夾", + "devSubtitle": "將 resources 安裝在目前設置的 Grasscutter 資料夾中。 除非您計劃從外部獲取resources,否則應該這樣做。", + + "gcScriptRunning": "執行中...", + "stableInstall": "安裝", + "devInstall": "安装", + "updateNotifText": "有新的GrassClipper更新可用! 最新版本: " } From ac334d41684e21ce12eee69071732e44a1d102dc Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 01:26:26 -0700 Subject: [PATCH 208/248] fix translations --- languages/en.json | 4 ++-- languages/zh-tw.json | 4 ++-- resources/index.html | 2 +- resources/js/translation.js | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/languages/en.json b/languages/en.json index 1fecb4d..538e68c 100644 --- a/languages/en.json +++ b/languages/en.json @@ -71,9 +71,9 @@ "downloadStable": "Download Grasscutter Stable Build", "stableSubtitle": "Install Grasscutter stable branch. This build usually has less bugs, but also less features.", "downloadDev": "Download Grasscutter Development Build", - "downloadSubtitle": "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", - "devSubtitle": "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.", "gcScriptRunning": "Running...", "stableInstall": "Download", diff --git a/languages/zh-tw.json b/languages/zh-tw.json index 7737f49..6296b5b 100644 --- a/languages/zh-tw.json +++ b/languages/zh-tw.json @@ -71,9 +71,9 @@ "downloadStable": "安裝 Stable 構建", "stableSubtitle": "安裝 Stable 分支. 此構建通常具有較少的錯誤,但功能也很少。", "downloadDev": "安裝 Development 構建", - "downloadSubtitle": "安裝 Development 分支. 此版本有時存在錯誤,並且經常更新。 使用此版本風險自負。", + "devSubtitle": "安裝 Development 分支. 此版本有時存在錯誤,並且經常更新。 使用此版本風險自負。", "downloadResources": "下載 resources 資料夾", - "devSubtitle": "將 resources 安裝在目前設置的 Grasscutter 資料夾中。 除非您計劃從外部獲取resources,否則應該這樣做。", + "resourceSubtitle": "將 resources 安裝在目前設置的 Grasscutter 資料夾中。 除非您計劃從外部獲取resources,否則應該這樣做。", "gcScriptRunning": "執行中...", "stableInstall": "安裝", diff --git a/resources/index.html b/resources/index.html index bb71778..086712a 100644 --- a/resources/index.html +++ b/resources/index.html @@ -161,7 +161,7 @@ Download Grasscutter Resources
- + Downloads Grasscutter resources into the currently set Grasscutter folder. This should be done unless you plan on getting resources externally.
diff --git a/resources/js/translation.js b/resources/js/translation.js index 374357b..a579a5f 100644 --- a/resources/js/translation.js +++ b/resources/js/translation.js @@ -99,8 +99,9 @@ async function doTranslation() { set('downloadStable', 'downloadStable') set('stableSubtitle', 'stableSubtitle') set('downloadDev', 'downloadDev') - set('devSubtitle', 'downloadSubtitle') + set('devSubtitle', 'devSubtitle') set('downloadResources', 'downloadResources') + set('resourceSubtitle', 'resourceSubtitle') set('stableInstall', 'stableInstall') set('devInstall', 'devInstall') From c5af2666aed6d90cdfb377aaed75933f46df64b8 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 01:26:55 -0700 Subject: [PATCH 209/248] version bump --- manifest.json | 2 +- neutralino.config.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 77d9e27..7d625b7 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { "applicationId": "js.grassclipper.app", - "version": "0.9.0", + "version": "0.9.1", "resourcesURL": "https://github.com/Grasscutters/GrassClipper/releases/latest/download/resources.neu" } \ No newline at end of file diff --git a/neutralino.config.json b/neutralino.config.json index 0bdb3dd..0df0bd1 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -1,6 +1,6 @@ { "applicationId": "js.grassclipper.app", - "version": "0.9.0", + "version": "0.9.1", "defaultMode": "window", "port": 0, "documentRoot": "/resources/", diff --git a/package.json b/package.json index 764fed5..b05cf2c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grassclipper", - "version": "0.9.0", + "version": "0.9.1", "repository": "https://github.com/Grasscutters/GrassClipper.git", "author": "SpikeHD ", "license": "Apache-2.0", From 5cc20917640a77d427aa5e1931927a9c72c6815c Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 01:33:56 -0700 Subject: [PATCH 210/248] Update zh.json --- languages/zh.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages/zh.json b/languages/zh.json index 1e354a4..a111e96 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -1,5 +1,5 @@ { - "fullLangName": "Simplified Chinese", + "fullLangName": "简体中文", "appName": "GrassClipper 启动器", "playOfficial": "启动官方服务器", From 223790b0bd765d71a01538c63195dc8b65960e69 Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 20:34:53 -0700 Subject: [PATCH 211/248] potentially fix opening game/gc folders --- resources/js/helpers.js | 12 +++++------- resources/js/index.js | 1 - 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 8fe28c2..6952906 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -91,23 +91,22 @@ async function openLatestDownload() { async function openGameFolder() { const config = await getCfg() - const folder = config.gameexe.match(/.*\\/g, '')[0] - - openInExplorer(folder) + const folder = config.gameexe.match(/.*\\|.*\//g, '') + + if (folder.length > 0) openInExplorer(folder[0]) } async function openGrasscutterFolder() { const config = await getCfg() - const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] + const folder = config.serverFolder.match(/.*\\|.*\//g, '') - openInExplorer(folder) + if (folder.length > 0) openInExplorer(folder[0]) } /** * Minimize the window */ function minimizeWin() { - console.log('min') Neutralino.window.minimize() } @@ -115,7 +114,6 @@ function minimizeWin() { * Close the window */ function closeWin() { - console.log('close') Neutralino.app.exit() window.close() diff --git a/resources/js/index.js b/resources/js/index.js index 15523cc..911cdcc 100644 --- a/resources/js/index.js +++ b/resources/js/index.js @@ -7,7 +7,6 @@ const createCmdWindow = async (command) => { } const openInExplorer = async (path) => { - console.log(`explorer.exe "${path}"`) createCmdWindow(`explorer.exe "${path}"`) } From 6c0d8c2a194f48d17f23b645338b864de07da3fe Mon Sep 17 00:00:00 2001 From: SpikeHD Date: Tue, 3 May 2022 21:06:01 -0700 Subject: [PATCH 212/248] alert system --- package-lock.json | 1585 +++++++++++++++++++++++++++++ resources/index.html | 6 + resources/js/alerts.js | 19 + resources/js/authAlert.js | 6 +- resources/js/helpers.js | 13 + resources/style/index.css | 27 + scripts/private_server_launch.cmd | 3 + 7 files changed, 1656 insertions(+), 3 deletions(-) create mode 100644 package-lock.json create mode 100644 resources/js/alerts.js diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0b2dccb --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1585 @@ +{ + "name": "grassclipper", + "version": "0.9.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "grassclipper", + "version": "0.9.1", + "license": "Apache-2.0", + "devDependencies": { + "eslint": "^8.14.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.2.2", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + }, + "dependencies": { + "@eslint/eslintrc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.2.2", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/resources/index.html b/resources/index.html index 086712a..cbd814a 100644 --- a/resources/index.html +++ b/resources/index.html @@ -10,12 +10,18 @@ + + +
+ This is a test alert +
+