Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
41ab585a48 | |||
3edefccd0b | |||
713196c9db | |||
5bde3d347a | |||
2304a78db4 | |||
81cf2cf413 | |||
45b06e4478 | |||
77f5b6cd5e | |||
67872bc4d1 | |||
469ba5f574 | |||
8f05a04350 | |||
4ddc54d528 | |||
c4d023ed43 | |||
9b86af282e | |||
2e17e0ae75 | |||
edef5cc6dc | |||
2dad0de4f1 | |||
14a65eb5bb | |||
0add9200a6 | |||
ee49da3665 | |||
f478ad9216 | |||
c59dbcc35c | |||
91d38b58c4 | |||
240f60b283 | |||
6a32ad65a5 | |||
6cc7a537b6 | |||
bf4c06ee2d | |||
f26d83f291 | |||
8b2c1a04ee | |||
ce03668252 | |||
58c692a879 | |||
e569d57788 |
74
CHANGELOG.md
74
CHANGELOG.md
@ -1,3 +1,77 @@
|
||||
## 0.22.0
|
||||
|
||||
- Added Spanish localization (courtesy of 7x)
|
||||
- Added Korean localization (courtesy of LEveLiQ)
|
||||
|
||||
## 0.21.0
|
||||
|
||||
- Added simplified Chinese localization (courtesy of Chilor)
|
||||
|
||||
## 0.20.1
|
||||
|
||||
- Added Japanese localization (courtesy of SALEC)
|
||||
- Added user-customizable scripts
|
||||
- The launch script runs directly before the game, and is equivalent to adding lines above `start "AM Daemon" ...` in start.bat
|
||||
- The end script runs after the game has closed for any reason, and is equivalent to adding lines below `taskkill /f /im amdaemon.exe ...` in start.bat
|
||||
- This functionality is needed for cursed things such as brokenithm
|
||||
- Fixed the file editor not updating its state properly
|
||||
- Fixed diagnostic exports not exporting paths
|
||||
- Fixed "Install recommended packages" not enabling the segatools hook
|
||||
|
||||
## 0.19.1
|
||||
|
||||
- Fixed the update button enabling the package
|
||||
- Fixed deep URLs with rainycolor.org
|
||||
|
||||
## 0.19.0
|
||||
|
||||
- Added diagnostic exports
|
||||
|
||||
## 0.18.3
|
||||
|
||||
- Updated Rainycolor's domain・真
|
||||
|
||||
## 0.18.2
|
||||
|
||||
- Updated Rainycolor's domain
|
||||
|
||||
## 0.18.1
|
||||
|
||||
- Keys can now be unbinded with Esc
|
||||
- Fixed CHUNITHM IR behavior on actual keyboards
|
||||
|
||||
## 0.18.0
|
||||
|
||||
- Added new grouping options to the package list
|
||||
|
||||
## 0.17.0
|
||||
|
||||
- Added a package creation prompt
|
||||
- Added a default package icon
|
||||
|
||||
## 0.16.0
|
||||
|
||||
- Fixed the clear cache button not working
|
||||
- Fixed Linux builds
|
||||
- Moved the store tab to the left
|
||||
- "Reapply mods and start" renamed from "Refresh and start" to better convey the meaning
|
||||
- "Reapply mods and start" is no longer necessary when enabling packages from the `local` namespace
|
||||
- Various internationalization additions
|
||||
- STARTLINER now remembers the recently open tab and re-opens it on the next session
|
||||
- Added "Beta" to the title as STARTLINER is approaching feature-completeness
|
||||
- Added full Polish localization :smciota:
|
||||
|
||||
## 0.15.0
|
||||
|
||||
- Added internationalization
|
||||
- Moved some client options to the home page
|
||||
- Added 'dll-game32' and 'dll-game64' entries for native mods that target both Chunithm and Ongeki
|
||||
- Ongeki: added mempatcher support (amdaemon)
|
||||
|
||||
## 0.14.0
|
||||
|
||||
- Added the custom FREE PLAY patch for Verse
|
||||
|
||||
## 0.13.0
|
||||
|
||||
- Added profile imports/exports
|
||||
|
@ -1,4 +1,7 @@
|
||||
Looking for maimai DX players willing to help develop/test maimai DX support
|
||||
Looking for
|
||||
|
||||
- maimai DX players willing to help develop/test maimai DX support
|
||||
- translators (any language other than English)
|
||||
|
||||
# STARTLINER
|
||||
|
||||
@ -6,7 +9,7 @@ This is a program that seeks to streamline game data configuration, currently su
|
||||
|
||||
STARTLINER is four things:
|
||||
|
||||
- a mod installer and updater, powered by [Rainycolor Watercolor](https://rainy.patafour.zip),
|
||||
- a mod installer and updater, powered by [Rainycolor Watercolor](https://rainycolor.org),
|
||||
- a configuration GUI for segatools,
|
||||
- a glorified `start.bat` clicker, with automatic monitor setup and rollback,
|
||||
- [an abstraction allowing data configuration without touching the game directory](https://gitea.tendokyu.moe/akanyan/STARTLINER/wiki/Architecture-details).
|
||||
|
1
TODO.md
1
TODO.md
@ -1,5 +1,6 @@
|
||||
### Short-term
|
||||
|
||||
- i18n
|
||||
- https://gitea.tendokyu.moe/TeamTofuShop/segatools/issues/63
|
||||
|
||||
### Long-term
|
||||
|
231
bun.lock
231
bun.lock
@ -8,15 +8,15 @@
|
||||
"@mdi/font": "7.4.47",
|
||||
"@primevue/forms": "^4.3.3",
|
||||
"@primevue/themes": "^4.3.3",
|
||||
"@tailwindcss/vite": "^4.1.3",
|
||||
"@tauri-apps/api": "^2.4.1",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"@tauri-apps/api": "^2.5.0",
|
||||
"@tauri-apps/plugin-cli": "^2.2.0",
|
||||
"@tauri-apps/plugin-deep-link": "~2.2.1",
|
||||
"@tauri-apps/plugin-dialog": "~2.2.1",
|
||||
"@tauri-apps/plugin-fs": "^2.2.1",
|
||||
"@tauri-apps/plugin-opener": "^2.2.6",
|
||||
"@tauri-apps/plugin-shell": "~2.2.1",
|
||||
"@tauri-apps/plugin-updater": "^2.7.0",
|
||||
"@tauri-apps/plugin-updater": "^2.7.1",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"markdown-it": "^14.1.0",
|
||||
@ -24,13 +24,14 @@
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.3.3",
|
||||
"roboto-fontface": "^0.10.0",
|
||||
"tailwindcss": "^4.1.3",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"tailwindcss-primeui": "^0.4.0",
|
||||
"vue": "^3.5.13",
|
||||
"vuetify": "^3.8.1",
|
||||
"vue-i18n": "^11.1.3",
|
||||
"vuetify": "^3.8.2",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.4.1",
|
||||
"@tauri-apps/cli": "^2.5.0",
|
||||
"@tsconfig/node22": "^22.0.1",
|
||||
"@types/node": "^22.14.1",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
@ -38,11 +39,11 @@
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"sass": "1.77.8",
|
||||
"sass-embedded": "^1.86.3",
|
||||
"sass-embedded": "^1.87.0",
|
||||
"typescript": "^5.8.3",
|
||||
"unplugin-fonts": "^1.3.1",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"vite": "^6.2.6",
|
||||
"vite": "^6.3.2",
|
||||
"vite-plugin-vuetify": "^2.1.1",
|
||||
"vue-tsc": "^2.2.8",
|
||||
},
|
||||
@ -145,6 +146,12 @@
|
||||
|
||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.1", "", {}, "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA=="],
|
||||
|
||||
"@intlify/core-base": ["@intlify/core-base@11.1.3", "", { "dependencies": { "@intlify/message-compiler": "11.1.3", "@intlify/shared": "11.1.3" } }, "sha512-cMuHunYO7LE80azTitcvEbs1KJmtd6g7I5pxlApV3Jo547zdO3h31/0uXpqHc+Y3RKt1wo2y68RGSx77Z1klyA=="],
|
||||
|
||||
"@intlify/message-compiler": ["@intlify/message-compiler@11.1.3", "", { "dependencies": { "@intlify/shared": "11.1.3", "source-map-js": "^1.0.2" } }, "sha512-7rbqqpo2f5+tIcwZTAG/Ooy9C8NDVwfDkvSeDPWUPQW+Dyzfw2o9H103N5lKBxO7wxX9dgCDjQ8Umz73uYw3hw=="],
|
||||
|
||||
"@intlify/shared": ["@intlify/shared@11.1.3", "", {}, "sha512-pTFBgqa/99JRA2H1qfyqv97MKWJrYngXBA/I0elZcYxvJgcCw3mApAoPW3mJ7vx3j+Ti0FyKUFZ4hWxdjKaxvA=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
@ -183,97 +190,101 @@
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.6", "", { "os": "android", "cpu": "arm" }, "sha512-+GcCXtOQoWuC7hhX1P00LqjjIiS/iOouHXhMdiDSnq/1DGTox4SpUvO52Xm+div6+106r+TcvOeo/cxvyEyTgg=="],
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.40.0", "", { "os": "android", "cpu": "arm" }, "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.6", "", { "os": "android", "cpu": "arm64" }, "sha512-E8+2qCIjciYUnCa1AiVF1BkRgqIGW9KzJeesQqVfyRITGQN+dFuoivO0hnro1DjT74wXLRZ7QF8MIbz+luGaJA=="],
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.40.0", "", { "os": "android", "cpu": "arm64" }, "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-z9Ib+OzqN3DZEjX7PDQMHEhtF+t6Mi2z/ueChQPLS/qUMKY7Ybn5A2ggFoKRNRh1q1T03YTQfBTQCJZiepESAg=="],
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.40.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-PShKVY4u0FDAR7jskyFIYVyHEPCPnIQY8s5OcXkdU8mz3Y7eXDJPdyM/ZWjkYdR2m0izD9HHWA8sGcXn+Qrsyg=="],
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.40.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.6", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-YSwyOqlDAdKqs0iKuqvRHLN4SrD2TiswfoLfvYXseKbL47ht1grQpq46MSiQAx6rQEN8o8URtpXARCpqabqxGQ=="],
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.40.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-HEP4CgPAY1RxXwwL5sPFv6BBM3tVeLnshF03HMhJYCNc6kvSqBgTMmsEjb72RkZBAWIqiPUyF1JpEBv5XT9wKQ=="],
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.40.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.6", "", { "os": "linux", "cpu": "arm" }, "sha512-88fSzjC5xeH9S2Vg3rPgXJULkHcLYMkh8faix8DX4h4TIAL65ekwuQMA/g2CXq8W+NJC43V6fUpYZNjaX3+IIg=="],
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.40.0", "", { "os": "linux", "cpu": "arm" }, "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.6", "", { "os": "linux", "cpu": "arm" }, "sha512-wM4ztnutBqYFyvNeR7Av+reWI/enK9tDOTKNF+6Kk2Q96k9bwhDDOlnCUNRPvromlVXo04riSliMBs/Z7RteEg=="],
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.40.0", "", { "os": "linux", "cpu": "arm" }, "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-9RyprECbRa9zEjXLtvvshhw4CMrRa3K+0wcp3KME0zmBe1ILmvcVHnypZ/aIDXpRyfhSYSuN4EPdCCj5Du8FIA=="],
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.40.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-qTmklhCTyaJSB05S+iSovfo++EwnIEZxHkzv5dep4qoszUMX5Ca4WM4zAVUMbfdviLgCSQOu5oU8YoGk1s6M9Q=="],
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.40.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ=="],
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.6", "", { "os": "linux", "cpu": "none" }, "sha512-4Qmkaps9yqmpjY5pvpkfOerYgKNUGzQpFxV6rnS7c/JfYbDSU0y6WpbbredB5cCpLFGJEqYX40WUmxMkwhWCjw=="],
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.40.0", "", { "os": "linux", "cpu": "none" }, "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg=="],
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.6", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Zsrtux3PuaxuBTX/zHdLaFmcofWGzaWW1scwLU3ZbW/X+hSsFbz9wDIp6XvnT7pzYRl9MezWqEqKy7ssmDEnuQ=="],
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.40.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.6", "", { "os": "linux", "cpu": "none" }, "sha512-aK+Zp+CRM55iPrlyKiU3/zyhgzWBxLVrw2mwiQSYJRobCURb781+XstzvA8Gkjg/hbdQFuDw44aUOxVQFycrAg=="],
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.40.0", "", { "os": "linux", "cpu": "none" }, "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.6", "", { "os": "linux", "cpu": "s390x" }, "sha512-WoKLVrY9ogmaYPXwTH326+ErlCIgMmsoRSx6bO+l68YgJnlOXhygDYSZe/qbUJCSiCiZAQ+tKm88NcWuUXqOzw=="],
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.40.0", "", { "os": "linux", "cpu": "none" }, "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.6", "", { "os": "linux", "cpu": "x64" }, "sha512-Sht4aFvmA4ToHd2vFzwMFaQCiYm2lDFho5rPcvPBT5pCdC+GwHG6CMch4GQfmWTQ1SwRKS0dhDYb54khSrjDWw=="],
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.40.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.6", "", { "os": "linux", "cpu": "x64" }, "sha512-zmmpOQh8vXc2QITsnCiODCDGXFC8LMi64+/oPpPx5qz3pqv0s6x46ps4xoycfUiVZps5PFn1gksZzo4RGTKT+A=="],
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.40.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-3/q1qUsO/tLqGBaD4uXsB6coVGB3usxw3qyeVb59aArCgedSF66MPdgRStUd7vbZOsko/CgVaY5fo2vkvPLWiA=="],
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.40.0", "", { "os": "linux", "cpu": "x64" }, "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-oLHxuyywc6efdKVTxvc0135zPrRdtYVjtVD5GUm55I3ODxhU/PwkQFD97z16Xzxa1Fz0AEe4W/2hzRtd+IfpOA=="],
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.40.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.6", "", { "os": "win32", "cpu": "x64" }, "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w=="],
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.40.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA=="],
|
||||
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.3", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "tailwindcss": "4.1.3" } }, "sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA=="],
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.40.0", "", { "os": "win32", "cpu": "x64" }, "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ=="],
|
||||
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.3", "@tailwindcss/oxide-darwin-arm64": "4.1.3", "@tailwindcss/oxide-darwin-x64": "4.1.3", "@tailwindcss/oxide-freebsd-x64": "4.1.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.3", "@tailwindcss/oxide-linux-arm64-musl": "4.1.3", "@tailwindcss/oxide-linux-x64-gnu": "4.1.3", "@tailwindcss/oxide-linux-x64-musl": "4.1.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.3", "@tailwindcss/oxide-win32-x64-msvc": "4.1.3" } }, "sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ=="],
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.4", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "tailwindcss": "4.1.4" } }, "sha512-MT5118zaiO6x6hNA04OWInuAiP1YISXql8Z+/Y8iisV5nuhM8VXlyhRuqc2PEviPszcXI66W44bCIk500Oolhw=="],
|
||||
|
||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.3", "", { "os": "android", "cpu": "arm64" }, "sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g=="],
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.4", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.4", "@tailwindcss/oxide-darwin-arm64": "4.1.4", "@tailwindcss/oxide-darwin-x64": "4.1.4", "@tailwindcss/oxide-freebsd-x64": "4.1.4", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.4", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.4", "@tailwindcss/oxide-linux-arm64-musl": "4.1.4", "@tailwindcss/oxide-linux-x64-gnu": "4.1.4", "@tailwindcss/oxide-linux-x64-musl": "4.1.4", "@tailwindcss/oxide-wasm32-wasi": "4.1.4", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.4", "@tailwindcss/oxide-win32-x64-msvc": "4.1.4" } }, "sha512-p5wOpXyOJx7mKh5MXh5oKk+kqcz8T+bA3z/5VWWeQwFrmuBItGwz8Y2CHk/sJ+dNb9B0nYFfn0rj/cKHZyjahQ=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw=="],
|
||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.4", "", { "os": "android", "cpu": "arm64" }, "sha512-xMMAe/SaCN/vHfQYui3fqaBDEXMu22BVwQ33veLc8ep+DNy7CWN52L+TTG9y1K397w9nkzv+Mw+mZWISiqhmlA=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg=="],
|
||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JGRj0SYFuDuAGilWFBlshcexev2hOKfNkoX+0QTksKYq2zgF9VY/vVMq9m8IObYnLna0Xlg+ytCi2FN2rOL0Sg=="],
|
||||
|
||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w=="],
|
||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-sdDeLNvs3cYeWsEJ4H1DvjOzaGios4QbBTNLVLVs0XQ0V95bffT3+scptzYGPMjm7xv4+qMhCDrkHwhnUySEzA=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.3", "", { "os": "linux", "cpu": "arm" }, "sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg=="],
|
||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-VHxAqxqdghM83HslPhRsNhHo91McsxRJaEnShJOMu8mHmEj9Ig7ToHJtDukkuLWLzLboh2XSjq/0zO6wgvykNA=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg=="],
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4", "", { "os": "linux", "cpu": "arm" }, "sha512-OTU/m/eV4gQKxy9r5acuesqaymyeSCnsx1cFto/I1WhPmi5HDxX1nkzb8KYBiwkHIGg7CTfo/AcGzoXAJBxLfg=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ=="],
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-hKlLNvbmUC6z5g/J4H+Zx7f7w15whSVImokLPmP6ff1QqTVE+TxUM9PGuNsjHvkvlHUtGTdDnOvGNSEUiXI1Ww=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA=="],
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw=="],
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.4", "", { "os": "linux", "cpu": "x64" }, "sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg=="],
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.4", "", { "os": "linux", "cpu": "x64" }, "sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.3", "", { "os": "win32", "cpu": "x64" }, "sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA=="],
|
||||
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.4", "", { "dependencies": { "@emnapi/core": "^1.4.0", "@emnapi/runtime": "^1.4.0", "@emnapi/wasi-threads": "^1.0.1", "@napi-rs/wasm-runtime": "^0.2.8", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q=="],
|
||||
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.3", "", { "dependencies": { "@tailwindcss/node": "4.1.3", "@tailwindcss/oxide": "4.1.3", "tailwindcss": "4.1.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-lUI/QaDxLtlV52Lho6pu07CG9pSnRYLOPmKGIQjyHdTBagemc6HmgZxyjGAQ/5HMPrNeWBfTVIpQl0/jLXvWHQ=="],
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-VlnhfilPlO0ltxW9/BgfLI5547PYzqBMPIzRrk4W7uupgCt8z6Trw/tAj6QUtF2om+1MH281Pg+HHUJoLesmng=="],
|
||||
|
||||
"@tauri-apps/api": ["@tauri-apps/api@2.4.1", "", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="],
|
||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+7S63t5zhYjslUGb8NcgLpFXD+Kq1F/zt5Xv5qTv7HaFTG/DHyHD9GA6ieNAxhgyA4IcKa/zy7Xx4Oad2/wuhw=="],
|
||||
|
||||
"@tauri-apps/cli": ["@tauri-apps/cli@2.4.1", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.4.1", "@tauri-apps/cli-darwin-x64": "2.4.1", "@tauri-apps/cli-linux-arm-gnueabihf": "2.4.1", "@tauri-apps/cli-linux-arm64-gnu": "2.4.1", "@tauri-apps/cli-linux-arm64-musl": "2.4.1", "@tauri-apps/cli-linux-riscv64-gnu": "2.4.1", "@tauri-apps/cli-linux-x64-gnu": "2.4.1", "@tauri-apps/cli-linux-x64-musl": "2.4.1", "@tauri-apps/cli-win32-arm64-msvc": "2.4.1", "@tauri-apps/cli-win32-ia32-msvc": "2.4.1", "@tauri-apps/cli-win32-x64-msvc": "2.4.1" }, "bin": { "tauri": "tauri.js" } }, "sha512-9Ta81jx9+57FhtU/mPIckDcOBtPTUdKM75t4+aA0X84b8Sclb0jy1xA8NplmcRzp2fsfIHNngU2NiRxsW5+yOQ=="],
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.4", "", { "dependencies": { "@tailwindcss/node": "4.1.4", "@tailwindcss/oxide": "4.1.4", "tailwindcss": "4.1.4" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-4UQeMrONbvrsXKXXp/uxmdEN5JIJ9RkH7YVzs6AMxC/KC1+Np7WZBaNIco7TEjlkthqxZbt8pU/ipD+hKjm80A=="],
|
||||
|
||||
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.4.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QME7s8XQwy3LWClTVlIlwXVSLKkeJ/z88pr917Mtn9spYOjnBfsgHAgGdmpWD3NfJxjg7CtLbhH49DxoFL+hLg=="],
|
||||
"@tauri-apps/api": ["@tauri-apps/api@2.5.0", "", {}, "sha512-Ldux4ip+HGAcPUmuLT8EIkk6yafl5vK0P0c0byzAKzxJh7vxelVtdPONjfgTm96PbN24yjZNESY8CKo8qniluA=="],
|
||||
|
||||
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.4.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/r89IcW6Ya1sEsFUEH7wLNruDTj7WmDWKGpPy7gATFtQr5JEY4heernqE82isjTUimnHZD8SCr0jA3NceI4ybw=="],
|
||||
"@tauri-apps/cli": ["@tauri-apps/cli@2.5.0", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.5.0", "@tauri-apps/cli-darwin-x64": "2.5.0", "@tauri-apps/cli-linux-arm-gnueabihf": "2.5.0", "@tauri-apps/cli-linux-arm64-gnu": "2.5.0", "@tauri-apps/cli-linux-arm64-musl": "2.5.0", "@tauri-apps/cli-linux-riscv64-gnu": "2.5.0", "@tauri-apps/cli-linux-x64-gnu": "2.5.0", "@tauri-apps/cli-linux-x64-musl": "2.5.0", "@tauri-apps/cli-win32-arm64-msvc": "2.5.0", "@tauri-apps/cli-win32-ia32-msvc": "2.5.0", "@tauri-apps/cli-win32-x64-msvc": "2.5.0" }, "bin": { "tauri": "tauri.js" } }, "sha512-rAtHqG0Gh/IWLjN2zTf3nZqYqbo81oMbqop56rGTjrlWk9pTTAjkqOjSL9XQLIMZ3RbeVjveCqqCA0s8RnLdMg=="],
|
||||
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.4.1", "", { "os": "linux", "cpu": "arm" }, "sha512-9tDijkRB+CchAGjXxYdY9l/XzFpLp1yihUtGXJz9eh+3qIoRI043n3e+6xmU8ZURr7XPnu+R4sCmXs6HD+NCEQ=="],
|
||||
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.5.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VuVAeTFq86dfpoBDNYAdtQVLbP0+2EKCHIIhkaxjeoPARR0sLpFHz2zs0PcFU76e+KAaxtEtAJAXGNUc8E1PzQ=="],
|
||||
|
||||
"@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.4.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-pnFGDEXBAzS4iDYAVxTRhAzNu3K2XPGflYyBc0czfHDBXopqRgMyj5Q9Wj7HAwv6cM8BqzXINxnb2ZJFGmbSgA=="],
|
||||
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.5.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-hUF01sC06cZVa8+I0/VtsHOk9BbO75rd+YdtHJ48xTdcYaQ5QIwL4yZz9OR1AKBTaUYhBam8UX9Pvd5V2/4Dpw=="],
|
||||
|
||||
"@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.4.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Hp0zXgeZNKmT+eoJSCxSBUm2QndNuRxR55tmIeNm3vbyUMJN/49uW7nurZ5fBPsacN4Pzwlx1dIMK+Gnr9A69w=="],
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.5.0", "", { "os": "linux", "cpu": "arm" }, "sha512-LQKqttsK252LlqYyX8R02MinUsfFcy3+NZiJwHFgi5Y3+ZUIAED9cSxJkyNtuY5KMnR4RlpgWyLv4P6akN1xhg=="],
|
||||
|
||||
"@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.4.1", "", { "os": "linux", "cpu": "none" }, "sha512-3T3bo2E4fdYRvzcXheWUeQOVB+LunEEi92iPRgOyuSVexVE4cmHYl+MPJF+EUV28Et0hIVTsHibmDO0/04lAFg=="],
|
||||
"@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.5.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-mTQufsPcpdHg5RW0zypazMo4L55EfeE5snTzrPqbLX4yCK2qalN7+rnP8O8GT06xhp6ElSP/Ku1M2MR297SByQ=="],
|
||||
|
||||
"@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.4.1", "", { "os": "linux", "cpu": "x64" }, "sha512-kLN0FdNONO+2i+OpU9+mm6oTGufRC00e197TtwjpC0N6K2K8130w7Q3FeODIM2CMyg0ov3tH+QWqKW7GNhHFzg=="],
|
||||
"@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.5.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-rQO1HhRUQqyEaal5dUVOQruTRda/TD36s9kv1hTxZiFuSq3558lsTjAcUEnMAtBcBkps20sbyTJNMT0AwYIk8Q=="],
|
||||
|
||||
"@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.4.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a8exvA5Ub9eg66a6hsMQKJIkf63QAf9OdiuFKOsEnKZkNN2x0NLgfvEcqdw88VY0UMs9dBoZ1AGbWMeYnLrLwQ=="],
|
||||
"@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.5.0", "", { "os": "linux", "cpu": "none" }, "sha512-7oS18FN46yDxyw1zX/AxhLAd7T3GrLj3Ai6s8hZKd9qFVzrAn36ESL7d3G05s8wEtsJf26qjXnVF4qleS3dYsA=="],
|
||||
|
||||
"@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.4.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-4JFrslsMCJQG1c573T9uqQSAbF3j/tMKkMWzsIssv8jvPiP++OG61A2/F+y9te9/Q/O95cKhDK63kaiO5xQaeg=="],
|
||||
"@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.5.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SG5sFNL7VMmDBdIg3nO3EzNRT306HsiEQ0N90ILe3ZABYAVoPDO/ttpCO37ApLInTzrq/DLN+gOlC/mgZvLw1w=="],
|
||||
|
||||
"@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.4.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-9eXfFORehYSCRwxg2KodfmX/mhr50CI7wyBYGbPLePCjr5z0jK/9IyW6r0tC+ZVjwpX48dkk7hKiUgI25jHjzA=="],
|
||||
"@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.5.0", "", { "os": "linux", "cpu": "x64" }, "sha512-QXDM8zp/6v05PNWju5ELsVwF0VH1n6b5pk2E6W/jFbbiwz80Vs1lACl9pv5kEHkrxBj+aWU/03JzGuIj2g3SkQ=="],
|
||||
|
||||
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.4.1", "", { "os": "win32", "cpu": "x64" }, "sha512-60a4Ov7Jrwqz2hzDltlS7301dhSAmM9dxo+IRBD3xz7yobKrgaHXYpWvnRomYItHcDd51VaKc9292H8/eE/gsw=="],
|
||||
"@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.5.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-pFSHFK6b+o9y4Un8w0gGLwVyFTZaC3P0kQ7umRt/BLDkzD5RnQ4vBM7CF8BCU5nkwmEBUCZd7Wt3TWZxe41o6Q=="],
|
||||
|
||||
"@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.5.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-EArv1IaRlogdLAQyGlKmEqZqm5RfHCUMhJoedWu7GtdbOMUfSAz6FMX2boE1PtEmNO4An+g188flLeVErrxEKg=="],
|
||||
|
||||
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.5.0", "", { "os": "win32", "cpu": "x64" }, "sha512-lj43EFYbnAta8pd9JnUq87o+xRUR0odz+4rixBtTUwUgdRdwQ2V9CzFtsMu6FQKpFQ6mujRK6P1IEwhL6ADRsQ=="],
|
||||
|
||||
"@tauri-apps/plugin-cli": ["@tauri-apps/plugin-cli@2.2.0", "", { "dependencies": { "@tauri-apps/api": "^2.0.0" } }, "sha512-rvNhMog9rHr01Xk+trBFKJ0eZICIvPkm9GX6ogB89/0hROU/lf+a/sb4vC0wtSeR7zrJuCSxwxYuvHCZheaYFA=="],
|
||||
|
||||
@ -287,7 +298,7 @@
|
||||
|
||||
"@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.2.1", "", { "dependencies": { "@tauri-apps/api": "^2.0.0" } }, "sha512-G1GFYyWe/KlCsymuLiNImUgC8zGY0tI0Y3p8JgBCWduR5IEXlIJS+JuG1qtveitwYXlfJrsExt3enhv5l2/yhA=="],
|
||||
|
||||
"@tauri-apps/plugin-updater": ["@tauri-apps/plugin-updater@2.7.0", "", { "dependencies": { "@tauri-apps/api": "^2.0.0" } }, "sha512-oBug5UCH2wOsoYk0LW5LEMAT51mszjg11s8eungRH26x/qOrEjLvnuJJoxVVr9nsWowJ6vnpXKS+lUMfFTlvHQ=="],
|
||||
"@tauri-apps/plugin-updater": ["@tauri-apps/plugin-updater@2.7.1", "", { "dependencies": { "@tauri-apps/api": "^2.0.0" } }, "sha512-1OPqEY/z7NDVSeTEMIhD2ss/vXWdpfZ5Th2Mk0KtPR/RA6FKuOTDGZQhxoyYBk0pcZJ+nNZUbl/IujDCLBApjA=="],
|
||||
|
||||
"@trivago/prettier-plugin-sort-imports": ["@trivago/prettier-plugin-sort-imports@5.2.2", "", { "dependencies": { "@babel/generator": "^7.26.5", "@babel/parser": "^7.26.7", "@babel/traverse": "^7.26.7", "@babel/types": "^7.26.7", "javascript-natural-sort": "^0.7.1", "lodash": "^4.17.21" }, "peerDependencies": { "@vue/compiler-sfc": "3.x", "prettier": "2.x - 3.x", "prettier-plugin-svelte": "3.x", "svelte": "4.x || 5.x" }, "optionalPeers": ["@vue/compiler-sfc", "prettier-plugin-svelte", "svelte"] }, "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA=="],
|
||||
|
||||
@ -461,6 +472,8 @@
|
||||
|
||||
"fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="],
|
||||
|
||||
"fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
|
||||
|
||||
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
@ -653,7 +666,7 @@
|
||||
|
||||
"roboto-fontface": ["roboto-fontface@0.10.0", "", {}, "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g=="],
|
||||
|
||||
"rollup": ["rollup@4.34.6", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.6", "@rollup/rollup-android-arm64": "4.34.6", "@rollup/rollup-darwin-arm64": "4.34.6", "@rollup/rollup-darwin-x64": "4.34.6", "@rollup/rollup-freebsd-arm64": "4.34.6", "@rollup/rollup-freebsd-x64": "4.34.6", "@rollup/rollup-linux-arm-gnueabihf": "4.34.6", "@rollup/rollup-linux-arm-musleabihf": "4.34.6", "@rollup/rollup-linux-arm64-gnu": "4.34.6", "@rollup/rollup-linux-arm64-musl": "4.34.6", "@rollup/rollup-linux-loongarch64-gnu": "4.34.6", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.6", "@rollup/rollup-linux-riscv64-gnu": "4.34.6", "@rollup/rollup-linux-s390x-gnu": "4.34.6", "@rollup/rollup-linux-x64-gnu": "4.34.6", "@rollup/rollup-linux-x64-musl": "4.34.6", "@rollup/rollup-win32-arm64-msvc": "4.34.6", "@rollup/rollup-win32-ia32-msvc": "4.34.6", "@rollup/rollup-win32-x64-msvc": "4.34.6", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ=="],
|
||||
"rollup": ["rollup@4.40.0", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.0", "@rollup/rollup-android-arm64": "4.40.0", "@rollup/rollup-darwin-arm64": "4.40.0", "@rollup/rollup-darwin-x64": "4.40.0", "@rollup/rollup-freebsd-arm64": "4.40.0", "@rollup/rollup-freebsd-x64": "4.40.0", "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", "@rollup/rollup-linux-arm-musleabihf": "4.40.0", "@rollup/rollup-linux-arm64-gnu": "4.40.0", "@rollup/rollup-linux-arm64-musl": "4.40.0", "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", "@rollup/rollup-linux-riscv64-gnu": "4.40.0", "@rollup/rollup-linux-riscv64-musl": "4.40.0", "@rollup/rollup-linux-s390x-gnu": "4.40.0", "@rollup/rollup-linux-x64-gnu": "4.40.0", "@rollup/rollup-linux-x64-musl": "4.40.0", "@rollup/rollup-win32-arm64-msvc": "4.40.0", "@rollup/rollup-win32-ia32-msvc": "4.40.0", "@rollup/rollup-win32-x64-msvc": "4.40.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
@ -661,47 +674,47 @@
|
||||
|
||||
"sass": ["sass@1.77.8", "", { "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" } }, "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ=="],
|
||||
|
||||
"sass-embedded": ["sass-embedded@1.86.3", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-android-arm": "1.86.3", "sass-embedded-android-arm64": "1.86.3", "sass-embedded-android-ia32": "1.86.3", "sass-embedded-android-riscv64": "1.86.3", "sass-embedded-android-x64": "1.86.3", "sass-embedded-darwin-arm64": "1.86.3", "sass-embedded-darwin-x64": "1.86.3", "sass-embedded-linux-arm": "1.86.3", "sass-embedded-linux-arm64": "1.86.3", "sass-embedded-linux-ia32": "1.86.3", "sass-embedded-linux-musl-arm": "1.86.3", "sass-embedded-linux-musl-arm64": "1.86.3", "sass-embedded-linux-musl-ia32": "1.86.3", "sass-embedded-linux-musl-riscv64": "1.86.3", "sass-embedded-linux-musl-x64": "1.86.3", "sass-embedded-linux-riscv64": "1.86.3", "sass-embedded-linux-x64": "1.86.3", "sass-embedded-win32-arm64": "1.86.3", "sass-embedded-win32-ia32": "1.86.3", "sass-embedded-win32-x64": "1.86.3" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-3pZSp24ibO1hdopj+W9DuiWsZOb2YY6AFRo/jjutKLBkqJGM1nJjXzhAYfzRV+Xn5BX1eTI4bBTE09P0XNHOZg=="],
|
||||
"sass-embedded": ["sass-embedded@1.87.0", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-android-arm": "1.87.0", "sass-embedded-android-arm64": "1.87.0", "sass-embedded-android-ia32": "1.87.0", "sass-embedded-android-riscv64": "1.87.0", "sass-embedded-android-x64": "1.87.0", "sass-embedded-darwin-arm64": "1.87.0", "sass-embedded-darwin-x64": "1.87.0", "sass-embedded-linux-arm": "1.87.0", "sass-embedded-linux-arm64": "1.87.0", "sass-embedded-linux-ia32": "1.87.0", "sass-embedded-linux-musl-arm": "1.87.0", "sass-embedded-linux-musl-arm64": "1.87.0", "sass-embedded-linux-musl-ia32": "1.87.0", "sass-embedded-linux-musl-riscv64": "1.87.0", "sass-embedded-linux-musl-x64": "1.87.0", "sass-embedded-linux-riscv64": "1.87.0", "sass-embedded-linux-x64": "1.87.0", "sass-embedded-win32-arm64": "1.87.0", "sass-embedded-win32-ia32": "1.87.0", "sass-embedded-win32-x64": "1.87.0" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-1IA3iTJNh4BkkA/nidKiVwbmkxr9o6LsPegycHMX/JYs255zpocN5GdLF1+onohQCJxbs5ldr8osKV7qNaNBjg=="],
|
||||
|
||||
"sass-embedded-android-arm": ["sass-embedded-android-arm@1.86.3", "", { "os": "android", "cpu": "arm" }, "sha512-UyeXrFzZSvrGbvrWUBcspbsbivGgAgebLGJdSqJulgSyGbA6no3DWQ5Qpdd6+OAUC39BlpPu74Wx9s4RrVuaFw=="],
|
||||
"sass-embedded-android-arm": ["sass-embedded-android-arm@1.87.0", "", { "os": "android", "cpu": "arm" }, "sha512-Z20u/Y1kFDpMbgiloR5YPLxNuMVeKQRC8e/n68oAAxf3u7rDSmNn2msi7USqgT1f2zdBBNawn/ifbFEla6JiHw=="],
|
||||
|
||||
"sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.86.3", "", { "os": "android", "cpu": "arm64" }, "sha512-q+XwFp6WgAv+UgnQhsB8KQ95kppvWAB7DSoJp+8Vino8b9ND+1ai3cUUZPE5u4SnLZrgo5NtrbPvN5KLc4Pfyg=="],
|
||||
"sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.87.0", "", { "os": "android", "cpu": "arm64" }, "sha512-uqeZoBuXm3W2KhxolScAAfWOLHL21e50g7AxlLmG0he7WZsWw6e9kSnmq301iLIFp4kvmXYXbXbNKAeu9ItRYA=="],
|
||||
|
||||
"sass-embedded-android-ia32": ["sass-embedded-android-ia32@1.86.3", "", { "os": "android", "cpu": "ia32" }, "sha512-gTJjVh2cRzvGujXj5ApPk/owUTL5SiO7rDtNLrzYAzi1N5HRuLYXqk3h1IQY3+eCOBjGl7mQ9XyySbJs/3hDvg=="],
|
||||
"sass-embedded-android-ia32": ["sass-embedded-android-ia32@1.87.0", "", { "os": "android", "cpu": "ia32" }, "sha512-hSWTqo2Igdig528cUb1W1+emw9d1J4+nqOoR4tERS04zcwRRFNDiuBT0o5meV7nkEwE982F+h57YdcRXj8gTtg=="],
|
||||
|
||||
"sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.86.3", "", { "os": "android", "cpu": "none" }, "sha512-Po3JnyiCS16kd6REo1IMUbFGYtvL9O0rmKaXx5vOuBaJD1LPy2LiSSp7TU7wkJ9IxsTDGzFaSeP1I9qb6D8VVg=="],
|
||||
"sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.87.0", "", { "os": "android", "cpu": "none" }, "sha512-kBAPSjiTBLy5ua/0LRNAJwOAARhzFU7gP35fYORJcdBuz1lkIVPVnid1lh9qQ6Ce9MOJcr7VKFtGnTuqVeig5A=="],
|
||||
|
||||
"sass-embedded-android-x64": ["sass-embedded-android-x64@1.86.3", "", { "os": "android", "cpu": "x64" }, "sha512-+7h3jdDv/0kUFx0BvxYlq2fa7CcHiDPlta6k5OxO5K6jyqJwo9hc0Z052BoYEauWTqZ+vK6bB5rv2BIzq4U9nA=="],
|
||||
"sass-embedded-android-x64": ["sass-embedded-android-x64@1.87.0", "", { "os": "android", "cpu": "x64" }, "sha512-ZHMrNdtdMSpJUYco2MesnlPwDTZftD3pqkkOMI2pbqarPoFUKJtP5k80nwCM0sJGtqfNE+O16w9yPght0CMiJg=="],
|
||||
|
||||
"sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.86.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EgLwV4ORm5Hr0DmIXo0Xw/vlzwLnfAiqD2jDXIglkBsc5czJmo4/IBdGXOP65TRnsgJEqvbU3aQhuawX5++x9A=="],
|
||||
"sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.87.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7TK1JWJdCIRSdZv5CJv/HpDz/wIfwUy2FoPz9sVOEj1pDTH0N+VfJd5VutCddIdoQN9jr0ap8vwkc65FbAxV2A=="],
|
||||
|
||||
"sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.86.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-dfKhfrGPRNLWLC82vy/vQGmNKmAiKWpdFuWiePRtg/E95pqw+sCu6080Y6oQLfFu37Iq3MpnXiSpDuSo7UnPWA=="],
|
||||
"sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.87.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-2JiQzt7FmgUC4MYT2QvbeH/Bi3e76WEhaYoc5P3WyTW8unsHksyTdMuTuYe0Qf9usIyt6bmm5no/4BBw7c8Cig=="],
|
||||
|
||||
"sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.86.3", "", { "os": "linux", "cpu": "arm" }, "sha512-+fVCIH+OR0SMHn2NEhb/VfbpHuUxcPtqMS34OCV3Ka99LYZUJZqth4M3lT/ppGl52mwIVLNYzR4iLe6mdZ6mYA=="],
|
||||
"sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.87.0", "", { "os": "linux", "cpu": "arm" }, "sha512-z5P6INMsGXiUcq1sRRbksyQUhalFFYjTEexuxfSYdK3U2YQMADHubQh8pGzkWvFRPOpnh83RiGuwvpaARYHnsw=="],
|
||||
|
||||
"sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.86.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-tYq5rywR53Qtc+0KI6pPipOvW7a47ETY69VxfqI9BR2RKw2hBbaz0bIw6OaOgEBv2/XNwcWb7a4sr7TqgkqKAA=="],
|
||||
"sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.87.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-5z+mwJCbGZcg+q+MwdEVSh0ogFK7OSAe175Gsozzr/Izw34Q+RGUw9O82jsV2c4YNuTAQvzEHgIO5cvNvt3Quw=="],
|
||||
|
||||
"sass-embedded-linux-ia32": ["sass-embedded-linux-ia32@1.86.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-CmQ5OkqnaeLdaF+bMqlYGooBuenqm3LvEN9H8BLhjkpWiFW8hnYMetiqMcJjhrXLvDw601KGqA5sr/Rsg5s45g=="],
|
||||
"sass-embedded-linux-ia32": ["sass-embedded-linux-ia32@1.87.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-Xzcp+YPp0iakGL148Jl57CO+MxLuj2jsry3M+rc1cSnDlvkjNVs6TMxaL70GFeV5HdU2V60voYcgE7adDUtJjw=="],
|
||||
|
||||
"sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.86.3", "", { "os": "linux", "cpu": "arm" }, "sha512-SEm65SQknI4pl+mH5Xf231hOkHJyrlgh5nj4qDbiBG6gFeutaNkNIeRgKEg3cflXchCr8iV/q/SyPgjhhzQb7w=="],
|
||||
"sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.87.0", "", { "os": "linux", "cpu": "arm" }, "sha512-4PyqOWhRzyu06RRmpCCBOJdF4BOv7s446wrV6yODtEyyfSIDx3MJabo3KT0oJ1lTWSI/aU3R89bKx0JFXcIHHw=="],
|
||||
|
||||
"sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.86.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-4zOr2C/eW89rxb4ozTfn7lBzyyM5ZigA1ZSRTcAR26Qbg/t2UksLdGnVX9/yxga0d6aOi0IvO/7iM2DPPRRotg=="],
|
||||
"sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.87.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-HWE5eTRCoKzFZWsxOjDMTF5m4DDTQ0n7NJxSYiUXPBDydr9viPXbGOMYG7WVJLjiF7upr7DYo/mfp/SNTMlZyg=="],
|
||||
|
||||
"sass-embedded-linux-musl-ia32": ["sass-embedded-linux-musl-ia32@1.86.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-84Tcld32LB1loiqUvczWyVBQRCChm0wNLlkT59qF29nxh8njFIVf9yaPgXcSyyjpPoD9Tu0wnq3dvVzoMCh9AQ=="],
|
||||
"sass-embedded-linux-musl-ia32": ["sass-embedded-linux-musl-ia32@1.87.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-aQaPvlRn3kh93PLQvl6BcFKu8Ji92+42blFEkg6nMVvmugD5ZwH2TGFrX25ibx4CYxRpMS4ssF7a0i7vy5HB1Q=="],
|
||||
|
||||
"sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.86.3", "", { "os": "linux", "cpu": "none" }, "sha512-IxEqoiD7vdNpiOwccybbV93NljBy64wSTkUOknGy21SyV43C8uqESOwTwW9ywa3KufImKm8L3uQAW/B0KhJMWg=="],
|
||||
"sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.87.0", "", { "os": "linux", "cpu": "none" }, "sha512-o5DxcqiFzET3KRWo+futHr/lhAMBP3tJGGx8YIgpHQYfvDMbsvE0hiFC+nZ/GF9dbcGd+ceIQwfvE5mcc7Gsjw=="],
|
||||
|
||||
"sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.86.3", "", { "os": "linux", "cpu": "x64" }, "sha512-ePeTPXUxPK6JgHcUfnrkIyDtyt+zlAvF22mVZv6y1g/PZFm1lSfX+Za7TYHg9KaYqaaXDiw6zICX4i44HhR8rA=="],
|
||||
"sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.87.0", "", { "os": "linux", "cpu": "x64" }, "sha512-dKxWsu9Wu/CyfzQmHdeiGqrRSzJ85VUjbSx+aP1/7ttmps3SSg+YW95PuqnCOa7GSuSreC3dKKpXHTywUxMLQA=="],
|
||||
|
||||
"sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.86.3", "", { "os": "linux", "cpu": "none" }, "sha512-NuXQ72dwfNLe35E+RaXJ4Noq4EkFwM65eWwCwxEWyJO9qxOx1EXiCAJii6x8kkOh5daWuMU0VAI1B9RsJaqqQQ=="],
|
||||
"sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.87.0", "", { "os": "linux", "cpu": "none" }, "sha512-Sy3ESZ4FwBiijvmTA9n+0p0w3MNCue1AgINVPzpAY27EFi0h49eqQm9SWfOkFqmkFS2zFRYowdQOr5Bbr2gOXA=="],
|
||||
|
||||
"sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.86.3", "", { "os": "linux", "cpu": "x64" }, "sha512-t8be9zJ5B82+og9bQmIQ83yMGYZMTMrlGA+uGWtYacmwg6w3093dk91Fx0YzNSZBp3Tk60qVYjCZnEIwy60x0g=="],
|
||||
"sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.87.0", "", { "os": "linux", "cpu": "x64" }, "sha512-+UfjakOcHHKTnEqB3EZ+KqzezQOe1emvy4Rs+eQhLyfekpYuNze/qlRvYxfKTmrtvDiUrIto8MXsyZfMLzkuMA=="],
|
||||
|
||||
"sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.86.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-4ghuAzjX4q8Nksm0aifRz8hgXMMxS0SuymrFfkfJlrSx68pIgvAge6AOw0edoZoe0Tf5ZbsWUWamhkNyNxkTvw=="],
|
||||
"sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.87.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-m1DS6FYUE0/fv+vt38uQB/kxR4UjnyD+2zcSc298pFmA0aYh/XZIPWw7RxG1HL3KLE1ZrGyu3254MPoxRhs3ig=="],
|
||||
|
||||
"sass-embedded-win32-ia32": ["sass-embedded-win32-ia32@1.86.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-tCaK4zIRq9mLRPxLzBAdYlfCuS/xLNpmjunYxeWkIwlJo+k53h1udyXH/FInnQ2GgEz0xMXyvH3buuPgzwWYsw=="],
|
||||
"sass-embedded-win32-ia32": ["sass-embedded-win32-ia32@1.87.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-JztXLo59GMe2E6g+kCsyiERYhtZgkcyDYx6CrXoSTE5WaE+RbxRiCCCv8/1+hf406f08pUxJ8G0Ody7M5urtBA=="],
|
||||
|
||||
"sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.86.3", "", { "os": "win32", "cpu": "x64" }, "sha512-zS+YNKfTF4SnOfpC77VTb0qNZyTXrxnAezSoRV0xnw6HlY+1WawMSSB6PbWtmbvyfXNgpmJUttoTtsvJjRCucg=="],
|
||||
"sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.87.0", "", { "os": "win32", "cpu": "x64" }, "sha512-4nQErpauvhgSo+7ClumGdjdf9sGx+U9yBgvhI0+zUw+D5YvraVgvA0Lk8Wuwntx2PqnvKUk8YDr/vxHJostv4Q=="],
|
||||
|
||||
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
|
||||
|
||||
@ -725,12 +738,14 @@
|
||||
|
||||
"sync-message-port": ["sync-message-port@1.1.3", "", {}, "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="],
|
||||
"tailwindcss": ["tailwindcss@4.1.4", "", {}, "sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A=="],
|
||||
|
||||
"tailwindcss-primeui": ["tailwindcss-primeui@0.4.0", "", { "peerDependencies": { "tailwindcss": ">=3.1.0" } }, "sha512-YYC7B7Yyzm1/4pEGgpf1ABAhbrKY++LuPoUamnKE7fTPO5Ct/Qr/dT+Uq2yiVhQnaW1zHQpYnThxfksaxhlDfQ=="],
|
||||
|
||||
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
|
||||
@ -765,7 +780,7 @@
|
||||
|
||||
"varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="],
|
||||
|
||||
"vite": ["vite@6.2.6", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw=="],
|
||||
"vite": ["vite@6.3.2", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.3", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.12" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg=="],
|
||||
|
||||
"vite-plugin-vuetify": ["vite-plugin-vuetify@2.1.1", "", { "dependencies": { "@vuetify/loader-shared": "^2.1.0", "debug": "^4.3.3", "upath": "^2.0.1" }, "peerDependencies": { "vite": ">=5", "vue": "^3.0.0", "vuetify": "^3.0.0" } }, "sha512-Pb7bKhQH8qPMzURmEGq2aIqCJkruFNsyf1NcrrtnjsOIkqJPMcBbiP0oJoO8/uAmyB5W/1JTbbUEsyXdMM0QHQ=="],
|
||||
|
||||
@ -775,9 +790,11 @@
|
||||
|
||||
"vue-eslint-parser": ["vue-eslint-parser@10.1.2", "", { "dependencies": { "debug": "^4.4.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.6.0", "lodash": "^4.17.21", "semver": "^7.6.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-1guOfYgNlD7JH2popr/bt5vc7Mzt6quRCnEbqLgpMHvoHEGV1oImzdqrLd+oMD76cHt8ilBP4cda9WA72TLFDQ=="],
|
||||
|
||||
"vue-i18n": ["vue-i18n@11.1.3", "", { "dependencies": { "@intlify/core-base": "11.1.3", "@intlify/shared": "11.1.3", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-Pcylh9z9S5+CJAqgbRZ3EKxFIBIrtY5YUppU722GIT65+Nukm0TCqiQegZnNLCZkXGthxe0cpqj0AoM51H+6Gw=="],
|
||||
|
||||
"vue-tsc": ["vue-tsc@2.2.8", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.8" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ=="],
|
||||
|
||||
"vuetify": ["vuetify@3.8.1", "", { "peerDependencies": { "typescript": ">=4.7", "vite-plugin-vuetify": ">=2.1.0", "vue": "^3.5.0", "webpack-plugin-vuetify": ">=3.1.0" }, "optionalPeers": ["typescript", "vite-plugin-vuetify", "webpack-plugin-vuetify"] }, "sha512-3qReKBBWIIdJJmwnFU1blVIKHDtnLfIP7kk0MwUrrfjYkWmsDpsymtDnsukkTCnlJ1WvhLr64eQFosr0RVbj9w=="],
|
||||
"vuetify": ["vuetify@3.8.2", "", { "peerDependencies": { "typescript": ">=4.7", "vite-plugin-vuetify": ">=2.1.0", "vue": "^3.5.0", "webpack-plugin-vuetify": ">=3.1.0" }, "optionalPeers": ["typescript", "vite-plugin-vuetify", "webpack-plugin-vuetify"] }, "sha512-UJNFP4egmKJTQ3V3MKOq+7vIUKO7/Fko5G6yUsOW2Rm0VNBvAjgO6VY6EnK3DTqEKN6ugVXDEPw37NQSTGLZvw=="],
|
||||
|
||||
"webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
|
||||
|
||||
@ -805,8 +822,30 @@
|
||||
|
||||
"@primeuix/forms/@primeuix/utils": ["@primeuix/utils@0.4.1", "", {}, "sha512-5+1NLfyna+gLRPeFTo+xlR0tfPVLuVdidbeahAMLkQga5Rw0LxyUBCyD2/Zv2JkV69o2T+hpEDyddl3VdnYoBw=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.9", "", { "dependencies": { "@emnapi/core": "^1.4.0", "@emnapi/runtime": "^1.4.0", "@tybys/wasm-util": "^0.9.0" }, "bundled": true }, "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tauri-apps/plugin-cli/@tauri-apps/api": ["@tauri-apps/api@2.4.1", "", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="],
|
||||
|
||||
"@tauri-apps/plugin-deep-link/@tauri-apps/api": ["@tauri-apps/api@2.4.1", "", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="],
|
||||
|
||||
"@tauri-apps/plugin-dialog/@tauri-apps/api": ["@tauri-apps/api@2.4.1", "", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="],
|
||||
|
||||
"@tauri-apps/plugin-fs/@tauri-apps/api": ["@tauri-apps/api@2.4.1", "", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="],
|
||||
|
||||
"@tauri-apps/plugin-opener/@tauri-apps/api": ["@tauri-apps/api@2.3.0", "", {}, "sha512-33Z+0lX2wgZbx1SPFfqvzI6su63hCBkbzv+5NexeYjIx7WA9htdOKoRR7Dh3dJyltqS5/J8vQFyybiRoaL0hlA=="],
|
||||
|
||||
"@tauri-apps/plugin-shell/@tauri-apps/api": ["@tauri-apps/api@2.4.1", "", {}, "sha512-5sYwZCSJb6PBGbBL4kt7CnE5HHbBqwH+ovmOW6ZVju3nX4E3JX6tt2kRklFEH7xMOIwR0btRkZktuLhKvyEQYg=="],
|
||||
|
||||
"@vue/compiler-sfc/postcss": ["postcss@8.5.1", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ=="],
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
@ -829,14 +868,34 @@
|
||||
|
||||
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"rollup/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
||||
|
||||
"sass-embedded/immutable": ["immutable@5.0.3", "", {}, "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw=="],
|
||||
|
||||
"unplugin-vue-components/unplugin": ["unplugin@1.16.1", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w=="],
|
||||
|
||||
"vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"@eslint/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||
|
||||
"@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"eslint-plugin-vue/vue-eslint-parser/eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="],
|
||||
@ -846,5 +905,17 @@
|
||||
"eslint-plugin-vue/vue-eslint-parser/espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="],
|
||||
|
||||
"eslint/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
}
|
||||
}
|
||||
|
17
package.json
17
package.json
@ -14,15 +14,15 @@
|
||||
"@mdi/font": "7.4.47",
|
||||
"@primevue/forms": "^4.3.3",
|
||||
"@primevue/themes": "^4.3.3",
|
||||
"@tailwindcss/vite": "^4.1.3",
|
||||
"@tauri-apps/api": "^2.4.1",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"@tauri-apps/api": "^2.5.0",
|
||||
"@tauri-apps/plugin-cli": "^2.2.0",
|
||||
"@tauri-apps/plugin-deep-link": "~2.2.1",
|
||||
"@tauri-apps/plugin-dialog": "~2.2.1",
|
||||
"@tauri-apps/plugin-fs": "^2.2.1",
|
||||
"@tauri-apps/plugin-opener": "^2.2.6",
|
||||
"@tauri-apps/plugin-shell": "~2.2.1",
|
||||
"@tauri-apps/plugin-updater": "^2.7.0",
|
||||
"@tauri-apps/plugin-updater": "^2.7.1",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"markdown-it": "^14.1.0",
|
||||
@ -30,13 +30,14 @@
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.3.3",
|
||||
"roboto-fontface": "^0.10.0",
|
||||
"tailwindcss": "^4.1.3",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"tailwindcss-primeui": "^0.4.0",
|
||||
"vue": "^3.5.13",
|
||||
"vuetify": "^3.8.1"
|
||||
"vue-i18n": "^11.1.3",
|
||||
"vuetify": "^3.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.4.1",
|
||||
"@tauri-apps/cli": "^2.5.0",
|
||||
"@tsconfig/node22": "^22.0.1",
|
||||
"@types/node": "^22.14.1",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
@ -44,11 +45,11 @@
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"sass": "1.77.8",
|
||||
"sass-embedded": "^1.86.3",
|
||||
"sass-embedded": "^1.87.0",
|
||||
"typescript": "^5.8.3",
|
||||
"unplugin-fonts": "^1.3.1",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"vite": "^6.2.6",
|
||||
"vite": "^6.3.2",
|
||||
"vite-plugin-vuetify": "^2.1.1",
|
||||
"vue-tsc": "^2.2.8"
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
If you're stuck on this screen, restart the game.
|
||||
|
||||
If the problem persists, <a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ#game-is-stuck-at-checking-distribution-server" target="_blank">check your network configuration</a>
|
@ -1,8 +0,0 @@
|
||||
You can access this page any time by right-clicking the START button.
|
||||
|
||||
Additional resources:
|
||||
|
||||
- <a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ" target="_blank">SEGAguide</a>
|
||||
- <a href="https://two-torial.xyz/" target="_blank">two-torial</a>
|
||||
|
||||
## Have fun
|
@ -1,3 +0,0 @@
|
||||
You also have to calibrate the lever, or you may get the error 3301.
|
||||
|
||||
Go to lever settings (<span class="bg-black text-white">レバー設定</span>), move the lever to both edges, then press "end" (<span class="bg-black text-white">終了</span>) and "save" (<span class="bg-black text-white">保存する</span>).
|
@ -1,3 +0,0 @@
|
||||
You might get stuck on this screen for several minutes. _This is normal_. The game just takes a long time to load data.
|
||||
|
||||
If you install <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, subsequent launches will be much faster.
|
@ -1,7 +0,0 @@
|
||||
You might get stuck on the following screen:
|
||||
|
||||
<div class="p-2 mt-1 mb-1 bg-black text-white">Aグループの基準機から設定を取得</div>
|
||||
|
||||
In which case, you should go to the test menu, and in game settings <span class="bg-black text-white">ゲーム設定</span> switch from "follow the standard machine" <span class="bg-black text-white">基準機に従う</span> to "standard machine" <span class="bg-black text-white">基準機</span>.
|
||||
|
||||
The test menu can be accessed with %TESTMENU%.
|
BIN
public/no-icon.png
Normal file
BIN
public/no-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
370
rust/Cargo.lock
generated
370
rust/Cargo.lock
generated
@ -134,9 +134,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.97"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
@ -162,7 +162,7 @@ dependencies = [
|
||||
"enumflags2",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
@ -208,9 +208,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.22"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64"
|
||||
checksum = "b37fc50485c4f3f736a4fb14199f6d5f5ba008d7f28fe710306c92780f004c07"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"futures-core",
|
||||
@ -488,11 +488,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037"
|
||||
checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2"
|
||||
dependencies = [
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -521,9 +521,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.2"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
|
||||
checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@ -644,9 +644,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
version = "1.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@ -732,18 +732,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.35"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.35"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -1199,9 +1199,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a0d569e003ff27784e0e14e4a594048698e0c0f0b66cabcb51511be55a7caa0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"block2 0.6.0",
|
||||
"block2 0.6.1",
|
||||
"libc",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1995,9 +2005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.8"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
|
||||
checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
@ -2536,9 +2546,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.6"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
|
||||
checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
@ -2549,9 +2559,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.6"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
|
||||
checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2697,9 +2707,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -2770,12 +2780,6 @@ dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lockfree-object-pool"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
@ -2908,10 +2912,10 @@ dependencies = [
|
||||
"dpi",
|
||||
"gtk",
|
||||
"keyboard-types",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"once_cell",
|
||||
"png",
|
||||
"serde",
|
||||
@ -3056,9 +3060,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59"
|
||||
checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551"
|
||||
dependencies = [
|
||||
"objc2-encode",
|
||||
"objc2-exception-helper",
|
||||
@ -3066,75 +3070,77 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-app-kit"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb"
|
||||
checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"block2 0.6.0",
|
||||
"block2 0.6.1",
|
||||
"libc",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-cloud-kit",
|
||||
"objc2-core-data",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
"objc2-core-image",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-quartz-core 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"objc2-quartz-core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-cloud-kit"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c"
|
||||
checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-data"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4"
|
||||
checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"dispatch2 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-graphics"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02"
|
||||
checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"dispatch2 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-surface",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-image"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56"
|
||||
checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e"
|
||||
dependencies = [
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3166,25 +3172,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-foundation"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998"
|
||||
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"block2 0.6.0",
|
||||
"block2 0.6.1",
|
||||
"libc",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-io-surface"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19"
|
||||
checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
@ -3202,14 +3208,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-osa-kit"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1ac59da3ceebc4a82179b35dc550431ad9458f9cc326e053f49ba371ce76c5a"
|
||||
checksum = "26bb88504b5a050dbba515d2414607bf5e57dd56b107bc5f0351197a3e7bdc5d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3227,39 +3233,39 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-quartz-core"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071"
|
||||
checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-ui-kit"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1"
|
||||
checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-web-kit"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce"
|
||||
checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"block2 0.6.0",
|
||||
"objc2 0.6.0",
|
||||
"block2 0.6.1",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3375,8 +3381,8 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b"
|
||||
dependencies = [
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-foundation 0.3.1",
|
||||
"objc2-osa-kit",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -3810,9 +3816,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -3854,7 +3860,7 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.2",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
@ -3922,13 +3928,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4119,17 +4124,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80c844748fdc82aae252ee4594a89b6e7ebef1063de7951545564cbc4e57075d"
|
||||
dependencies = [
|
||||
"ashpd",
|
||||
"block2 0.6.0",
|
||||
"dispatch2",
|
||||
"block2 0.6.1",
|
||||
"dispatch2 0.2.0",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gtk-sys",
|
||||
"js-sys",
|
||||
"log",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"raw-window-handle",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
@ -4607,9 +4612,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@ -4918,9 +4923,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.32.8"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63c8b1020610b9138dd7b1e06cf259ae91aa05c30f3bd0d6b42a03997b92dec1"
|
||||
checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"core-foundation 0.10.0",
|
||||
@ -4939,9 +4944,9 @@ dependencies = [
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"ndk-sys",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"raw-window-handle",
|
||||
@ -4949,8 +4954,8 @@ dependencies = [
|
||||
"tao-macros",
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
"windows 0.61.1",
|
||||
"windows-core 0.61.0",
|
||||
"windows-version",
|
||||
"x11-dl",
|
||||
]
|
||||
@ -4985,9 +4990,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.4.1"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d08db1ff9e011e04014e737ec022610d756c0eae0b3b3a9037bccaf3003173a"
|
||||
checksum = "e7b0bc1aec81bda6bc455ea98fcaed26b3c98c1648c627ad6ff1c704e8bf8cbc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -5006,9 +5011,10 @@ dependencies = [
|
||||
"log",
|
||||
"mime",
|
||||
"muda",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"objc2-ui-kit",
|
||||
"percent-encoding",
|
||||
"plist",
|
||||
"raw-window-handle",
|
||||
@ -5031,14 +5037,14 @@ dependencies = [
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
"window-vibrancy",
|
||||
"windows",
|
||||
"windows 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.1.1"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fd20e4661c2cce65343319e6e8da256958f5af958cafc47c0d0af66a55dcd17"
|
||||
checksum = "d7a0350f0df1db385ca5c02888a83e0e66655c245b7443db8b78a70da7d7f8fc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@ -5058,9 +5064,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.1.1"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458258b19032450ccf975840116ecf013e539eadbb74420bd890e8c56ab2b1a4"
|
||||
checksum = "f93f035551bf7b11b3f51ad9bc231ebbe5e085565527991c16cf326aa38cdf47"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brotli",
|
||||
@ -5085,9 +5091,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.1.1"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d402813d3b9c773a0fa58697c457c771f10e735498fdcb7b343264d18e5a601f"
|
||||
checksum = "8db4df25e2d9d45de0c4c910da61cd5500190da14ae4830749fee3466dddd112"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@ -5099,9 +5105,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin"
|
||||
version = "2.1.1"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4190775d6ff73fe66d9af44c012739a2659720efd9c0e1e56a918678038699d"
|
||||
checksum = "37a5ebe6a610d1b78a94650896e6f7c9796323f408800cef436e0fa0539de601"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"glob",
|
||||
@ -5120,7 +5126,7 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5458ae16eac81bdbe8d9da2a9f3e01e8cdedbc381cc1727c01127542c8a61c5"
|
||||
dependencies = [
|
||||
"clap 4.5.35",
|
||||
"clap 4.5.37",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -5199,7 +5205,7 @@ dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"open",
|
||||
"schemars",
|
||||
"serde",
|
||||
@ -5208,7 +5214,7 @@ dependencies = [
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
"windows",
|
||||
"windows 0.60.0",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
@ -5251,9 +5257,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-updater"
|
||||
version = "2.7.0"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d82da763248e635d60ee4aed56c862290e523acc838d83097171f9a544708387"
|
||||
checksum = "73f05c38afd77a4b8fd98e8fb6f1cdbb5fbb8a46ba181eb2758b05321e3c6209"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"dirs",
|
||||
@ -5283,37 +5289,39 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.5.1"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00ada7ac2f9276f09b8c3afffd3215fd5d9bff23c22df8a7c70e7ef67cacd532"
|
||||
checksum = "00f004905d549854069e6774533d742b03cacfd6f03deb08940a8677586cbe39"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
"gtk",
|
||||
"http",
|
||||
"jni",
|
||||
"objc2 0.6.1",
|
||||
"objc2-ui-kit",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
"windows",
|
||||
"windows 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.5.1"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf2e5842c57e154af43a20a49c7efee0ce2578c20b4c2bdf266852b422d2e421"
|
||||
checksum = "f85d056f4d4b014fe874814034f3416d57114b617a493a4fe552580851a3f3a2"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
"jni",
|
||||
"log",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
@ -5324,15 +5332,15 @@ dependencies = [
|
||||
"url",
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
"windows",
|
||||
"windows 0.61.1",
|
||||
"wry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f037e66c7638cc0a2213f61566932b9a06882b8346486579c90e4b019bac447"
|
||||
checksum = "b2900399c239a471bcff7f15c4399eb1a8c4fe511ba2853e07c996d771a5e0a4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"brotli",
|
||||
@ -5731,19 +5739,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.20.0"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5"
|
||||
checksum = "9f7eee98ec5c90daf179d55c20a49d8c0d043054ce7c26336c09a24d31f14fa0"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dirs",
|
||||
"libappindicator",
|
||||
"muda",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"once_cell",
|
||||
"png",
|
||||
"serde",
|
||||
@ -6185,15 +6193,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.36.0"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0d606f600e5272b514dbb66539dd068211cc20155be8d3958201b4b5bd79ed3"
|
||||
checksum = "b542b5cfbd9618c46c2784e4d41ba218c336ac70d44c55e47b251033e7d85601"
|
||||
dependencies = [
|
||||
"webview2-com-macros",
|
||||
"webview2-com-sys",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
"windows-implement 0.59.0",
|
||||
"windows 0.61.1",
|
||||
"windows-core 0.61.0",
|
||||
"windows-implement 0.60.0",
|
||||
"windows-interface",
|
||||
]
|
||||
|
||||
@ -6210,13 +6218,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com-sys"
|
||||
version = "0.36.0"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac"
|
||||
checksum = "8ae2d11c4a686e4409659d7891791254cf9286d3cfe0eef54df1523533d22295"
|
||||
dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
"windows 0.61.1",
|
||||
"windows-core 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6256,10 +6264,10 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
|
||||
dependencies = [
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"raw-window-handle",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-version",
|
||||
@ -6271,11 +6279,24 @@ version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529"
|
||||
dependencies = [
|
||||
"windows-collections",
|
||||
"windows-collections 0.1.1",
|
||||
"windows-core 0.60.1",
|
||||
"windows-future",
|
||||
"windows-future 0.1.1",
|
||||
"windows-link",
|
||||
"windows-numerics",
|
||||
"windows-numerics 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
|
||||
dependencies = [
|
||||
"windows-collections 0.2.0",
|
||||
"windows-core 0.61.0",
|
||||
"windows-future 0.2.0",
|
||||
"windows-link",
|
||||
"windows-numerics 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6287,6 +6308,15 @@ dependencies = [
|
||||
"windows-core 0.60.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-collections"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.60.1"
|
||||
@ -6323,6 +6353,16 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.59.0"
|
||||
@ -6372,6 +6412,16 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.4.0"
|
||||
@ -6771,12 +6821,12 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.50.5"
|
||||
version = "0.51.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b19b78efae8b853c6c817e8752fc1dbf9cab8a8ffe9c30f399bd750ccf0f0730"
|
||||
checksum = "c886a0a9d2a94fd90cfa1d929629b79cfefb1546e2c7430c63a47f0664c0e4e2"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.6.0",
|
||||
"block2 0.6.1",
|
||||
"cookie",
|
||||
"crossbeam-channel",
|
||||
"dpi",
|
||||
@ -6790,10 +6840,10 @@ dependencies = [
|
||||
"kuchikiki",
|
||||
"libc",
|
||||
"ndk",
|
||||
"objc2 0.6.0",
|
||||
"objc2 0.6.1",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-foundation 0.3.1",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
"once_cell",
|
||||
@ -6807,8 +6857,8 @@ dependencies = [
|
||||
"webkit2gtk",
|
||||
"webkit2gtk-sys",
|
||||
"webview2-com",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
"windows 0.61.1",
|
||||
"windows-core 0.61.0",
|
||||
"windows-version",
|
||||
"x11-dl",
|
||||
]
|
||||
@ -7075,15 +7125,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
|
||||
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"lockfree-object-pool",
|
||||
"log",
|
||||
"once_cell",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
|
204
rust/src/cmd.rs
204
rust/src/cmd.rs
@ -1,11 +1,11 @@
|
||||
use ini::Ini;
|
||||
use log;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
use std::path::PathBuf;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::fs;
|
||||
use tauri::{AppHandle, Manager, State};
|
||||
use crate::model::config::GlobalConfigField;
|
||||
use crate::model::local::PackageManifest;
|
||||
use crate::model::misc::Game;
|
||||
use crate::model::patch::Patch;
|
||||
use crate::modules::package::prepare_dlls;
|
||||
@ -65,7 +65,7 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
||||
let mut amd_dlls = Vec::new();
|
||||
if let Some(p) = &appd.profile {
|
||||
hash = appd.sum_packages(p);
|
||||
(game_dlls, amd_dlls) = prepare_dlls(p.mod_pkgs(), &appd.pkgs).map_err(|e| e.to_string())?
|
||||
(game_dlls, amd_dlls) = prepare_dlls(p.meta.game, p.mod_pkgs(), &appd.pkgs);
|
||||
}
|
||||
if let Some(p) = &appd.profile {
|
||||
log::debug!("{}", hash);
|
||||
@ -73,12 +73,12 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
||||
let patches_enabled = appd.patches_enabled(
|
||||
&p.data.sgt.target,
|
||||
&p.data.sgt.target.parent().unwrap().join("amdaemon.exe")
|
||||
).map_err(|e| e.to_string())?;
|
||||
).map_err(|e| format!("Unable to apply patches: {e}"))?;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let info = p.prepare_display()
|
||||
.map_err(|e| e.to_string())?;
|
||||
let lineup_res = p.line_up(hash, refresh, patches_enabled).await
|
||||
.map_err(|e| e.to_string());
|
||||
.map_err(|e| format!("Unable to configure displays: {e}"))?;
|
||||
let lineup_res = p.line_up(hash, refresh, patches_enabled).await;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
if let Some(info) = info {
|
||||
@ -86,11 +86,12 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
||||
if lineup_res.is_ok() {
|
||||
Display::wait_for_exit(app.clone(), info);
|
||||
} else {
|
||||
Display::clean_up(&info).map_err(|e| e.to_string())?;
|
||||
Display::clean_up(&info)
|
||||
.map_err(|e| format!("Unable to restore displays: {e}"))?;
|
||||
}
|
||||
}
|
||||
|
||||
lineup_res?;
|
||||
lineup_res.map_err(|e| format!("Init failed: {e}"))?;
|
||||
|
||||
let app_clone = app.clone();
|
||||
let p_clone = p.clone();
|
||||
@ -123,14 +124,15 @@ pub async fn kill() -> Result<(), String> {
|
||||
pub async fn install_package(
|
||||
state: State<'_, tokio::sync::Mutex<AppData>>,
|
||||
key: PkgKey,
|
||||
force: bool
|
||||
force: bool,
|
||||
enable: bool
|
||||
) -> Result<InstallResult, String> {
|
||||
log::debug!("invoke: install_package({})", key);
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
appd.pkgs.install_package(&key, force, true)
|
||||
appd.pkgs.install_package(&key, force, true, enable)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
.map_err(|e| format!("Unable to install {key}: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -140,10 +142,10 @@ pub async fn delete_package(state: State<'_, tokio::sync::Mutex<AppData>>, key:
|
||||
let mut appd = state.lock().await;
|
||||
appd.pkgs.delete_package(&key, true)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
.map_err(|e| format!("Unable to delete {key}: {e}"))?;
|
||||
|
||||
appd.toggle_package(key, ToggleAction::Disable)
|
||||
.map_err(|e| e.to_string())
|
||||
appd.toggle_package(key.clone(), ToggleAction::Disable)
|
||||
.map_err(|e| format!("Unable to disable {key}: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -152,7 +154,7 @@ pub async fn get_package(state: State<'_, tokio::sync::Mutex<AppData>>, key: Pkg
|
||||
|
||||
let appd = state.lock().await;
|
||||
appd.pkgs.get(&key)
|
||||
.map_err(|e| e.to_string())
|
||||
.map_err(|e| format!("Unable to load {key}: {e}"))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
@ -161,8 +163,70 @@ pub async fn toggle_package(state: State<'_, tokio::sync::Mutex<AppData>>, key:
|
||||
log::debug!("invoke: toggle_package({}, {})", key, enable);
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
appd.toggle_package(key, if enable { ToggleAction::EnableRecursive } else { ToggleAction::Disable })
|
||||
.map_err(|e| e.to_string())
|
||||
appd.toggle_package(key.clone(), if enable { ToggleAction::EnableRecursive } else { ToggleAction::Disable })
|
||||
.map_err(|e| format!("Unable to toggle {key}: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn create_package(
|
||||
name: String,
|
||||
description: String,
|
||||
website: String,
|
||||
r#type: String,
|
||||
games: Vec<Game>
|
||||
) -> Result<(), String> {
|
||||
log::debug!("invoke: create_package");
|
||||
|
||||
let dir = util::pkg_dir_of("local", &name);
|
||||
|
||||
if dir.exists() {
|
||||
return Err("Package already exists".to_owned());
|
||||
}
|
||||
|
||||
let mut installers = Vec::new();
|
||||
|
||||
if r#type == "segatools" {
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(
|
||||
"identifier".to_owned(),
|
||||
serde_json::Value::String("segatools".to_owned())
|
||||
);
|
||||
installers.push(map);
|
||||
} else if r#type == "native" {
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(
|
||||
"identifier".to_owned(),
|
||||
serde_json::Value::String("native_mod".to_owned())
|
||||
);
|
||||
map.insert(
|
||||
"dll-game".to_owned(),
|
||||
serde_json::Value::String("some.dll".to_owned())
|
||||
);
|
||||
map.insert(
|
||||
"dll-amdaemon".to_owned(),
|
||||
serde_json::Value::String("another.dll".to_owned())
|
||||
);
|
||||
installers.push(map);
|
||||
}
|
||||
|
||||
let manifest = PackageManifest {
|
||||
name,
|
||||
version_number: "1.0.0".to_owned(),
|
||||
description,
|
||||
website_url: website,
|
||||
dependencies: BTreeSet::new(),
|
||||
installers,
|
||||
games: Some(games)
|
||||
};
|
||||
|
||||
std::fs::create_dir(&dir)
|
||||
.map_err(|e| format!("Unable to create {} directory: {e}", dir.file_name().unwrap_or_default().to_string_lossy()))?;
|
||||
let json = serde_json::to_string_pretty(&manifest)
|
||||
.map_err(|e| format!("Unable to serialize manifest.json: {e}"))?;
|
||||
std::fs::write(dir.join("manifest.json"), json)
|
||||
.map_err(|e| format!("Unable to write manifest.json: {e}"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -172,7 +236,7 @@ pub async fn reload_all_packages(state: State<'_, tokio::sync::Mutex<AppData>>)
|
||||
let mut appd = state.lock().await;
|
||||
appd.pkgs.reload_all()
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
.map_err(|e| format!("Unable to reload packages: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -190,12 +254,16 @@ pub async fn get_all_packages(state: State<'_, Mutex<AppData>>) -> Result<HashMa
|
||||
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_game_packages(state: State<'_, Mutex<AppData>>, game: Game) -> Result<Vec<PkgKey>, ()> {
|
||||
log::debug!("invoke: get_game_packages {game}");
|
||||
pub async fn get_game_packages(state: State<'_, Mutex<AppData>>, game: Option<Game>) -> Result<Vec<PkgKey>, ()> {
|
||||
log::debug!("invoke: get_game_packages {game:?}");
|
||||
|
||||
let appd = state.lock().await;
|
||||
|
||||
Ok(appd.pkgs.get_game_list(game))
|
||||
if let Some(game) = game {
|
||||
Ok(appd.pkgs.get_game_list(game))
|
||||
} else {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -222,17 +290,17 @@ pub async fn fetch_listings(state: State<'_, Mutex<AppData>>) -> Result<(), Stri
|
||||
|
||||
// Can be this lazy for now as there are only two short lists
|
||||
let listings1 = PackageStore::fetch_listings(Game::Ongeki).await
|
||||
.map_err(|e| e.to_string())?;
|
||||
.map_err(|e| format!("Unable to fetch Chunithm listings: {e}"))?;
|
||||
|
||||
let listings2 = PackageStore::fetch_listings(Game::Chunithm).await
|
||||
.map_err(|e| e.to_string())?;
|
||||
.map_err(|e| format!("Unable to fetch Ongeki listings: {e}"))?;
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
appd.pkgs.process_fetched_listings(listings1, Game::Ongeki);
|
||||
appd.pkgs.process_fetched_listings(listings2, Game::Chunithm);
|
||||
|
||||
appd.pkgs.save().await
|
||||
.map_err(|e| e.to_string())?;
|
||||
.map_err(|e| format!("Unable to save package-list: {e}"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -241,7 +309,9 @@ pub async fn fetch_listings(state: State<'_, Mutex<AppData>>) -> Result<(), Stri
|
||||
pub async fn list_profiles() -> Result<Vec<ProfileMeta>, String> {
|
||||
log::debug!("invoke: list_profiles");
|
||||
|
||||
let list = crate::profiles::list_profiles().await.map_err(|e| e.to_string())?;
|
||||
let list = crate::profiles::list_profiles()
|
||||
.await
|
||||
.map_err(|e| format!("Unable to list profiles: {e}"))?;
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
@ -255,7 +325,7 @@ pub async fn init_profile(
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
let new_profile = Profile::new(ProfileMeta { game, name })
|
||||
.map_err(|e| format!("Unable to create profile: {}", e))?;
|
||||
.map_err(|e| format!("Unable to create a profile: {}", e))?;
|
||||
|
||||
appd.profile = Some(new_profile);
|
||||
|
||||
@ -267,7 +337,8 @@ pub async fn load_profile(state: State<'_, Mutex<AppData>>, game: Game, name: St
|
||||
log::debug!("invoke: load_profile({} {:?})", game, name);
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
appd.switch_profile(game, name).map_err(|e| e.to_string())?;
|
||||
appd.switch_profile(game, name)
|
||||
.map_err(|e| format!("Unable to switch profile: {e}"))?;
|
||||
appd.fix();
|
||||
Ok(())
|
||||
}
|
||||
@ -374,7 +445,7 @@ pub async fn save_current_profile(state: State<'_, Mutex<AppData>>) -> Result<()
|
||||
appd.fix();
|
||||
match &mut appd.profile {
|
||||
Some(p) => {
|
||||
p.save().map_err(|e| e.to_string())
|
||||
p.save().map_err(|e| format!("Unable to save profile: {e}"))
|
||||
},
|
||||
None => {
|
||||
Err("no profile to save".to_owned())
|
||||
@ -388,37 +459,38 @@ pub async fn load_segatools_ini(state: State<'_, Mutex<AppData>>, path: PathBuf)
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
if let Some(p) = &mut appd.profile {
|
||||
let str = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
|
||||
// Stupid path escape hack for the ini reader
|
||||
let str = str.replace("\\", "\\\\").replace("\\\\\\\\", "\\\\");
|
||||
let ini = Ini::load_from_str(&str).map_err(|e| e.to_string())?;
|
||||
p.data.sgt.load_from_ini(&ini, p.config_dir()).map_err(|e| e.to_string())?;
|
||||
p.data.network.load_from_ini(&ini).map_err(|e| e.to_string())?;
|
||||
if let Some(kb) = &mut p.data.keyboard {
|
||||
kb.load_from_ini(&ini).map_err(|e| e.to_string())?;
|
||||
}
|
||||
p.save().map_err(|e| e.to_string())?;
|
||||
p.load_segatools_ini(path).map_err(|e| format!("Unable to load segatools.ini: {e}"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn create_shortcut(app: AppHandle, profile_meta: ProfileMeta) -> Result<(), String> {
|
||||
pub async fn create_shortcut(_app: AppHandle, profile_meta: ProfileMeta) -> Result<(), String> {
|
||||
log::debug!("invoke: create_shortcut({:?})", profile_meta);
|
||||
|
||||
util::create_shortcut(app, &profile_meta).map_err(|e| e.to_string())
|
||||
#[cfg(target_os = "windows")]
|
||||
return util::create_shortcut(_app, &profile_meta)
|
||||
.map_err(|e| format!("Unable to create a shortcut: {e}"));
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
return Err("unsupported".to_owned());
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn export_profile(state: State<'_, Mutex<AppData>>, export_keychip: bool, files: Vec<String>) -> Result<(), String> {
|
||||
pub async fn export_profile(
|
||||
state: State<'_, Mutex<AppData>>,
|
||||
is_diagnostic: bool,
|
||||
export_keychip: bool,
|
||||
files: Vec<String>
|
||||
) -> Result<(), String> {
|
||||
log::debug!("invoke: export_profile({:?}, {:?} files)", export_keychip, files.len());
|
||||
|
||||
let appd = state.lock().await;
|
||||
match &appd.profile {
|
||||
Some(p) => {
|
||||
p.export(export_keychip, files)
|
||||
.map_err(|e| e.to_string())?;
|
||||
p.export(export_keychip, files, is_diagnostic)
|
||||
.map_err(|e| format!("Unable to export profile: {e}"))?;
|
||||
}
|
||||
None => {
|
||||
let err = "export_profile: no profile".to_owned();
|
||||
@ -431,21 +503,43 @@ pub async fn export_profile(state: State<'_, Mutex<AppData>>, export_keychip: bo
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn import_profile(state: State<'_, Mutex<AppData>>, path: PathBuf) -> Result<(), String> {
|
||||
pub async fn import_profile(path: PathBuf) -> Result<(), String> {
|
||||
log::debug!("invoke: import_profile({:?})", path);
|
||||
|
||||
Profile::import(path).map_err(|e| e.to_string())
|
||||
Profile::import(path).map_err(|e| format!("Unable to import profile: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_platform_capabilities() -> Result<Vec<String>, ()> {
|
||||
pub async fn clear_cache(state: State<'_, Mutex<AppData>>) -> Result<(), String> {
|
||||
log::debug!("invoke: clear_cache");
|
||||
|
||||
let appd = state.lock().await;
|
||||
if let Some(p) = &appd.profile {
|
||||
let dir = p.data_dir().join("mu3-mods-cache");
|
||||
let path = dir.join("data_cache.bin");
|
||||
if path.exists() {
|
||||
std::fs::remove_file(path)
|
||||
.map_err(|e| format!("Unable to delete data_cache: {e}"))?;
|
||||
}
|
||||
let path = dir.join("data_fumen_analysis_cache.bin");
|
||||
if path.exists() {
|
||||
std::fs::remove_file(path)
|
||||
.map_err(|e| format!("Unable to delete data_fumen_analysis_cache: {e}"))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn list_platform_capabilities() -> Result<Vec<String>, ()> {
|
||||
log::debug!("invoke: list_platform_capabilities");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
return Ok(vec!["display".to_owned()]);
|
||||
return Ok(vec!["display".to_owned(), "shortcut".to_owned(), "chunithm".to_owned(), "preload-bat".to_owned()]);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
return Ok(vec!["wine".to_owned()]);
|
||||
return Ok(vec!["wine".to_owned(), "preload-sh".to_owned()]);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -470,7 +564,7 @@ pub async fn set_global_config(state: State<'_, Mutex<AppData>>, field: GlobalCo
|
||||
GlobalConfigField::EnableAutoupdates => appd.cfg.enable_autoupdates = value,
|
||||
GlobalConfigField::Verbose => appd.cfg.verbose = value,
|
||||
};
|
||||
appd.write().map_err(|e| e.to_string())
|
||||
appd.write().map_err(|e| format!("Unable to write config.json: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -518,7 +612,7 @@ pub async fn file_exists(path: String) -> Result<bool, ()> {
|
||||
// Easier than trying to get the barely-documented tauri permissions system to work
|
||||
#[tauri::command]
|
||||
pub async fn open_file(path: String) -> Result<(), String> {
|
||||
open::that(path).map_err(|e| e.to_string())?;
|
||||
open::that(&path).map_err(|e| format!("Unable to open {path}: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -543,12 +637,14 @@ pub async fn list_com_ports() -> Result<BTreeMap<String, i32>, String> {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_patches(state: State<'_, Mutex<AppData>>, target: String) -> Result<Vec<Patch>, String> {
|
||||
log::debug!("invoke: list_patches({})", target);
|
||||
pub async fn list_patches(state: State<'_, Mutex<AppData>>, target: PathBuf) -> Result<Vec<Patch>, String> {
|
||||
log::debug!("invoke: list_patches({:?})", target);
|
||||
|
||||
let mut appd = state.lock().await;
|
||||
appd.fix();
|
||||
let list = appd.patch_vec.find_patches(target).map_err(|e| e.to_string())?;
|
||||
let list = appd.patch_vec
|
||||
.find_patches(&target)
|
||||
.map_err(|e| format!("Unable to list patches for {}: {e}", target.file_name().unwrap_or_default().to_string_lossy()))?;
|
||||
|
||||
Ok(list)
|
||||
}
|
@ -17,6 +17,12 @@ pub struct DownloadTick {
|
||||
ratio: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct DownloadEndPayload {
|
||||
pub key: PkgKey,
|
||||
pub enable: bool
|
||||
}
|
||||
|
||||
impl DownloadHandler {
|
||||
pub fn new(app: AppHandle) -> DownloadHandler {
|
||||
DownloadHandler {
|
||||
@ -25,7 +31,7 @@ impl DownloadHandler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn download_zip(&mut self, zip_path: &PathBuf, pkg: &Package) -> Result<()> {
|
||||
pub fn download_zip(&mut self, zip_path: &PathBuf, pkg: &Package, enable: bool) -> Result<()> {
|
||||
let rmt = pkg.rmt.as_ref()
|
||||
.ok_or_else(|| anyhow!("Attempted to download a package without remote data"))?
|
||||
.clone();
|
||||
@ -34,12 +40,18 @@ impl DownloadHandler {
|
||||
} else {
|
||||
// TODO clear cache button should clear this
|
||||
self.paths.insert(zip_path.clone());
|
||||
tauri::async_runtime::spawn(Self::download_zip_proc(self.app.clone(), zip_path.clone(), pkg.key(), rmt));
|
||||
tauri::async_runtime::spawn(Self::download_zip_proc(self.app.clone(), zip_path.clone(), pkg.key(), rmt, enable));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn download_zip_proc(app: AppHandle, zip_path: PathBuf, pkg_key: PkgKey, rmt: Remote) -> Result<()> {
|
||||
async fn download_zip_proc(
|
||||
app: AppHandle,
|
||||
zip_path: PathBuf,
|
||||
pkg_key: PkgKey,
|
||||
rmt: Remote,
|
||||
enable: bool
|
||||
) -> Result<()> {
|
||||
use futures::StreamExt;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
@ -66,7 +78,10 @@ impl DownloadHandler {
|
||||
|
||||
log::debug!("downloaded to {:?}", zip_path);
|
||||
|
||||
app.emit("download-end", pkg_key)?;
|
||||
app.emit("download-end", DownloadEndPayload {
|
||||
key: pkg_key,
|
||||
enable
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -102,16 +102,23 @@ pub async fn run(_args: Vec<String>) {
|
||||
});
|
||||
|
||||
app.listen("download-end", closure!(clone apph, |ev| {
|
||||
let raw = ev.payload();
|
||||
log::debug!("download-end triggered: {}", raw);
|
||||
let key = PkgKey(raw[1..raw.len()-1].to_owned());
|
||||
let apph = apph.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let mutex = apph.state::<Mutex<AppData>>();
|
||||
let mut appd = mutex.lock().await;
|
||||
let res = appd.pkgs.install_package(&key, true, false).await;
|
||||
log::debug!("download-end install {:?}", res);
|
||||
});
|
||||
let payload = serde_json::from_str::<download_handler::DownloadEndPayload>(ev.payload());
|
||||
match payload {
|
||||
Ok(payload) => {
|
||||
log::debug!("download-end triggered: {:?}", payload);
|
||||
let key = payload.key;
|
||||
let apph = apph.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let mutex = apph.state::<Mutex<AppData>>();
|
||||
let mut appd = mutex.lock().await;
|
||||
let res = appd.pkgs.install_package(&key, true, false, payload.enable).await;
|
||||
log::debug!("download-end install {:?}", res);
|
||||
});
|
||||
},
|
||||
Err(err) => {
|
||||
log::error!("invalid download payload: {err}");
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
app.listen("launch-end", closure!(clone apph, |_| {
|
||||
@ -134,11 +141,13 @@ pub async fn run(_args: Vec<String>) {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let mutex = apph.state::<Mutex<AppData>>();
|
||||
let mut appd = mutex.lock().await;
|
||||
let res = appd.toggle_package(payload.pkg.clone(), ToggleAction::EnableSelf);
|
||||
log::debug!(
|
||||
"install-end-prelude toggle {:?}",
|
||||
res
|
||||
);
|
||||
if payload.enable == true {
|
||||
let res = appd.toggle_package(payload.pkg.clone(), ToggleAction::EnableSelf);
|
||||
log::debug!(
|
||||
"install-end-prelude toggle {:?}",
|
||||
res
|
||||
);
|
||||
}
|
||||
use tauri::Emitter;
|
||||
let res = apph.emit("install-end", payload);
|
||||
log::debug!("install-end {:?}", res);
|
||||
@ -193,6 +202,7 @@ pub async fn run(_args: Vec<String>) {
|
||||
cmd::install_package,
|
||||
cmd::delete_package,
|
||||
cmd::toggle_package,
|
||||
cmd::create_package,
|
||||
|
||||
cmd::list_profiles,
|
||||
cmd::init_profile,
|
||||
@ -207,6 +217,7 @@ pub async fn run(_args: Vec<String>) {
|
||||
cmd::create_shortcut,
|
||||
cmd::export_profile,
|
||||
cmd::import_profile,
|
||||
cmd::clear_cache,
|
||||
|
||||
cmd::get_global_config,
|
||||
cmd::set_global_config,
|
||||
@ -259,7 +270,7 @@ fn deep_link(app: AppHandle, args: Vec<String>) {
|
||||
log::info!("deep link: {}", url);
|
||||
|
||||
let regex = regex::Regex::new(
|
||||
r"rainycolor://v1/install/rainy\.patafour\.zip/([^/]+)/([^/]+)/[0-9]+\.[0-9]+\.[0-9]+/"
|
||||
r"rainycolor://v1/install/www\.rainycolor\.org/([^/]+)/([^/]+)/[0-9]+\.[0-9]+\.[0-9]+/"
|
||||
).expect("Invalid regex");
|
||||
|
||||
if let Some(caps) = regex.captures(url) {
|
||||
@ -271,11 +282,13 @@ fn deep_link(app: AppHandle, args: Vec<String>) {
|
||||
let mut appd = mutex.lock().await;
|
||||
if appd.pkgs.is_offline() {
|
||||
log::warn!("Deep link installation failed: offline");
|
||||
} else if let Err(e) = appd.pkgs.install_package(&key, true, true).await {
|
||||
} else if let Err(e) = appd.pkgs.install_package(&key, true, true, true).await {
|
||||
log::warn!("Deep link installation failed: {}", e.to_string());
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
log::error!("No caps");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -335,7 +348,7 @@ async fn update(app: tauri::AppHandle) -> tauri_plugin_updater::Result<()> {
|
||||
fn open_window(apph: AppHandle) -> anyhow::Result<()> {
|
||||
let config = apph.config().clone();
|
||||
tauri::WebviewWindowBuilder::new(&apph, "main", tauri::WebviewUrl::App("index.html".into()))
|
||||
.title(format!("STARTLINER {}", config.version.unwrap_or_default()))
|
||||
.title(format!("STARTLINER {} Beta", config.version.unwrap_or_default()))
|
||||
.inner_size(900f64, 600f64)
|
||||
.min_inner_size(900f64, 600f64)
|
||||
.build()?;
|
||||
|
@ -6,10 +6,11 @@ use super::misc::Game;
|
||||
|
||||
// manifest.json
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct PackageManifest {
|
||||
pub name: String,
|
||||
pub version_number: String,
|
||||
pub website_url: String,
|
||||
pub description: String,
|
||||
pub dependencies: BTreeSet<PkgKeyVersion>,
|
||||
|
||||
|
@ -71,10 +71,17 @@ impl Game {
|
||||
|
||||
pub fn has_module(&self, module: ProfileModule) -> bool {
|
||||
match self {
|
||||
Game::Ongeki => make_bitflags!(ProfileModule::{Segatools | Display | Network | BepInEx | Mu3Ini | Keyboard}),
|
||||
Game::Ongeki => make_bitflags!(ProfileModule::{Segatools | Display | Network | BepInEx | Mu3Ini | Keyboard | Mempatcher}),
|
||||
Game::Chunithm => make_bitflags!(ProfileModule::{Segatools | Display | Network | Keyboard | Mempatcher}),
|
||||
}.contains(module)
|
||||
}
|
||||
|
||||
pub fn bitness(&self) -> i32 {
|
||||
match self {
|
||||
Game::Ongeki => 64,
|
||||
Game::Chunithm => 32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Game {
|
||||
|
@ -42,6 +42,7 @@ pub struct Patch {
|
||||
pub enum PatchData {
|
||||
Normal(NormalPatch),
|
||||
Number(NumberPatch),
|
||||
Hex(HexPatch),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
@ -65,6 +66,12 @@ pub struct NumberPatch {
|
||||
pub max: i32
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct HexPatch {
|
||||
pub offset: u64,
|
||||
pub off: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Serialize for Patch {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer {
|
||||
@ -83,6 +90,11 @@ impl Serialize for Patch {
|
||||
state.serialize_field("size", &patch.size)?;
|
||||
state.serialize_field("min", &patch.min)?;
|
||||
state.serialize_field("max", &patch.max)?;
|
||||
},
|
||||
PatchData::Hex(patch) => {
|
||||
state.serialize_field("type", "hex")?;
|
||||
state.serialize_field("offset", &patch.offset)?;
|
||||
state.serialize_field("off", &patch.off)?;
|
||||
}
|
||||
}
|
||||
state.end()
|
||||
@ -114,6 +126,23 @@ impl<'de> serde::Deserialize<'de> for Patch {
|
||||
.ok_or_else(|| de::Error::missing_field("max"))?
|
||||
).map_err(|_| de::Error::missing_field("max"))?
|
||||
}),
|
||||
Some("hex") => {
|
||||
let mut off_list = Vec::new();
|
||||
for off in value.get("off").and_then(Value::as_array).unwrap() {
|
||||
off_list.push(u8::try_from(
|
||||
off.as_u64().ok_or_else(|| de::Error::missing_field("off"))?
|
||||
).map_err(|_| de::Error::missing_field("off"))?);
|
||||
}
|
||||
// for off in value.get("off").and_then(Value::as_str).unwrap().bytes() {
|
||||
// off_list.push(off);
|
||||
// }
|
||||
PatchData::Hex(HexPatch {
|
||||
offset: value.get("offset")
|
||||
.and_then(Value::as_u64)
|
||||
.ok_or_else(|| de::Error::missing_field("offset"))?,
|
||||
off: off_list
|
||||
})
|
||||
},
|
||||
None => {
|
||||
let mut patches = vec![];
|
||||
for patch in value.get("patches").and_then(Value::as_array).unwrap() {
|
||||
|
@ -108,7 +108,10 @@ impl Display {
|
||||
Game::Ongeki => 60,
|
||||
},
|
||||
borderless_fullscreen: true,
|
||||
#[cfg(target_os = "windows")]
|
||||
dont_switch_primary: false,
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
dont_switch_primary: true,
|
||||
monitor_index_override: None,
|
||||
}
|
||||
}
|
||||
@ -141,7 +144,7 @@ pub struct BepInEx {
|
||||
pub console: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(default)]
|
||||
pub struct Wine {
|
||||
pub runtime: PathBuf,
|
||||
|
8
rust/src/modules/display_linux.rs
Normal file
8
rust/src/modules/display_linux.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use ini::Ini;
|
||||
use crate::model::{misc::Game, profile::Display};
|
||||
|
||||
impl Display {
|
||||
pub fn line_up(&self, _game: Game, _ini: &mut Ini) {
|
||||
// nop
|
||||
}
|
||||
}
|
@ -103,7 +103,10 @@ impl Display {
|
||||
}
|
||||
|
||||
display_set.apply().map_err(
|
||||
|_| anyhow!("The selected monitor has been disconnected or doesn't support the chosen display mode")
|
||||
|e| {
|
||||
log::error!("display_set: {e}");
|
||||
anyhow!("The selected monitor has been disconnected or doesn't support the chosen display mode")
|
||||
}
|
||||
)?;
|
||||
displayz::refresh()?;
|
||||
|
||||
|
@ -117,12 +117,16 @@ impl Keyboard {
|
||||
}
|
||||
}
|
||||
Keyboard::Chunithm(kb) => {
|
||||
let mut enabled_ir = false;
|
||||
if kb.enabled {
|
||||
for (i, cell) in kb.cell.iter().enumerate() {
|
||||
ini.with_section(Some("slider")).set(format!("cell{}", i + 1), cell.to_string());
|
||||
}
|
||||
for (i, ir) in kb.ir.iter().enumerate() {
|
||||
ini.with_section(Some("ir")).set(format!("ir{}", i + 1), ir.to_string());
|
||||
ini.with_section(Some("ir")).set(format!("ir{}", i + 1), (*ir).to_string());
|
||||
if i > 0 && *ir != 0 {
|
||||
enabled_ir = true;
|
||||
}
|
||||
}
|
||||
ini.with_section(Some("io3"))
|
||||
.set("test", kb.test.to_string())
|
||||
@ -140,8 +144,13 @@ impl Keyboard {
|
||||
.set("service", "0")
|
||||
.set("coin", "0");
|
||||
}
|
||||
ini.with_section(Some("io3"))
|
||||
.set("ir", "0");
|
||||
if enabled_ir {
|
||||
ini.with_section(Some("io3"))
|
||||
.set("ir", "0");
|
||||
} else {
|
||||
ini.with_section(Some("io3"))
|
||||
.set("ir", kb.ir[0].to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,21 @@ impl PatchSelection {
|
||||
} else {
|
||||
log::error!("invalid number patch {:?}", patch);
|
||||
}
|
||||
},
|
||||
PatchData::Hex(data) => {
|
||||
if let PatchSelectionData::Hex(val) = sel {
|
||||
res += &format!("{} F+{:X} ", filename, data.offset);
|
||||
for byte in val {
|
||||
res += &format!("{:02X}", byte);
|
||||
}
|
||||
res += " ";
|
||||
for byte in &data.off {
|
||||
res += &format!("{:02X}", byte);
|
||||
}
|
||||
} else {
|
||||
log::error!("invalid number patch {:?}", patch);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
format!("{}\n", res)
|
||||
|
@ -7,4 +7,7 @@ pub mod keyboard;
|
||||
pub mod mempatcher;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod display_windows;
|
||||
pub mod display_windows;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod display_linux;
|
@ -1,17 +1,26 @@
|
||||
use anyhow::Result;
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::PathBuf;
|
||||
use crate::model::misc::Game;
|
||||
use crate::pkg::{PkgKey, Status};
|
||||
use crate::pkg_store::PackageStore;
|
||||
use crate::util;
|
||||
use crate::profiles::types::ProfilePaths;
|
||||
|
||||
pub async fn prepare_packages<'a>(p: &'a impl ProfilePaths, pkgs: &BTreeSet<PkgKey>, redo_bepinex: bool) -> Result<()> {
|
||||
pub async fn prepare_packages<'a>(p: &'a impl ProfilePaths, pkgs: &BTreeSet<PkgKey>, mut redo_bepinex: bool) -> Result<()> {
|
||||
log::debug!("begin prepare packages");
|
||||
|
||||
let pfx_dir = p.data_dir();
|
||||
let opt_dir = pfx_dir.join("option");
|
||||
|
||||
for m in pkgs {
|
||||
let (namespace, _) = m.split()?;
|
||||
if namespace == "local" {
|
||||
log::info!("package with the 'local' namespace enabled -- force refreshing");
|
||||
redo_bepinex = true;
|
||||
}
|
||||
}
|
||||
|
||||
if redo_bepinex {
|
||||
if pfx_dir.join("BepInEx").exists() {
|
||||
util::remove_dir_all(pfx_dir.join("BepInEx")).await?;
|
||||
@ -60,9 +69,10 @@ pub async fn prepare_packages<'a>(p: &'a impl ProfilePaths, pkgs: &BTreeSet<PkgK
|
||||
}
|
||||
|
||||
pub fn prepare_dlls(
|
||||
game: Game,
|
||||
enabled_pkgs: &BTreeSet<PkgKey>,
|
||||
store: &PackageStore,
|
||||
) -> Result<(Vec<PathBuf>, Vec<PathBuf>)> {
|
||||
) -> (Vec<PathBuf>, Vec<PathBuf>) {
|
||||
let mut res_game = Vec::new();
|
||||
let mut res_amd = Vec::new();
|
||||
for pkg in enabled_pkgs {
|
||||
@ -72,6 +82,16 @@ pub fn prepare_dlls(
|
||||
if let Some(game_dll) = &dlls.game {
|
||||
res_game.push(pkg.path().join(game_dll.clone()));
|
||||
}
|
||||
if let Some(game32_dll) = &dlls.game32 {
|
||||
if game.bitness() == 32 {
|
||||
res_game.push(pkg.path().join(game32_dll.clone()));
|
||||
}
|
||||
}
|
||||
if let Some(game64_dll) = &dlls.game64 {
|
||||
if game.bitness() == 64 {
|
||||
res_game.push(pkg.path().join(game64_dll.clone()));
|
||||
}
|
||||
}
|
||||
if let Some(amd_dll) = &dlls.amd {
|
||||
res_amd.push(pkg.path().join(amd_dll.clone()));
|
||||
}
|
||||
@ -79,5 +99,5 @@ pub fn prepare_dlls(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((res_game, res_amd))
|
||||
(res_game, res_amd)
|
||||
}
|
@ -43,7 +43,11 @@ impl Segatools {
|
||||
if let Some(aime_path) = s.get("aimePath") {
|
||||
if let Some(game_dir) = self.target.parent() {
|
||||
let target = game_dir.join(aime_path);
|
||||
std::fs::copy(target, config_dir.as_ref().join("aime.txt"))?;
|
||||
if target.exists() {
|
||||
std::fs::copy(target, config_dir.as_ref().join("aime.txt"))?;
|
||||
} else {
|
||||
log::warn!("aime.txt was configured in segatools.ini but it doesn't exist");
|
||||
}
|
||||
} else {
|
||||
log::error!("profile doesn't have a game directory");
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ impl PatchFileVec {
|
||||
std::fs::create_dir(&path)?;
|
||||
}
|
||||
std::fs::write(path.join("builtin-chunithm.json5"), include_bytes!("../static/standard-chunithm.json5"))?;
|
||||
std::fs::write(path.join("builtin-amdaemon.json5"), include_bytes!("../static/standard-amdaemon.json5"))?;
|
||||
let mut res = Vec::new();
|
||||
for f in std::fs::read_dir(path)? {
|
||||
let f = f?;
|
||||
@ -28,6 +29,10 @@ impl PatchFileVec {
|
||||
}
|
||||
|
||||
pub fn find_patches(&self, target: impl AsRef<Path>) -> Result<Vec<Patch>> {
|
||||
if !target.as_ref().exists() {
|
||||
log::warn!("invalid target path: {:?}", target.as_ref());
|
||||
anyhow::bail!("Unable to open {:?}. Make sure the game path is correct.", target.as_ref());
|
||||
}
|
||||
let checksum = try_digest(target.as_ref())?;
|
||||
|
||||
let mut res_patches = Vec::new();
|
||||
|
@ -41,6 +41,8 @@ pub enum Status {
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
|
||||
pub struct DLLs {
|
||||
pub game: Option<String>,
|
||||
pub game32: Option<String>,
|
||||
pub game64: Option<String>,
|
||||
pub amd: Option<String>
|
||||
}
|
||||
|
||||
@ -107,7 +109,7 @@ impl Package {
|
||||
loc: None,
|
||||
rmt: Some(Remote {
|
||||
package_url: p.package_url,
|
||||
download_url: v.download_url,
|
||||
download_url: v.download_url.replace("https://rainy.patafour.zip/", "https://www.rainycolor.org/"),
|
||||
icon: v.icon,
|
||||
deprecated: p.is_deprecated,
|
||||
nsfw: p.has_nsfw_content,
|
||||
@ -231,10 +233,12 @@ impl Package {
|
||||
if dir.as_ref().join("app").join("data").exists() {
|
||||
return Status::Unsupported;
|
||||
}
|
||||
return Status::OK(make_bitflags!(Feature::Mod), DLLs { game: None, amd: None });
|
||||
return Status::OK(make_bitflags!(Feature::Mod), DLLs { game: None, game32: None, game64: None, amd: None });
|
||||
} else {
|
||||
let mut flags = BitFlags::default();
|
||||
let mut game_dll = None;
|
||||
let mut game32_dll = None;
|
||||
let mut game64_dll = None;
|
||||
let mut amd_dll = None;
|
||||
for installer in &mft.installers {
|
||||
if let Some(serde_json::Value::String(id)) = installer.get("identifier") {
|
||||
@ -262,6 +266,16 @@ impl Package {
|
||||
flags |= Feature::Mod;
|
||||
game_dll = Some(path.to_owned());
|
||||
}
|
||||
if let Some(serde_json::Value::String(path)) = installer.get("dll-game32") {
|
||||
flags |= Feature::GameDLL;
|
||||
flags |= Feature::Mod;
|
||||
game32_dll = Some(path.to_owned());
|
||||
}
|
||||
if let Some(serde_json::Value::String(path)) = installer.get("dll-game64") {
|
||||
flags |= Feature::GameDLL;
|
||||
flags |= Feature::Mod;
|
||||
game64_dll = Some(path.to_owned());
|
||||
}
|
||||
if let Some(serde_json::Value::String(path)) = installer.get("dll-amdaemon") {
|
||||
flags |= Feature::AmdDLL;
|
||||
flags |= Feature::Mod;
|
||||
@ -272,8 +286,8 @@ impl Package {
|
||||
}
|
||||
}
|
||||
}
|
||||
log::debug!("{} parse result: {:?} {:?} {:?}", mft.name, flags, game_dll, amd_dll);
|
||||
Status::OK(flags, DLLs { game: game_dll, amd: amd_dll })
|
||||
log::debug!("{} parse result: {:?} {:?} {:?} {:?} {:?}", mft.name, flags, game_dll, game32_dll, game64_dll, amd_dll);
|
||||
Status::OK(flags, DLLs { game: game_dll, game32: game32_dll, game64: game64_dll, amd: amd_dll })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,8 @@ pub struct PackageStore {
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct Payload {
|
||||
pub pkg: PkgKey
|
||||
pub pkg: PkgKey,
|
||||
pub enable: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||
@ -132,7 +133,7 @@ impl PackageStore {
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
let response = reqwest::get(format!("https://rainy.patafour.zip/c/{game}/api/v1/package/")).await?;
|
||||
let response = reqwest::get(format!("https://www.rainycolor.org/c/{game}/api/v1/package/")).await?;
|
||||
|
||||
let reader = response
|
||||
.bytes_stream()
|
||||
@ -180,7 +181,13 @@ impl PackageStore {
|
||||
self.offline = false;
|
||||
}
|
||||
|
||||
pub async fn install_package(&mut self, key: &PkgKey, force: bool, install_deps: bool) -> Result<InstallResult> {
|
||||
pub async fn install_package(
|
||||
&mut self,
|
||||
key: &PkgKey,
|
||||
force: bool,
|
||||
install_deps: bool,
|
||||
enable: bool
|
||||
) -> Result<InstallResult> {
|
||||
log::info!("installation request: {}/{}/{}", key, force, install_deps);
|
||||
|
||||
let pkg = self.store.get(key)
|
||||
@ -193,7 +200,8 @@ impl PackageStore {
|
||||
}
|
||||
|
||||
self.app.emit("install-start", Payload {
|
||||
pkg: key.to_owned()
|
||||
pkg: key.to_owned(),
|
||||
enable
|
||||
})?;
|
||||
|
||||
let rmt = pkg.rmt.as_ref()
|
||||
@ -203,7 +211,7 @@ impl PackageStore {
|
||||
let mut set = HashSet::new();
|
||||
self.resolve_deps(rmt.clone(), &mut set)?;
|
||||
for dep in set {
|
||||
Box::pin(self.install_package(&dep, false, false)).await?;
|
||||
Box::pin(self.install_package(&dep, false, false, enable)).await?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,7 +222,7 @@ impl PackageStore {
|
||||
let part_path = zip_path.join(".part");
|
||||
|
||||
if !zip_path.exists() && !part_path.exists() {
|
||||
self.dlh.download_zip(&zip_path, &pkg)?;
|
||||
self.dlh.download_zip(&zip_path, &pkg, enable)?;
|
||||
log::debug!("deferring {}", key);
|
||||
return Ok(InstallResult::Deferred);
|
||||
}
|
||||
@ -230,7 +238,8 @@ impl PackageStore {
|
||||
self.reload_package(key.to_owned()).await;
|
||||
|
||||
self.app.emit("install-end-prelude", Payload {
|
||||
pkg: key.to_owned()
|
||||
pkg: key.to_owned(),
|
||||
enable
|
||||
})?;
|
||||
|
||||
log::info!("installed {}", key);
|
||||
@ -252,7 +261,8 @@ impl PackageStore {
|
||||
|
||||
if rv.is_ok() {
|
||||
self.app.emit("install-end-prelude", Payload {
|
||||
pkg: key.to_owned()
|
||||
pkg: key.to_owned(),
|
||||
enable: false
|
||||
})?;
|
||||
log::info!("deleted {}", key);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
pub use types::{Profile, ProfileData, ProfileMeta, ProfilePaths, StartPayload};
|
||||
use std::{collections::{BTreeMap, BTreeSet}, path::{Path, PathBuf}};
|
||||
use crate::{model::{misc::Game, patch::{PatchList, PatchSelection}, profile::{Aime, ChunithmKeyboard, IOSelection, Keyboard, Mu3Ini, OngekiKeyboard, ProfileModule}}, modules::{display_windows::DisplayInfo, package::prepare_packages}, pkg::PkgKey, pkg_store::PackageStore, util};
|
||||
use crate::{model::{misc::Game, patch::{PatchList, PatchSelection}, profile::{Aime, ChunithmKeyboard, IOSelection, Keyboard, Mu3Ini, OngekiKeyboard, ProfileModule}}, modules::package::prepare_packages, pkg::PkgKey, pkg_store::PackageStore, util};
|
||||
use tauri::Emitter;
|
||||
use std::process::Stdio;
|
||||
use crate::model::profile::BepInEx;
|
||||
@ -10,9 +10,23 @@ use std::fs::File;
|
||||
use tokio::process::Command;
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use crate::modules::display_windows::DisplayInfo;
|
||||
|
||||
pub mod template;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub trait RawArg {
|
||||
fn raw_arg<S: AsRef<std::ffi::OsStr>>(&mut self, arg: S) -> &mut Command;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
impl RawArg for Command {
|
||||
fn raw_arg<S: AsRef<std::ffi::OsStr>>(&mut self, arg: S) -> &mut Command {
|
||||
return self.arg::<S>(arg);
|
||||
}
|
||||
}
|
||||
|
||||
impl Profile {
|
||||
pub fn new(mut meta: ProfileMeta) -> Result<Self> {
|
||||
meta.name = fixed_name(&meta, true);
|
||||
@ -36,7 +50,7 @@ impl Profile {
|
||||
} else {
|
||||
Some(Keyboard::Chunithm(ChunithmKeyboard::default()))
|
||||
},
|
||||
patches: if meta.game == Game::Chunithm { Some(PatchSelection(BTreeMap::new())) } else { None }
|
||||
patches: Some(PatchSelection(BTreeMap::new()))
|
||||
},
|
||||
meta: meta.clone()
|
||||
};
|
||||
@ -78,6 +92,9 @@ impl Profile {
|
||||
} else {
|
||||
data.mu3_ini = Some(Mu3Ini::default());
|
||||
}
|
||||
if data.patches.is_none() {
|
||||
data.patches = Some(PatchSelection(BTreeMap::new()));
|
||||
}
|
||||
|
||||
Self::load_existing_mu3_ini(&data, &ProfileMeta { game, name: name.clone() })?;
|
||||
}
|
||||
@ -173,6 +190,7 @@ impl Profile {
|
||||
self.data.patches = source.patches;
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn prepare_display(&self) -> Result<Option<DisplayInfo>> {
|
||||
let info = match &self.data.display {
|
||||
None => None,
|
||||
@ -237,6 +255,7 @@ impl Profile {
|
||||
|
||||
let mut game_builder;
|
||||
let mut amd_builder;
|
||||
let mut prescript = None;
|
||||
|
||||
let target_path = PathBuf::from(&self.data.sgt.target);
|
||||
let exe_dir = target_path.parent().ok_or_else(|| anyhow!("Invalid target path"))?;
|
||||
@ -249,13 +268,19 @@ impl Profile {
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
game_builder = Command::new(&self.wine.runtime);
|
||||
amd_builder = Command::new(&self.wine.runtime);
|
||||
game_builder = Command::new(&self.data.wine.runtime);
|
||||
amd_builder = Command::new(&self.data.wine.runtime);
|
||||
|
||||
game_builder.arg(sgt_dir.join(self.meta.game.inject_exe()));
|
||||
amd_builder.arg("cmd.exe");
|
||||
}
|
||||
|
||||
let script_ext = if cfg!(target_os = "windows") { "bat" } else { "sh" };
|
||||
let prescript_path = self.config_dir().join(format!("pre.{script_ext}"));
|
||||
if prescript_path.exists() {
|
||||
prescript = util::spawn_script(prescript_path, &exe_dir, "\"STARTLINER launch script\"");
|
||||
}
|
||||
|
||||
amd_builder.env(
|
||||
"SEGATOOLS_CONFIG_PATH",
|
||||
&ini_path,
|
||||
@ -346,8 +371,8 @@ impl Profile {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
amd_builder.env("WINEPREFIX", &self.wine.prefix);
|
||||
game_builder.env("WINEPREFIX", &self.wine.prefix);
|
||||
amd_builder.env("WINEPREFIX", &self.data.wine.prefix);
|
||||
game_builder.env("WINEPREFIX", &self.data.wine.prefix);
|
||||
}
|
||||
|
||||
let amd_log = File::create(self.data_dir().join("amdaemon.exe.log"))?;
|
||||
@ -402,6 +427,23 @@ impl Profile {
|
||||
util::pkill("amdaemon.exe").await;
|
||||
}
|
||||
|
||||
if let Some(mut _child) = prescript {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// child.kill() doesn't work
|
||||
util::pkill_title("STARTLINER launch script").await;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
_child.start_kill()?;
|
||||
}
|
||||
}
|
||||
|
||||
let postscript_path = self.config_dir().join(format!("post.{script_ext}"));
|
||||
if postscript_path.exists() {
|
||||
_ = util::spawn_script(postscript_path, &exe_dir, "\"STARTLINER end script\"");
|
||||
}
|
||||
|
||||
set.join_next().await.expect("No spawn").expect("No result");
|
||||
|
||||
log::debug!("Fin");
|
||||
@ -437,6 +479,21 @@ impl Profile {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_segatools_ini(&mut self, path: impl AsRef<Path>) -> Result<()> {
|
||||
let str = std::fs::read_to_string(path.as_ref())?;
|
||||
// Stupid path escape hack for the ini reader
|
||||
let str = str.replace("\\", "\\\\").replace("\\\\\\\\", "\\\\");
|
||||
let ini = ini::Ini::load_from_str(&str)?;
|
||||
self.data.sgt.load_from_ini(&ini, self.config_dir())?;
|
||||
self.data.network.load_from_ini(&ini)?;
|
||||
if let Some(kb) = &mut self.data.keyboard {
|
||||
kb.load_from_ini(&ini)?;
|
||||
}
|
||||
self.save()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ProfilePaths for Profile {
|
||||
|
@ -36,7 +36,7 @@ impl Profile {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn export(&self, export_keychip: bool, extra_files: Vec<String>) -> anyhow::Result<()> {
|
||||
pub fn export(&self, export_keychip: bool, extra_files: Vec<String>, is_diagnostic: bool) -> anyhow::Result<()> {
|
||||
let mut prf = self.clone();
|
||||
|
||||
let dir = util::config_dir().join("exports");
|
||||
@ -45,19 +45,21 @@ impl Profile {
|
||||
std::fs::create_dir(&dir)?;
|
||||
}
|
||||
|
||||
let path = dir.join(format!("{}-{}-template.zip", &self.meta.game, &self.meta.name));
|
||||
let path = dir.join(format!("{}-{}-{}.zip", &self.meta.game, &self.meta.name, if is_diagnostic { "diagnostic" } else { "template" } ));
|
||||
|
||||
{
|
||||
let sgt = &mut prf.data.sgt;
|
||||
sgt.target = PathBuf::new();
|
||||
if sgt.amfs.is_absolute() {
|
||||
sgt.amfs = PathBuf::new();
|
||||
}
|
||||
if sgt.option.is_absolute() {
|
||||
sgt.option = PathBuf::new();
|
||||
}
|
||||
if sgt.appdata.is_absolute() {
|
||||
sgt.appdata = PathBuf::new();
|
||||
if !is_diagnostic {
|
||||
sgt.target = PathBuf::new();
|
||||
if sgt.amfs.is_absolute() {
|
||||
sgt.amfs = PathBuf::new();
|
||||
}
|
||||
if sgt.option.is_absolute() {
|
||||
sgt.option = PathBuf::new();
|
||||
}
|
||||
if sgt.appdata.is_absolute() {
|
||||
sgt.appdata = PathBuf::new();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +68,7 @@ impl Profile {
|
||||
if network.local_path.is_absolute() {
|
||||
network.local_path = PathBuf::new();
|
||||
}
|
||||
if !export_keychip {
|
||||
if !export_keychip || is_diagnostic {
|
||||
network.keychip = String::new();
|
||||
}
|
||||
}
|
||||
@ -83,6 +85,29 @@ impl Profile {
|
||||
zip.write_all(&std::fs::read(self.config_dir().join(file))?)?;
|
||||
}
|
||||
|
||||
if is_diagnostic {
|
||||
let name = "mu3.exe.log";
|
||||
let path = self.data_dir().join(name);
|
||||
if path.exists() {
|
||||
zip.start_file(name, options)?;
|
||||
zip.write_all(&std::fs::read(path)?)?;
|
||||
}
|
||||
|
||||
let name = "chusanApp.exe.log";
|
||||
let path = self.data_dir().join(name);
|
||||
if path.exists() {
|
||||
zip.start_file(name, options)?;
|
||||
zip.write_all(&std::fs::read(path)?)?;
|
||||
}
|
||||
|
||||
let name = "amdaemon.exe.log";
|
||||
let path = self.data_dir().join(name);
|
||||
if path.exists() {
|
||||
zip.start_file(name, options)?;
|
||||
zip.write_all(&std::fs::read(path)?)?;
|
||||
}
|
||||
}
|
||||
|
||||
zip.finish()?;
|
||||
|
||||
Ok(())
|
||||
|
@ -105,6 +105,12 @@ pub async fn pkill(process_name: &str) {
|
||||
.creation_flags(CREATE_NO_WINDOW).output().await;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub async fn pkill_title(window_title: &str) {
|
||||
_ = Command::new("taskkill.exe").arg("/fi").raw_arg(format!("\"WindowTitle eq {window_title}\""))
|
||||
.creation_flags(CREATE_NO_WINDOW).output().await;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn pkill(process_name: &str) {
|
||||
_ = Command::new("pkill").arg(process_name)
|
||||
@ -152,6 +158,7 @@ impl PathStr for PathBuf {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn bool_to_01(val: bool) -> &'static str {
|
||||
return if val { "1" } else { "0" }
|
||||
}
|
||||
@ -213,4 +220,38 @@ pub fn create_shortcut(
|
||||
file.Save(Some(lnk_path.to_str().ok_or_else(|| anyhow!("Illegal shortcut path"))?), true)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn spawn_script(path: impl AsRef<Path>, cwd: impl AsRef<Path>, title: &str) -> Option<tokio::process::Child> {
|
||||
// Seems? like this autism is needed to:
|
||||
// 1. pop up a cmd window
|
||||
// 2. launch the batch
|
||||
// 3. die afterwards
|
||||
let mut c;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
c = Command::new("cmd");
|
||||
c.args(["/C", "start"]);
|
||||
c.raw_arg(title);
|
||||
c.args(["cmd", "/C"]);
|
||||
c.arg(path.as_ref());
|
||||
c.current_dir(cwd);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
c = Command::new("sh");
|
||||
c.arg(path.as_ref());
|
||||
c.current_dir(cwd);
|
||||
}
|
||||
|
||||
log::debug!("Script launch: {:?}", c);
|
||||
match c.spawn() {
|
||||
Ok(child) => Some(child),
|
||||
Err(e) => {
|
||||
log::error!("unable to launch {:?}: {e}", path.as_ref());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
@ -64,19 +64,4 @@ controllerLedOutputOpeNITHM=0
|
||||
; [60]-[62]: right side partition LEDs
|
||||
;
|
||||
; Board 2 is the slider and has 31 LEDs:
|
||||
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[chuniio]
|
||||
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
|
||||
; (will use chu2to3 engine internally)
|
||||
;path=
|
||||
|
||||
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
|
||||
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
||||
;path32=
|
||||
;path64=
|
||||
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
105
rust/static/standard-amdaemon.json5
Normal file
105
rust/static/standard-amdaemon.json5
Normal file
@ -0,0 +1,105 @@
|
||||
[
|
||||
{
|
||||
// CHUNITHM Luminous+
|
||||
filename: 'amdaemon.exe',
|
||||
version: '2.25.00',
|
||||
sha256: '00FB867D1EE821033101B8773FAC116A45DF1939D23C38E9DAFC9B86CD5A3777',
|
||||
patches: [
|
||||
{
|
||||
id: 'standard-localhost',
|
||||
name: "Allow 127.0.0.1/localhost as the network server",
|
||||
patches: [
|
||||
{ offset: 0x6E28A4, off: [0x31, 0x32, 0x37, 0x2F], on: [0x30, 0x2F, 0x38, 0x00] },
|
||||
{ offset: 0x3C94C4, off: [0xFF, 0x15, 0xC6, 0x2F, 0x1B, 0x00, 0x8B], on: [0x33, 0xC0, 0x48, 0x83, 0xC4, 0x28, 0xC3] }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'standard-credit-freeze',
|
||||
name: "Infinite credits",
|
||||
patches: [
|
||||
{ offset: 0x2BBBC8, off: [0x28], on: [0x08] }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
// CHUNITHM Verse
|
||||
filename: 'amdaemon.exe',
|
||||
version: '2.30.00',
|
||||
sha256: 'd4809220578374865370e31c541ed6e406b854d8c26cfe7464c2c15145113bfd',
|
||||
patches: [
|
||||
{
|
||||
id: 'standard-localhost',
|
||||
name: 'Allow 127.0.0.1/localhost as the network server',
|
||||
patches: [
|
||||
{
|
||||
offset: 0x6e1ca4,
|
||||
off: [0x31, 0x32, 0x37, 0x2f],
|
||||
on: [0x30, 0x2f, 0x38, 0x00],
|
||||
},
|
||||
{
|
||||
offset: 0x3c88c4,
|
||||
off: [0xff, 0x15, 0xc6, 0x2f, 0x1b, 0x00, 0x8b],
|
||||
on: [0x33, 0xc0, 0x48, 0x83, 0xc4, 0x28, 0xc3],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'standard-credit-freeze',
|
||||
name: 'Credit freeze',
|
||||
tooltip: 'Prevents credits from being used. At least one credit must be available to start the game or purchase premium tickets.',
|
||||
patches: [{ offset: 0x2bafc8, off: [0x28], on: [0x08] }],
|
||||
},
|
||||
{
|
||||
id: 'standard-openssl-fix',
|
||||
name: 'OpenSSL SHA crash bug fix',
|
||||
tooltip: 'Fix crashes on 10th generation and newer Intel CPUs',
|
||||
patches: [
|
||||
{ offset: 0x4d4a43, off: [0x48], on: [0x4c] },
|
||||
{ offset: 0x4d4a4b, off: [0x48], on: [0x49] },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// Ongeki
|
||||
filename: "amdaemon.exe",
|
||||
version: "46d47eab",
|
||||
sha256: '962C76331306D0839AFD40808EA99D83E651D39C4708C448ADE0C77E8BC0A1B0',
|
||||
patches: [
|
||||
{
|
||||
id: 'standard-localhost',
|
||||
name: "Allow 127.0.0.1/localhost as the network server",
|
||||
patches: [
|
||||
{
|
||||
offset: 0x69042C,
|
||||
off: [0x31, 0x32, 0x37, 0x2F],
|
||||
on: [0x30, 0x2F, 0x38, 0x00]
|
||||
},
|
||||
{
|
||||
offset: 0x3A0E34,
|
||||
off: [0xFF, 0x15, 0x86, 0xD5, 0x19, 0x00, 0x8B],
|
||||
on: [0x33, 0xC0, 0x48, 0x83, 0xC4, 0x28, 0xC3]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'standard-credit-freeze',
|
||||
name: "Credit freeze",
|
||||
tooltip: "Prevents credits from being used. At least one credit must be available to start the game or purchase premium tickets.",
|
||||
patches: [
|
||||
{ offset: 0x2AB4E8, off: [0x28], on: [0x08] }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'standard-openssl-fix',
|
||||
name: "OpenSSL SHA crash bug fix",
|
||||
tooltip: "Fixes crashing on 10th generation and newer Intel CPUs",
|
||||
patches: [
|
||||
{ offset: 0x4A4C43, off: [0x48], on: [0x4C] },
|
||||
{ offset: 0x4A4C4B, off: [0x48], on: [0x49] }
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
@ -127,28 +127,6 @@
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
filename: 'amdaemon.exe',
|
||||
version: '2.25.00',
|
||||
sha256: '00FB867D1EE821033101B8773FAC116A45DF1939D23C38E9DAFC9B86CD5A3777',
|
||||
patches: [
|
||||
{
|
||||
id: 'standard-localhost',
|
||||
name: "Allow 127.0.0.1/localhost as the network server",
|
||||
patches: [
|
||||
{ offset: 0x6E28A4, off: [0x31, 0x32, 0x37, 0x2F], on: [0x30, 0x2F, 0x38, 0x00] },
|
||||
{ offset: 0x3C94C4, off: [0xFF, 0x15, 0xC6, 0x2F, 0x1B, 0x00, 0x8B], on: [0x33, 0xC0, 0x48, 0x83, 0xC4, 0x28, 0xC3] }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'standard-credit-freeze',
|
||||
name: "Infinite credits",
|
||||
patches: [
|
||||
{ offset: 0x2BBBC8, off: [0x28], on: [0x08] }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
filename: 'chusanApp.exe',
|
||||
version: '2.30.00',
|
||||
@ -326,43 +304,25 @@
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
filename: 'amdaemon.exe',
|
||||
version: '2.30.00',
|
||||
sha256: 'd4809220578374865370e31c541ed6e406b854d8c26cfe7464c2c15145113bfd',
|
||||
patches: [
|
||||
{
|
||||
id: 'standard-localhost',
|
||||
name: 'Allow 127.0.0.1/localhost as the network server',
|
||||
patches: [
|
||||
{
|
||||
offset: 0x6e1ca4,
|
||||
off: [0x31, 0x32, 0x37, 0x2f],
|
||||
on: [0x30, 0x2f, 0x38, 0x00],
|
||||
},
|
||||
{
|
||||
offset: 0x3c88c4,
|
||||
off: [0xff, 0x15, 0xc6, 0x2f, 0x1b, 0x00, 0x8b],
|
||||
on: [0x33, 0xc0, 0x48, 0x83, 0xc4, 0x28, 0xc3],
|
||||
},
|
||||
],
|
||||
id: 'standard-custom-free-play-length',
|
||||
type: 'number',
|
||||
name: 'Custom FREE PLAY text length',
|
||||
tooltip: 'Changes the length of the text displayed when Force FREE PLAY credit text is enabled',
|
||||
danger: 'If this is longer than 11 characters, \"Force FREE PLAY credit text\" MUST be enabled.',
|
||||
offset: 0x3875A9,
|
||||
size: 1,
|
||||
default: 9,
|
||||
min: 0,
|
||||
max: 27,
|
||||
},
|
||||
{
|
||||
id: 'standard-credit-freeze',
|
||||
name: 'Credit freeze',
|
||||
tooltip: 'Prevents credits from being used. At least one credit must be available to start the game or purchase premium tickets.',
|
||||
patches: [{ offset: 0x2bafc8, off: [0x28], on: [0x08] }],
|
||||
},
|
||||
{
|
||||
id: 'standard-openssl-fix',
|
||||
name: 'OpenSSL SHA crash bug fix',
|
||||
tooltip: 'Fix crashes on 10th generation and newer Intel CPUs',
|
||||
patches: [
|
||||
{ offset: 0x4d4a43, off: [0x48], on: [0x4c] },
|
||||
{ offset: 0x4d4a4b, off: [0x48], on: [0x49] },
|
||||
],
|
||||
id: 'standard-custom-free-play-text',
|
||||
type: 'hex',
|
||||
name: 'Custom FREE PLAY text',
|
||||
tooltip: 'Replace the FREE PLAY text when using Infinite credits',
|
||||
offset: 0x1A5DFB4,
|
||||
off: [0x46, 0x52, 0x45, 0x45, 0x20, 0x50, 0x4c, 0x41, 0x59],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "STARTLINER",
|
||||
"version": "0.13.0",
|
||||
"version": "0.21.0",
|
||||
"identifier": "zip.patafour.startliner",
|
||||
"build": {
|
||||
"beforeDevCommand": "bun run dev",
|
||||
|
@ -20,15 +20,16 @@ import OptionList from './OptionList.vue';
|
||||
import PatchList from './PatchList.vue';
|
||||
import ProfileList from './ProfileList.vue';
|
||||
import StartButton from './StartButton.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import {
|
||||
useClientStore,
|
||||
useGeneralStore,
|
||||
usePkgStore,
|
||||
usePrfStore,
|
||||
} from '../stores';
|
||||
import { Dirs } from '../types';
|
||||
import { messageSplit, shouldPreferDark } from '../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
document.documentElement.classList.toggle('use-dark-mode', shouldPreferDark());
|
||||
|
||||
@ -37,10 +38,10 @@ const prf = usePrfStore();
|
||||
const general = useGeneralStore();
|
||||
const client = useClientStore();
|
||||
|
||||
client.load();
|
||||
|
||||
pkg.setupListeners();
|
||||
|
||||
const currentTab: Ref<'users' | 'loc' | 'patches' | 'rmt' | 'cfg' | 'info'> =
|
||||
ref('users');
|
||||
const pkgSearchTerm = ref('');
|
||||
|
||||
const isProfileDisabled = computed(() => prf.current === null);
|
||||
@ -56,17 +57,11 @@ listen<undefined>('update-end', (_) => {
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
invoke('list_directories').then((d) => {
|
||||
general.dirs = d as Dirs;
|
||||
client.load();
|
||||
});
|
||||
|
||||
const fetch_promise = pkg.fetch(true);
|
||||
|
||||
await Promise.all([prf.reloadList(), prf.reload()]);
|
||||
|
||||
if (prf.current !== null) {
|
||||
currentTab.value = 'loc';
|
||||
await pkg.reloadAll();
|
||||
}
|
||||
|
||||
@ -211,34 +206,34 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
||||
|
||||
<Tabs
|
||||
lazy
|
||||
:value="currentTab"
|
||||
:value="client.currentTab"
|
||||
v-on:update:value="
|
||||
(value) => {
|
||||
currentTab = value as any;
|
||||
client.currentTab = value as string;
|
||||
client.save();
|
||||
}
|
||||
"
|
||||
class="h-screen"
|
||||
>
|
||||
<div class="fixed w-full flex z-100">
|
||||
<TabList class="grow" :show-navigators="false">
|
||||
<Tab value="users"><div class="pi pi-users"></div></Tab>
|
||||
<Tab value="users"><div class="pi pi-home"></div></Tab>
|
||||
<Tab
|
||||
:disabled="
|
||||
isProfileDisabled || pkg.networkStatus !== 'online'
|
||||
"
|
||||
value="rmt"
|
||||
><div class="pi pi-download"></div
|
||||
></Tab>
|
||||
<Tab :disabled="isProfileDisabled" value="loc"
|
||||
><div class="pi pi-box"></div
|
||||
></Tab>
|
||||
<Tab
|
||||
v-if="
|
||||
prf.current?.meta.game === 'chunithm' &&
|
||||
prf.current.data.sgt.target.length > 0
|
||||
"
|
||||
v-if="(prf.current?.data.sgt.target.length ?? 0) > 0"
|
||||
value="patches"
|
||||
><div class="pi pi-ticket"></div
|
||||
></Tab>
|
||||
<Tab
|
||||
v-if="pkg.networkStatus === 'online'"
|
||||
:disabled="isProfileDisabled"
|
||||
value="rmt"
|
||||
><div class="pi pi-download"></div
|
||||
></Tab>
|
||||
|
||||
<Tab :disabled="isProfileDisabled" value="cfg"
|
||||
><div class="pi pi-cog"></div
|
||||
></Tab>
|
||||
@ -251,17 +246,21 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
||||
<div class="flex gap-4">
|
||||
<div
|
||||
class="flex"
|
||||
v-if="['loc', 'rmt', 'cfg'].includes(currentTab)"
|
||||
v-if="
|
||||
['loc', 'rmt', 'cfg'].includes(
|
||||
client.currentTab
|
||||
)
|
||||
"
|
||||
>
|
||||
<InputIcon class="self-center mr-2">
|
||||
<i class="pi pi-search" />
|
||||
</InputIcon>
|
||||
<InputText
|
||||
v-if="currentTab === 'cfg'"
|
||||
v-if="client.currentTab === 'cfg'"
|
||||
style="min-width: 0; width: 25dvw"
|
||||
class="self-center"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
:placeholder="t('search')"
|
||||
v-model="general.cfgSearchTerm"
|
||||
/>
|
||||
<InputText
|
||||
@ -269,7 +268,7 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
||||
style="min-width: 0; width: 25dvw"
|
||||
class="self-center"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
:placeholder="t('search')"
|
||||
v-model="pkgSearchTerm"
|
||||
/>
|
||||
</div>
|
||||
@ -296,7 +295,7 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
||||
pkg.hasAvailableUpdates
|
||||
"
|
||||
icon="pi pi-download"
|
||||
label="UPDATE ALL"
|
||||
:label="t('updateAll')"
|
||||
size="small"
|
||||
class="mr-4 m-2.5"
|
||||
@click="pkg.updateAll()"
|
||||
@ -307,19 +306,19 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
||||
</TabList>
|
||||
</div>
|
||||
<TabPanels class="w-full grow mt-[3rem]">
|
||||
<TabPanel value="loc">
|
||||
<TabPanel value="loc" v-if="!isProfileDisabled">
|
||||
<ModList :search="pkgSearchTerm" />
|
||||
</TabPanel>
|
||||
<TabPanel value="rmt">
|
||||
<TabPanel value="rmt" v-if="!isProfileDisabled">
|
||||
<ModStore :search="pkgSearchTerm" />
|
||||
</TabPanel>
|
||||
<TabPanel value="cfg">
|
||||
<TabPanel value="cfg" v-if="!isProfileDisabled">
|
||||
<OptionList />
|
||||
</TabPanel>
|
||||
<TabPanel value="users">
|
||||
<ProfileList />
|
||||
</TabPanel>
|
||||
<TabPanel value="patches">
|
||||
<TabPanel value="patches" v-if="!isProfileDisabled">
|
||||
<PatchList
|
||||
v-if="
|
||||
pkg.hasLocal('mempatcher-mempatcher') &&
|
||||
@ -350,7 +349,12 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
||||
<InfoPage />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
<div v-if="currentTab === 'users' || currentTab === 'info'">
|
||||
<div
|
||||
v-if="
|
||||
client.currentTab === 'users' ||
|
||||
client.currentTab === 'info'
|
||||
"
|
||||
>
|
||||
<img
|
||||
v-if="prf.current?.meta.game === 'ongeki'"
|
||||
src="/sticker-ongeki.svg"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import Button from 'primevue/button';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
@ -12,6 +12,7 @@ const props = defineProps({
|
||||
filename: String,
|
||||
promptname: String,
|
||||
extension: String,
|
||||
defaultValue: String,
|
||||
});
|
||||
|
||||
const exists = ref(false);
|
||||
@ -35,6 +36,12 @@ const save = async () => {
|
||||
};
|
||||
|
||||
const filePick = async () => {
|
||||
if (props.defaultValue !== undefined) {
|
||||
contents.value = props.defaultValue;
|
||||
exists.value = true;
|
||||
await save();
|
||||
return;
|
||||
}
|
||||
const p = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
@ -54,13 +61,13 @@ const filePick = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
(async () => {
|
||||
onMounted(async () => {
|
||||
if (props.filename === undefined) {
|
||||
throw new Error('FileEditor without a filename');
|
||||
}
|
||||
target_path.value = await path.join(await prf.configDir, props.filename);
|
||||
await load(target_path.value);
|
||||
})();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -12,8 +12,8 @@ invoke('get_changelog').then((s) => (changelog.value = s as string));
|
||||
|
||||
<template>
|
||||
<h1>About</h1>
|
||||
STARTLINER is a simple launcher, configuration tool and mod manager for
|
||||
O.N.G.E.K.I. and CHUNITHM.
|
||||
STARTLINER is a configuration tool, mod manager and start.bat automation
|
||||
engine for O.N.G.E.K.I. and CHUNITHM.
|
||||
<h1>Changelog</h1>
|
||||
<ScrollPanel style="height: 200px">
|
||||
<div class="markdown">
|
||||
|
@ -53,6 +53,6 @@ const remove = async () => {
|
||||
class="self-center ml-4"
|
||||
style="width: 2rem; height: 2rem"
|
||||
:loading="pkg?.js.downloading"
|
||||
v-on:click="async () => await pkgs.install(pkg)"
|
||||
v-on:click="async () => await pkgs.install(pkg, true)"
|
||||
/>
|
||||
</template>
|
||||
|
@ -4,6 +4,9 @@ import InputText from 'primevue/inputtext';
|
||||
import { fromKeycode, toKeycode } from '../keyboard';
|
||||
import { usePrfStore } from '../stores';
|
||||
import { OngekiButtons } from '../types';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
|
||||
@ -61,6 +64,10 @@ const handleKey = (
|
||||
}
|
||||
}
|
||||
|
||||
if (event.code === 'Escape') {
|
||||
keycode = 0;
|
||||
}
|
||||
|
||||
if (index !== undefined) {
|
||||
data[button][index] = keycode;
|
||||
} else {
|
||||
@ -160,13 +167,24 @@ const fontSize = computed(() => {
|
||||
<InputText
|
||||
:style="{
|
||||
width: small ? '2.8rem' : '5rem',
|
||||
height: small ? '2.8rem' : tall ? '10rem' : '5rem',
|
||||
height:
|
||||
small && tall
|
||||
? '5rem'
|
||||
: small
|
||||
? '2.8rem'
|
||||
: tall
|
||||
? '10rem'
|
||||
: '5rem',
|
||||
fontSize,
|
||||
backgroundColor: color,
|
||||
}"
|
||||
unstyled
|
||||
class="text-center buttoninputtext"
|
||||
v-tooltip="tooltip ? `${tooltip}: ${modelValue}` : undefined"
|
||||
v-tooltip="
|
||||
tooltip
|
||||
? `${tooltip}: ${modelValue} ${tooltip.startsWith('ir') ? `\n${t('cfg.keyboard.irTooltip')}` : ''}`
|
||||
: undefined
|
||||
"
|
||||
@contextmenu.prevent="() => {}"
|
||||
@keydown="(ev: KeyboardEvent) => handleKey(button, ev, index)"
|
||||
@mousedown="
|
||||
|
@ -1,61 +1,312 @@
|
||||
<script setup lang="ts">
|
||||
import { Ref, computed, ref } from 'vue';
|
||||
import Button from 'primevue/button';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import Fieldset from 'primevue/fieldset';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import MultiSelect from 'primevue/multiselect';
|
||||
import SelectButton from 'primevue/selectbutton';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
import ModListEntry from './ModListEntry.vue';
|
||||
import ModTitlecard from './ModTitlecard.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import { usePkgStore, usePrfStore } from '../stores';
|
||||
import { Package } from '../types';
|
||||
import { useClientStore, usePkgStore, usePrfStore } from '../stores';
|
||||
import { Feature, Game, Package } from '../types';
|
||||
import { pkgKey } from '../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
search: String,
|
||||
});
|
||||
|
||||
const pkgs = usePkgStore();
|
||||
const client = useClientStore();
|
||||
const prf = usePrfStore();
|
||||
const empty = ref(false);
|
||||
const gameSublist: Ref<string[]> = ref([]);
|
||||
|
||||
invoke('get_game_packages', {
|
||||
game: prf.current?.meta.game,
|
||||
}).then((list) => {
|
||||
gameSublist.value = list as string[];
|
||||
const loadPackages = () => {
|
||||
invoke('get_game_packages', {
|
||||
game: prf.current?.meta.game ?? null,
|
||||
}).then((list) => {
|
||||
gameSublist.value = list as string[];
|
||||
});
|
||||
};
|
||||
|
||||
loadPackages();
|
||||
|
||||
const allCategories = computed(() => {
|
||||
const res = new Set<string>();
|
||||
for (const pkg of pkgs.allLocal) {
|
||||
for (const cat of pkg.rmt?.categories ?? []) {
|
||||
res.add(cat);
|
||||
}
|
||||
}
|
||||
return [...res.values()].sort((a, b) => a.localeCompare(b));
|
||||
});
|
||||
|
||||
const group = computed(() => {
|
||||
const res = Object.assign(
|
||||
{},
|
||||
Object.groupBy(
|
||||
pkgs.allLocal
|
||||
.filter((p) => gameSublist.value.includes(pkgKey(p)))
|
||||
.filter(
|
||||
(p) =>
|
||||
props.search === undefined ||
|
||||
p.name
|
||||
.toLowerCase()
|
||||
.includes(props.search.toLowerCase()) ||
|
||||
p.namespace
|
||||
.toLowerCase()
|
||||
.includes(props.search.toLowerCase())
|
||||
)
|
||||
.sort((p1, p2) => p1.namespace.localeCompare(p2.namespace))
|
||||
.sort((p1, p2) => p1.name.localeCompare(p2.name)),
|
||||
({ namespace }) => namespace
|
||||
)
|
||||
);
|
||||
empty.value = Object.keys(res).length === 0;
|
||||
const local = computed(() => {
|
||||
return pkgs.allLocal
|
||||
.filter((p) => gameSublist.value.includes(pkgKey(p)))
|
||||
.filter((p) => p.namespace === 'local');
|
||||
});
|
||||
|
||||
const groupedList = computed(() => {
|
||||
const searchedPkgs = pkgs.allLocal
|
||||
.filter((p) => gameSublist.value.includes(pkgKey(p)))
|
||||
.filter((p) => p.namespace !== 'local')
|
||||
.filter(
|
||||
(p) =>
|
||||
props.search === undefined ||
|
||||
p.name.toLowerCase().includes(props.search.toLowerCase()) ||
|
||||
p.namespace.toLowerCase().includes(props.search.toLowerCase())
|
||||
);
|
||||
|
||||
let grouped;
|
||||
if (client.pkgListMode === 'namespace') {
|
||||
grouped = Object.groupBy(searchedPkgs, ({ namespace }) => namespace);
|
||||
} else if (client.pkgListMode === 'type') {
|
||||
grouped = {
|
||||
standard: [] as Package[],
|
||||
native: [] as Package[],
|
||||
segatools: [] as Package[],
|
||||
unsupported: [] as Package[] | undefined,
|
||||
};
|
||||
grouped.unsupported = [];
|
||||
for (const pkg of searchedPkgs) {
|
||||
const loc = pkg.loc;
|
||||
if (!loc || !loc.status || typeof loc.status === 'string') {
|
||||
grouped.unsupported.push(pkg);
|
||||
} else {
|
||||
if (
|
||||
loc.status.OK[0] &
|
||||
(Feature.GameDLL | Feature.Mempatcher | Feature.AmdDLL)
|
||||
) {
|
||||
grouped.native.push(pkg);
|
||||
} else if (loc.status.OK[0] & Feature.Mod) {
|
||||
grouped.standard.push(pkg);
|
||||
}
|
||||
if (
|
||||
loc.status.OK[0] &
|
||||
(Feature.AMNet |
|
||||
Feature.Aime |
|
||||
Feature.ChuniIO |
|
||||
Feature.ChusanHook |
|
||||
Feature.Mu3IO |
|
||||
Feature.Mu3Hook)
|
||||
) {
|
||||
grouped.segatools.push(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (grouped.unsupported.length === 0) {
|
||||
delete grouped.unsupported;
|
||||
}
|
||||
} else {
|
||||
grouped = {} as { [key: string]: Package[] };
|
||||
for (const pkg of searchedPkgs) {
|
||||
for (const cat of pkg.rmt?.categories ?? []) {
|
||||
if (client.hiddenCategories.includes(cat)) {
|
||||
continue;
|
||||
}
|
||||
if (!(cat in grouped)) {
|
||||
grouped[cat] = [] as Package[];
|
||||
}
|
||||
grouped[cat].push(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let res: [string, Package[]][] = [];
|
||||
for (const [k, v] of Object.entries(grouped)) {
|
||||
if (v !== undefined) {
|
||||
res.push([k, v]);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
client.pkgListMode === 'namespace' ||
|
||||
client.pkgListMode === 'category'
|
||||
) {
|
||||
res.sort((a, b) => `${a[0]}`.localeCompare(`${b[0]}`));
|
||||
} else if (client.pkgListMode === 'type') {
|
||||
for (const entry of res) {
|
||||
entry[0] = t(`pkglist.${entry[0]}`);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
});
|
||||
|
||||
const missing = computed(() => {
|
||||
return prf.current?.data.mods.filter((m) => !pkgs.hasLocal(m)) ?? [];
|
||||
});
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
const defaultModel = {
|
||||
name: '',
|
||||
description: '',
|
||||
website: '',
|
||||
type: 'rainy',
|
||||
games: [] as string[],
|
||||
};
|
||||
|
||||
const creatorModel = ref({ ...defaultModel });
|
||||
|
||||
const gameModel = (game: Game) =>
|
||||
computed({
|
||||
get() {
|
||||
return (creatorModel.value.games as string[]).includes(game);
|
||||
},
|
||||
set(v: boolean) {
|
||||
creatorModel.value.games = creatorModel.value.games.filter(
|
||||
(g) => g !== game
|
||||
);
|
||||
if (v) {
|
||||
creatorModel.value.games.push(game);
|
||||
}
|
||||
},
|
||||
});
|
||||
const gameModelOngeki = gameModel('ongeki');
|
||||
const gameModelChunithm = gameModel('chunithm');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Fieldset legend="Missing" v-if="(missing?.length ?? 0) > 0">
|
||||
<Dialog
|
||||
modal
|
||||
:visible="dialogVisible"
|
||||
:closable="false"
|
||||
:header="t('creator.header')"
|
||||
:style="{ width: '500px', scale: client.scaleValue }"
|
||||
class="creation-dialog"
|
||||
>
|
||||
<div style="position: absolute; left: 250px; top: 25px">
|
||||
<a
|
||||
href="https://gitea.tendokyu.moe/akanyan/STARTLINER/wiki/Package-format"
|
||||
target="_blank"
|
||||
style="text-decoration: underline"
|
||||
class="self-center"
|
||||
>{{ t('creator.packageFormat') }}</a
|
||||
>
|
||||
</div>
|
||||
<h2>{{ t('creator.basic') }}</h2>
|
||||
<div class="flex flex-col gap-3">
|
||||
<InputText
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
:placeholder="t('creator.name')"
|
||||
v-model="creatorModel.name"
|
||||
/>
|
||||
<InputText
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
:placeholder="t('creator.description')"
|
||||
v-model="creatorModel.description"
|
||||
/>
|
||||
<InputText
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
:placeholder="t('creator.website')"
|
||||
v-model="creatorModel.website"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2>{{ t('creator.type') }}</h2>
|
||||
<div class="flex flex-col items-center">
|
||||
<SelectButton
|
||||
:options="[
|
||||
{ title: t('creator.rainy'), value: 'rainy' },
|
||||
{ title: t('creator.native'), value: 'native' },
|
||||
{ title: t('creator.segatools'), value: 'segatools' },
|
||||
]"
|
||||
v-model="creatorModel.type"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2>{{ t('creator.games') }}</h2>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-row">
|
||||
<div class="grow">{{ t('game.ongeki') }}</div>
|
||||
<ToggleSwitch v-model="gameModelOngeki" />
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="grow">{{ t('game.chunithm') }}</div>
|
||||
<ToggleSwitch v-model="gameModelChunithm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row mt-5">
|
||||
<Button
|
||||
class="ml-auto mr-1"
|
||||
style="width: 80px"
|
||||
:label="t('ok')"
|
||||
:disabled="creatorModel.games.length === 0"
|
||||
@click="
|
||||
async () => {
|
||||
await invoke('create_package', creatorModel);
|
||||
await pkgs.reloadAll();
|
||||
loadPackages();
|
||||
dialogVisible = false;
|
||||
creatorModel = { ...defaultModel };
|
||||
}
|
||||
"
|
||||
/>
|
||||
<Button
|
||||
class="mr-auto ml-1"
|
||||
style="width: 80px"
|
||||
:label="t('cancel')"
|
||||
@click="
|
||||
() => (
|
||||
(dialogVisible = false),
|
||||
(creatorModel = { ...defaultModel })
|
||||
)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</Dialog>
|
||||
<div class="flex flex-row">
|
||||
<SelectButton
|
||||
:options="[
|
||||
{ title: t('pkglist.namespace'), value: 'namespace' },
|
||||
{ title: t('pkglist.type'), value: 'type' },
|
||||
{ title: t('pkglist.category'), value: 'category' },
|
||||
]"
|
||||
v-model="client.pkgListMode"
|
||||
v-on:update:model-value="
|
||||
client.save();
|
||||
emit('reload-icons');
|
||||
"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="grow text-right mr-2 self-center"
|
||||
v-if="client.pkgListMode === 'category'"
|
||||
>
|
||||
{{ t('pkglist.exclusions') }}
|
||||
</div>
|
||||
<MultiSelect
|
||||
v-if="client.pkgListMode === 'category'"
|
||||
style="width: 30%"
|
||||
:showToggleAll="false"
|
||||
v-model="client.hiddenCategories"
|
||||
v-on:value-change="
|
||||
client.save();
|
||||
emit('reload-icons');
|
||||
"
|
||||
:options="allCategories"
|
||||
class="w-full grow"
|
||||
/>
|
||||
</div>
|
||||
<Fieldset :legend="t('pkglist.missing')" v-if="(missing?.length ?? 0) > 0">
|
||||
<div class="flex items-center" v-for="p in missing">
|
||||
<ModTitlecard
|
||||
show-namespace
|
||||
@ -78,8 +329,28 @@ const missing = computed(() => {
|
||||
/>
|
||||
</div>
|
||||
</Fieldset>
|
||||
<Fieldset v-for="(namespace, key) in group" :legend="key.toString()">
|
||||
<ModListEntry v-for="p in namespace" :pkg="p" />
|
||||
<Fieldset :legend="t('pkglist.local')">
|
||||
<ModListEntry v-for="p in local" :pkg="p" />
|
||||
<Button
|
||||
rounded
|
||||
icon="pi pi-plus"
|
||||
severity="success"
|
||||
aria-label="install"
|
||||
size="small"
|
||||
class="self-center"
|
||||
style="width: 2rem; height: 2rem"
|
||||
v-on:click="() => (dialogVisible = true)"
|
||||
/>
|
||||
</Fieldset>
|
||||
<Fieldset v-for="[namespace, pkgs] in groupedList" :legend="namespace">
|
||||
<ModListEntry v-for="p in pkgs" :pkg="p" />
|
||||
</Fieldset>
|
||||
<div v-if="empty === true" class="text-3xl fadein">∅</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.creation-dialog h2 {
|
||||
margin-top: 0.6em;
|
||||
margin-bottom: 0.4em;
|
||||
font-size: 110%;
|
||||
}
|
||||
</style>
|
||||
|
@ -7,12 +7,16 @@ import LinkButton from './LinkButton.vue';
|
||||
import ModTitlecard from './ModTitlecard.vue';
|
||||
import UpdateButton from './UpdateButton.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import { usePkgStore, usePrfStore } from '../stores';
|
||||
import { useClientStore, usePkgStore, usePrfStore } from '../stores';
|
||||
import { Feature, Package } from '../types';
|
||||
import { hasFeature } from '../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
const pkgs = usePkgStore();
|
||||
const client = useClientStore();
|
||||
|
||||
const props = defineProps({
|
||||
pkg: Object as () => Package,
|
||||
@ -36,14 +40,15 @@ if (unsupported.value === true && model.value === true) {
|
||||
|
||||
<template>
|
||||
<div class="flex items-center">
|
||||
<ModTitlecard show-version show-icon show-description :pkg="pkg" />
|
||||
<ModTitlecard
|
||||
show-version
|
||||
show-icon
|
||||
show-description
|
||||
:show-namespace="client.pkgListMode !== 'namespace'"
|
||||
:pkg="pkg"
|
||||
/>
|
||||
<UpdateButton :pkg="pkg" />
|
||||
<span
|
||||
v-tooltip="
|
||||
unsupported &&
|
||||
'This package is currently incompatible with STARTLINER.'
|
||||
"
|
||||
>
|
||||
<span v-tooltip="unsupported && t('store.incompatible')">
|
||||
<ToggleSwitch
|
||||
v-if="hasFeature(pkg, Feature.Mod) || unsupported === true"
|
||||
class="scale-[1.33] shrink-0"
|
||||
|
@ -8,6 +8,9 @@ import ModStoreEntry from './ModStoreEntry.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import { usePkgStore, usePrfStore } from '../stores';
|
||||
import { pkgKey } from '../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const pkgs = usePkgStore();
|
||||
const prf = usePrfStore();
|
||||
@ -20,7 +23,7 @@ const props = defineProps({
|
||||
const gameSublist: Ref<string[]> = ref([]);
|
||||
|
||||
invoke('get_game_packages', {
|
||||
game: prf.current?.meta.game,
|
||||
game: prf.current?.meta.game ?? null,
|
||||
}).then((list) => {
|
||||
gameSublist.value = list as string[];
|
||||
});
|
||||
@ -43,10 +46,10 @@ const list = () => {
|
||||
};
|
||||
|
||||
const shouldShowRecommended = computed(() => {
|
||||
if (prf.current!.meta.game === 'ongeki') {
|
||||
if (prf.current?.meta.game === 'ongeki') {
|
||||
return !pkgs.allLocal.some((p) => pkgKey(p) === 'segatools-mu3hook');
|
||||
}
|
||||
if (prf.current!.meta.game === 'chunithm') {
|
||||
if (prf.current?.meta.game === 'chunithm') {
|
||||
return (
|
||||
!pkgs.allLocal.some((p) => pkgKey(p) === 'segatools-chusanhook') ||
|
||||
!pkgs.allLocal.some((p) => pkgKey(p) === 'mempatcher-mempatcher')
|
||||
@ -55,23 +58,25 @@ const shouldShowRecommended = computed(() => {
|
||||
return false;
|
||||
});
|
||||
|
||||
const getRecommendedTooltip = () => {
|
||||
if (prf.current!.meta.game === 'ongeki') {
|
||||
const recommendedTooltip = computed(() => {
|
||||
if (prf.current?.meta.game === 'ongeki') {
|
||||
return 'segatools-mu3hook';
|
||||
}
|
||||
if (prf.current!.meta.game === 'chunithm') {
|
||||
return 'segatools-chusanhook and mempatcher';
|
||||
if (prf.current?.meta.game === 'chunithm') {
|
||||
return 'segatools-chusanhook + mempatcher';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
});
|
||||
|
||||
const installRecommended = () => {
|
||||
if (prf.current!.meta.game === 'ongeki') {
|
||||
if (prf.current?.meta.game === 'ongeki') {
|
||||
pkgs.installFromKey('segatools-mu3hook');
|
||||
prf.current.data.sgt.hook = 'segatools-mu3hook';
|
||||
}
|
||||
if (prf.current!.meta.game === 'chunithm') {
|
||||
if (prf.current?.meta.game === 'chunithm') {
|
||||
pkgs.installFromKey('segatools-chusanhook');
|
||||
pkgs.installFromKey('mempatcher-mempatcher');
|
||||
prf.current.data.sgt.hook = 'segatools-chusanhook';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -80,15 +85,17 @@ const installRecommended = () => {
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<div class="grow">Show installed</div>
|
||||
<div class="grow">{{ t('store.installed') }}</div>
|
||||
<ToggleSwitch v-model="pkgs.showInstalled" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="text-amber-400 grow">Show deprecated</div>
|
||||
<div class="text-amber-400 grow">
|
||||
{{ t('store.deprecated') }}
|
||||
</div>
|
||||
<ToggleSwitch v-model="pkgs.showDeprecated" />
|
||||
</div>
|
||||
<!-- <div class="flex gap-2">
|
||||
<div class="text-red-400 grow">Show NSFW</div>
|
||||
<div class="text-red-400 grow">{{ t('store.nsfw') }}</div>
|
||||
<ToggleSwitch v-model="pkgs.showNSFW" />
|
||||
</div> -->
|
||||
</div>
|
||||
@ -96,7 +103,7 @@ const installRecommended = () => {
|
||||
<MultiSelect
|
||||
size="small"
|
||||
:showToggleAll="false"
|
||||
placeholder="Include categories"
|
||||
:placeholder="t('store.includeCategories')"
|
||||
v-model="pkgs.includeCategories"
|
||||
:options="[...pkgs.availableCategories]"
|
||||
class="w-full"
|
||||
@ -104,7 +111,7 @@ const installRecommended = () => {
|
||||
<MultiSelect
|
||||
size="small"
|
||||
:showToggleAll="false"
|
||||
placeholder="Exclude categories"
|
||||
:placeholder="t('store.excludeCategories')"
|
||||
v-model="pkgs.excludeCategories"
|
||||
:options="[...pkgs.availableCategories]"
|
||||
class="w-full"
|
||||
@ -114,8 +121,8 @@ const installRecommended = () => {
|
||||
<Divider />
|
||||
<Button
|
||||
v-if="shouldShowRecommended"
|
||||
label="Install recommended packages"
|
||||
v-tooltip="getRecommendedTooltip"
|
||||
:label="t('store.installRecommended')"
|
||||
v-tooltip="recommendedTooltip"
|
||||
icon="pi pi-plus"
|
||||
class="mb-3"
|
||||
@click="installRecommended"
|
||||
|
@ -1,9 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import Chip from 'primevue/chip';
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { invoke } from '../invoke';
|
||||
import { Feature, Package } from '../types';
|
||||
import { hasFeature, needsUpdate } from '../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
pkg: Object as () => Package,
|
||||
@ -14,23 +19,34 @@ const props = defineProps({
|
||||
showIcon: Boolean,
|
||||
});
|
||||
|
||||
const iconSrc = computed(() => {
|
||||
const icon = props.pkg?.loc?.icon ?? props.pkg?.rmt?.icon;
|
||||
const icon = ref('/no-icon.png');
|
||||
|
||||
if (icon === undefined) {
|
||||
return '';
|
||||
} else if (icon.startsWith('https://')) {
|
||||
return icon;
|
||||
const reloadIcons = async () => {
|
||||
const src = props.pkg?.loc?.icon ?? props.pkg?.rmt?.icon;
|
||||
|
||||
if (src === undefined) {
|
||||
icon.value = '/no-icon.png';
|
||||
} else if (src.startsWith('https://')) {
|
||||
icon.value = src;
|
||||
} else {
|
||||
return convertFileSrc(icon);
|
||||
const convt = convertFileSrc(src);
|
||||
if (await invoke('file_exists', { path: src })) {
|
||||
icon.value = convt;
|
||||
} else {
|
||||
icon.value = '/no-icon.png';
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
reloadIcons();
|
||||
|
||||
listen('reload-icons', reloadIcons);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<img
|
||||
v-if="showIcon"
|
||||
:src="iconSrc"
|
||||
:src="icon"
|
||||
class="self-center rounded-sm"
|
||||
width="32px"
|
||||
height="32px"
|
||||
@ -89,7 +105,12 @@ const iconSrc = computed(() => {
|
||||
v-if="showNamespace && pkg?.namespace"
|
||||
class="text-sm opacity-75"
|
||||
>
|
||||
by {{ pkg.namespace }}
|
||||
{{
|
||||
t('by', { namespace: pkg.namespace }).replaceAll(
|
||||
' ',
|
||||
' '
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<span class="m-2">
|
||||
<span
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ComputedRef, computed, onMounted, ref } from 'vue';
|
||||
import { ComputedRef, computed, ref } from 'vue';
|
||||
import Button from 'primevue/button';
|
||||
import Carousel from 'primevue/carousel';
|
||||
import Dialog from 'primevue/dialog';
|
||||
@ -7,6 +7,9 @@ import { fromKeycode } from '../keyboard';
|
||||
import { useClientStore, usePrfStore } from '../stores';
|
||||
import { prettyPrint } from '../util';
|
||||
import { VueMarkdownIt } from '@f3ve/vue-markdown-it';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
const client = useClientStore();
|
||||
@ -24,38 +27,73 @@ interface Datum {
|
||||
|
||||
const game = computed(() => prf.current?.meta.game);
|
||||
|
||||
const processText = (s: string) => {
|
||||
const processText = computed(() => (s: string) => {
|
||||
// Why do I have to do this
|
||||
s = s
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.join('\n');
|
||||
if (prf.current!.data.keyboard?.data.enabled) {
|
||||
const testKey = prf.current!.data.keyboard?.data.test;
|
||||
const readable = fromKeycode(testKey);
|
||||
if (readable !== null) {
|
||||
return s.replace(
|
||||
'%TESTMENU%',
|
||||
`${readable} or a button on the back of the controller`
|
||||
`${readable} ${t('onboarding.or')} ${t('onboarding.backButton')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
return s.replace('%TESTMENU%', 'a button on the back of the controller');
|
||||
};
|
||||
return s.replace('%TESTMENU%', t('onboarding.backButton'));
|
||||
});
|
||||
|
||||
const loadPage = async (title: string) => {
|
||||
const loadPage = computed(() => (title: string, messages?: object) => {
|
||||
return {
|
||||
text: await (await fetch(`/help-${title}.md`)).text(),
|
||||
text: t(`onboarding.${title}`, {
|
||||
endlink: '</a>',
|
||||
black: '<span class="bg-black text-white">',
|
||||
end: '</span>',
|
||||
...messages,
|
||||
}),
|
||||
image: `help-${title}.png`,
|
||||
};
|
||||
};
|
||||
|
||||
let systemProcessing: Datum;
|
||||
let standardOngeki: Datum;
|
||||
let standardChunithm: Datum;
|
||||
let lever: Datum;
|
||||
let server: Datum;
|
||||
let finaleOngeki: Datum;
|
||||
let finaleChunithm: Datum;
|
||||
});
|
||||
|
||||
const data: ComputedRef<Datum[]> = computed(() => {
|
||||
const res = [];
|
||||
|
||||
const [standard, systemProcessing, lever, server, finale] = [
|
||||
loadPage.value('standard', {
|
||||
bigblack: '<div class="p-2 mt-1 mb-1 bg-black text-white">',
|
||||
endbig: '</div>',
|
||||
}),
|
||||
loadPage.value('ongeki-system-processing'),
|
||||
loadPage.value('ongeki-lever'),
|
||||
loadPage.value('chunithm-server', {
|
||||
link: '<a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ#game-is-stuck-at-checking-distribution-server" target="_blank">',
|
||||
}),
|
||||
loadPage.value('finale', {
|
||||
segaguide:
|
||||
'<a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ" target="_blank">',
|
||||
twotorial: '<a href="https://two-torial.xyz/" target="_blank">',
|
||||
}),
|
||||
];
|
||||
const standardOngeki = {
|
||||
...standard,
|
||||
image: '/help-standard-ongeki.png',
|
||||
};
|
||||
const standardChunithm = {
|
||||
...standard,
|
||||
image: '/help-standard-chunithm.png',
|
||||
};
|
||||
const finaleOngeki = {
|
||||
...finale,
|
||||
image: '/help-finale-ongeki.png',
|
||||
};
|
||||
const finaleChunithm = {
|
||||
...finale,
|
||||
image: '/help-finale-chunithm.png',
|
||||
};
|
||||
|
||||
switch (prf.current?.meta.game) {
|
||||
case 'ongeki':
|
||||
res.push(systemProcessing);
|
||||
@ -75,40 +113,18 @@ const data: ComputedRef<Datum[]> = computed(() => {
|
||||
return res;
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
[standardOngeki, systemProcessing, lever, server, finaleOngeki] =
|
||||
await Promise.all([
|
||||
loadPage('standard'),
|
||||
loadPage('ongeki-system-processing'),
|
||||
loadPage('ongeki-lever'),
|
||||
loadPage('chunithm-server'),
|
||||
loadPage('finale'),
|
||||
]);
|
||||
standardOngeki = {
|
||||
...standardOngeki,
|
||||
image: '/help-standard-ongeki.png',
|
||||
};
|
||||
standardChunithm = {
|
||||
...standardOngeki,
|
||||
image: '/help-standard-chunithm.png',
|
||||
};
|
||||
finaleOngeki = {
|
||||
...finaleOngeki,
|
||||
image: '/help-finale-ongeki.png',
|
||||
};
|
||||
finaleChunithm = {
|
||||
...finaleOngeki,
|
||||
image: '/help-finale-chunithm.png',
|
||||
};
|
||||
const context = ref({
|
||||
index: 0,
|
||||
});
|
||||
|
||||
const counter = ref(0);
|
||||
|
||||
const exitLabel = computed(() => {
|
||||
return props.firstTime === true && counter.value < data.value.length - 1
|
||||
? 'Skip'
|
||||
: 'Close';
|
||||
return props.firstTime === true &&
|
||||
context.value.index < data.value.length - 1
|
||||
? t('skip')
|
||||
: t('close');
|
||||
});
|
||||
|
||||
const page = ref(0);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -122,13 +138,15 @@ const exitLabel = computed(() => {
|
||||
: `${game ? prettyPrint(game) : '<game>'} help`
|
||||
"
|
||||
:style="{ width: '760px', scale: client.scaleValue }"
|
||||
v-on:show="() => ((context.index = 0), (page = 0))"
|
||||
>
|
||||
<Carousel
|
||||
:value="data"
|
||||
:num-visible="1"
|
||||
:num-scroll="1"
|
||||
:page="counter"
|
||||
v-on:update:page="(p) => (counter = p)"
|
||||
:context="context"
|
||||
:page="page"
|
||||
v-on:update:page="(p) => ((context.index = p), (page = p))"
|
||||
>
|
||||
<template #item="slotProps">
|
||||
<div class="md-container markdown">
|
||||
@ -150,10 +168,10 @@ const exitLabel = computed(() => {
|
||||
</Carousel>
|
||||
<div style="width: 100%; text-align: center">
|
||||
<Button
|
||||
v-if="counter < data.length - 1"
|
||||
v-if="context.index < data.length - 1"
|
||||
class="m-auto mr-4"
|
||||
label="Next"
|
||||
@click="() => (counter += 1)"
|
||||
:label="t('next')"
|
||||
@click="() => (page += 1)"
|
||||
/>
|
||||
<Button
|
||||
class="m-auto"
|
||||
|
@ -14,6 +14,9 @@ import NetworkOptions from './options/Network.vue';
|
||||
import SegatoolsOptions from './options/Segatools.vue';
|
||||
import StartlinerOptions from './options/Startliner.vue';
|
||||
import { usePrfStore } from '../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
|
||||
@ -57,10 +60,10 @@ prf.reload();
|
||||
<AimeOptions />
|
||||
<MiscOptions />
|
||||
<OptionCategory
|
||||
title="Extensions"
|
||||
v-if="prf.current!.meta.game === 'chunithm'"
|
||||
:title="t('cfg.extensions.title')"
|
||||
v-if="prf.current?.meta.game === 'chunithm'"
|
||||
>
|
||||
<OptionRow title="Saekawa config">
|
||||
<OptionRow :title="t('cfg.extensions.saekawa')">
|
||||
<FileEditor
|
||||
filename="saekawa.toml"
|
||||
promptname="saekawa config file"
|
||||
@ -68,31 +71,31 @@ prf.reload();
|
||||
/> </OptionRow
|
||||
></OptionCategory>
|
||||
<OptionCategory
|
||||
title="Extensions"
|
||||
v-if="prf.current!.meta.game === 'ongeki'"
|
||||
:title="t('cfg.extensions.title')"
|
||||
v-if="prf.current?.meta.game === 'ongeki'"
|
||||
>
|
||||
<OptionRow title="Inohara config">
|
||||
<OptionRow :title="t('cfg.extensions.inohara')">
|
||||
<FileEditor
|
||||
filename="inohara.cfg"
|
||||
promptname="inohara config file"
|
||||
extension="cfg"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow title="BepInEx console">
|
||||
<OptionRow :title="t('cfg.extensions.bepInExConsole')">
|
||||
<!-- @vue-expect-error -->
|
||||
<ToggleSwitch v-model="prf.current!.data.bepinex.console" />
|
||||
</OptionRow>
|
||||
|
||||
<OptionRow
|
||||
title="Audio mode"
|
||||
tooltip="Exclusive 2-channel mode requires 7EVENDAYSHOLIDAYS-ExclusiveAudio"
|
||||
:title="t('cfg.extensions.audioMode')"
|
||||
:tooltip="t('cfg.extensions.audioTooltip')"
|
||||
>
|
||||
<SelectButton
|
||||
v-model="prf.current!.data.mu3_ini!.audio"
|
||||
:options="[
|
||||
{ title: 'Shared', value: 'Shared' },
|
||||
{ title: 'Exclusive 6-channel', value: 'Excl6Ch' },
|
||||
{ title: 'Exclusive 2-channel', value: 'Excl2Ch' },
|
||||
{ title: t('cfg.extensions.audioShared'), value: 'Shared' },
|
||||
{ title: t('cfg.extensions.audio6Ch'), value: 'Excl6Ch' },
|
||||
{ title: t('cfg.extensions.audio2Ch'), value: 'Excl2Ch' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
@ -100,7 +103,7 @@ prf.reload();
|
||||
/></OptionRow>
|
||||
|
||||
<OptionRow
|
||||
title="Sample rate"
|
||||
:title="t('cfg.extensions.sampleRate')"
|
||||
v-if="
|
||||
prf.current?.data.mods.includes(
|
||||
'7EVENDAYSHOLIDAYS-ExclusiveAudio'
|
||||
@ -126,8 +129,8 @@ prf.reload();
|
||||
prf.current?.data.mods.includes('7EVENDAYSHOLIDAYS-Blacklist')
|
||||
"
|
||||
class="number-input"
|
||||
title="Song ID Blacklist"
|
||||
tooltip="Scores on charts within this ID range will not be saved nor uploaded"
|
||||
:title="t('cfg.extensions.blacklist')"
|
||||
:tooltip="t('cfg.extensions.blacklistTooltip')"
|
||||
><InputNumber
|
||||
class="shrink"
|
||||
size="small"
|
||||
@ -165,8 +168,8 @@ prf.reload();
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Unlock Bonus Tracks"
|
||||
tooltip="Disabling this option can help declutter the song list"
|
||||
:title="t('cfg.extensions.bonusTracks')"
|
||||
:tooltip="t('cfg.extensions.bonusTracksTooltip')"
|
||||
v-if="
|
||||
prf.current?.data.mods.includes(
|
||||
'7EVENDAYSHOLIDAYS-UnlockAllMusic'
|
||||
|
@ -1,9 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import InputNumber from 'primevue/inputnumber';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import OptionRow from './OptionRow.vue';
|
||||
import { usePrfStore } from '../stores';
|
||||
import { Patch } from '../types';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t, te } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
|
||||
@ -23,20 +28,40 @@ const setNumber = (key: string, val: number) => {
|
||||
}
|
||||
};
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
patch: Object as () => Patch,
|
||||
});
|
||||
|
||||
// One day, I will repent
|
||||
const hexModel = computed({
|
||||
get() {
|
||||
const hex = (prf.current!.data.patches[props.patch!.id!] as any)?.hex;
|
||||
if (hex !== undefined) {
|
||||
return new TextDecoder().decode(new Int8Array(hex).buffer);
|
||||
} else {
|
||||
return 'FREE PLAY';
|
||||
}
|
||||
},
|
||||
set(value: string) {
|
||||
(prf.current!.data.patches[props.patch!.id!] as any) = {
|
||||
hex: new TextEncoder().encode(value),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Doesn't need to be reactive
|
||||
const nameKey = `patch.${props.patch?.id}`;
|
||||
const name = te(nameKey) ? t(nameKey) : props.patch?.name;
|
||||
|
||||
const tooltipKey = `patch.${props.patch?.id}-tooltip`;
|
||||
const tooltip = te(tooltipKey) ? t(tooltipKey) : props.patch?.tooltip;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionRow
|
||||
:title="patch?.name"
|
||||
:tooltip="patch?.tooltip"
|
||||
:greytext="patch?.id"
|
||||
>
|
||||
<OptionRow :title="name" :tooltip="tooltip" :greytext="patch?.id">
|
||||
<ToggleSwitch
|
||||
v-if="patch?.type === undefined"
|
||||
:model-value="prf.current!.data.patches[patch!.id!] !== undefined"
|
||||
:model-value="prf.current!.data.patches?.[patch!.id!] !== undefined"
|
||||
@update:model-value="(v: boolean) => toggleUnary(patch!.id!, v)"
|
||||
/>
|
||||
<InputNumber
|
||||
@ -50,5 +75,6 @@ defineProps({
|
||||
:max="patch?.max"
|
||||
:placeholder="(patch?.default ?? 0).toString()"
|
||||
/>
|
||||
<InputText v-else-if="patch?.type === 'hex'" v-model="hexModel" />
|
||||
</OptionRow>
|
||||
</template>
|
||||
|
@ -1,11 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { Ref, ref } from 'vue';
|
||||
// import Select from 'primevue/select';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import OptionCategory from './OptionCategory.vue';
|
||||
import PatchEntry from './PatchEntry.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import { usePrfStore } from '../stores';
|
||||
import { Patch } from '../types';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
|
||||
@ -29,21 +33,22 @@ invoke('list_patches', { target: prf.current!.data.sgt.target }).then(
|
||||
target: amd,
|
||||
})) as Patch[];
|
||||
})();
|
||||
|
||||
const errorMessage =
|
||||
"No compatible patches found. Make sure you're using unpacked and unpatched files.";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="chusanApp.exe" always-found>
|
||||
<OptionCategory
|
||||
v-if="prf.current?.meta.game === 'chunithm'"
|
||||
title="chusanApp.exe"
|
||||
always-found
|
||||
>
|
||||
<PatchEntry
|
||||
v-if="gamePatches !== null"
|
||||
v-for="p in gamePatches"
|
||||
:patch="p"
|
||||
/>
|
||||
<div v-if="gamePatches === null">Loading...</div>
|
||||
<div v-if="gamePatches === null">{{ t('patch.loading') }}</div>
|
||||
<div v-if="gamePatches !== null && gamePatches.length === 0">
|
||||
{{ errorMessage }}
|
||||
{{ t('patch.noneFound') }}
|
||||
</div>
|
||||
</OptionCategory>
|
||||
<OptionCategory title="amdaemon.exe" always-found>
|
||||
@ -52,9 +57,22 @@ const errorMessage =
|
||||
v-for="p in amdPatches"
|
||||
:patch="p"
|
||||
/>
|
||||
<div v-if="gamePatches === null">Loading...</div>
|
||||
<div v-if="gamePatches === null">{{ t('patch.loading') }}</div>
|
||||
<div v-if="amdPatches !== null && amdPatches.length === 0">
|
||||
{{ errorMessage }}
|
||||
{{ t('patch.noneFound') }}
|
||||
<!-- <br />
|
||||
<Select
|
||||
class="mt-3"
|
||||
style="width: 400px"
|
||||
:options="[
|
||||
{},
|
||||
{},
|
||||
]"
|
||||
:placeholder="t('patch.forceLoad')"
|
||||
size="small"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
></Select> -->
|
||||
</div>
|
||||
</OptionCategory>
|
||||
</template>
|
||||
|
@ -2,45 +2,74 @@
|
||||
import { Ref, ref } from 'vue';
|
||||
import Button from 'primevue/button';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import Select from 'primevue/select';
|
||||
import SelectButton from 'primevue/selectbutton';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import ProfileListEntry from './ProfileListEntry.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import { useClientStore, useGeneralStore, usePrfStore } from '../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
const client = useClientStore();
|
||||
const general = useGeneralStore();
|
||||
|
||||
const hasChunithm = ref(false);
|
||||
const exportVisible = ref(false);
|
||||
const exportKeychip = ref(false);
|
||||
const files = new Set<string>();
|
||||
|
||||
(async () => {
|
||||
hasChunithm.value = (
|
||||
(await invoke('list_platform_capabilities')) as string[]
|
||||
).includes('chunithm');
|
||||
})();
|
||||
|
||||
const fileList = [
|
||||
'aime.txt',
|
||||
'inohara.cfg',
|
||||
'saekawa.toml',
|
||||
'mu3.ini',
|
||||
'segatools-base.ini',
|
||||
'pre.sh',
|
||||
'pre.bat',
|
||||
'post.sh',
|
||||
'post.bat',
|
||||
];
|
||||
|
||||
const diagnosticList = {
|
||||
ongeki: ['mu3.ini', 'segatools-base.ini'],
|
||||
chunithm: ['segatools-base.ini'],
|
||||
};
|
||||
|
||||
const diagnostic = ref(false);
|
||||
|
||||
const exportTemplate = async () => {
|
||||
const fl = [...files.values()];
|
||||
exportVisible.value = false;
|
||||
await invoke('export_profile', {
|
||||
exportKeychip: exportKeychip.value,
|
||||
files: fl,
|
||||
isDiagnostic: diagnostic.value,
|
||||
files:
|
||||
diagnostic.value === true
|
||||
? diagnosticList[prf.current!.meta.game]
|
||||
: fl,
|
||||
});
|
||||
await invoke('open_file', {
|
||||
path: await path.join(general.configDir, 'exports'),
|
||||
path: await path.join(await general.configDir, 'exports'),
|
||||
});
|
||||
};
|
||||
|
||||
const fileList = {
|
||||
ongeki: ['aime.txt', 'inohara.cfg', 'mu3.ini', 'segatools-base.ini'],
|
||||
chunithm: ['aime.txt', 'saekawa.toml', 'segatools-base.ini'],
|
||||
};
|
||||
|
||||
const fileListCurrent: Ref<string[]> = ref([]);
|
||||
|
||||
const recalcFileList = async () => {
|
||||
const res: string[] = [];
|
||||
files.clear();
|
||||
for (const idx in fileList[prf.current!.meta.game]) {
|
||||
const f = fileList[prf.current!.meta.game][idx];
|
||||
for (const f of fileList) {
|
||||
const p = await path.join(await prf.configDir, f);
|
||||
if (await invoke('file_exists', { path: p })) {
|
||||
res.push(f);
|
||||
@ -61,7 +90,7 @@ const importPick = async () => {
|
||||
directory: false,
|
||||
filters: [
|
||||
{
|
||||
name: 'STARTLINER template',
|
||||
name: t('profile.template'),
|
||||
extensions: ['zip'],
|
||||
},
|
||||
],
|
||||
@ -78,17 +107,37 @@ const importPick = async () => {
|
||||
modal
|
||||
:visible="exportVisible"
|
||||
:closable="false /*this shit doesn't work */"
|
||||
:header="`Export ${prf.current?.meta.name}`"
|
||||
:style="{ width: '300px', scale: client.scaleValue }"
|
||||
:header="`${t('profile.export')} ${prf.current?.meta.name}`"
|
||||
:style="{ width: '330px', scale: client.scaleValue }"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col items-center">
|
||||
<SelectButton
|
||||
v-model="diagnostic"
|
||||
:options="[
|
||||
{
|
||||
title: t('profile.standardExport'),
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
title: t('profile.diagnostic'),
|
||||
value: true,
|
||||
},
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
>
|
||||
</SelectButton>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="grow">Export keychip</div>
|
||||
<ToggleSwitch v-model="exportKeychip" />
|
||||
<div class="grow">{{ t('profile.export') }} keychip</div>
|
||||
<ToggleSwitch :disabled="diagnostic" v-model="exportKeychip" />
|
||||
</div>
|
||||
<div class="flex flex-row" v-for="f in fileListCurrent">
|
||||
<div class="grow">Export {{ f }}</div>
|
||||
<div class="grow">{{ t('profile.export') }} {{ f }}</div>
|
||||
<ToggleSwitch
|
||||
:disabled="diagnostic"
|
||||
:model-value="true"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
@ -117,42 +166,99 @@ const importPick = async () => {
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
<div v-if="prf.list.length === 0">
|
||||
Welcome to STARTLINER! Start by creating a profile.
|
||||
</div>
|
||||
<div class="mt-4 flex flex-row flex-wrap align-middle gap-4">
|
||||
<Button
|
||||
label="O.N.G.E.K.I. profile"
|
||||
icon="pi pi-file-plus"
|
||||
class="ongeki-button profile-button"
|
||||
@click="() => prf.create('ongeki')"
|
||||
/>
|
||||
<Button
|
||||
label="CHUNITHM profile"
|
||||
icon="pi pi-file-plus"
|
||||
class="chunithm-button profile-button"
|
||||
@click="() => prf.create('chunithm')"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-row flex-wrap align-middle gap-4">
|
||||
<Button
|
||||
label="Import template"
|
||||
icon="pi pi-file-import"
|
||||
class="import-button profile-button"
|
||||
@click="() => importPick()"
|
||||
/>
|
||||
<Button
|
||||
:disabled="prf.current === null"
|
||||
label="Export template"
|
||||
icon="pi pi-file-export"
|
||||
class="profile-button"
|
||||
@click="() => openExportDialog()"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-12 flex flex-col flex-wrap align-middle gap-4">
|
||||
<div v-for="p in prf.list">
|
||||
<ProfileListEntry :p="p" />
|
||||
<div style="float: left">
|
||||
<div v-if="prf.list.length === 0">
|
||||
{{ t('profile.welcome') }}
|
||||
</div>
|
||||
<div class="mt-4 flex flex-row flex-wrap align-middle gap-4">
|
||||
<Button
|
||||
:label="t('profile.create', { game: t('game.ongeki') })"
|
||||
icon="pi pi-file-plus"
|
||||
class="ongeki-button profile-button"
|
||||
@click="() => prf.create('ongeki')"
|
||||
/>
|
||||
<Button
|
||||
v-if="hasChunithm"
|
||||
:label="t('profile.create', { game: t('game.chunithm') })"
|
||||
icon="pi pi-file-plus"
|
||||
class="chunithm-button profile-button"
|
||||
@click="() => prf.create('chunithm')"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-row flex-wrap align-middle gap-4">
|
||||
<Button
|
||||
:label="t('profile.importTemplate')"
|
||||
icon="pi pi-file-import"
|
||||
class="import-button profile-button"
|
||||
@click="() => importPick()"
|
||||
/>
|
||||
<Button
|
||||
:disabled="prf.current === null"
|
||||
:label="t('profile.exportTemplate')"
|
||||
icon="pi pi-file-export"
|
||||
class="profile-button"
|
||||
@click="() => openExportDialog()"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-12 flex flex-col flex-wrap align-middle gap-4">
|
||||
<div v-for="p in prf.list">
|
||||
<ProfileListEntry :p="p" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="float: right" class="mr-5 mt-3 flex flex-col gap-4 items-end">
|
||||
<div>
|
||||
<div class="pi pi-language mr-2"></div>
|
||||
<Select
|
||||
:model-value="client.locale"
|
||||
@update:model-value="async (v) => await client.setLocale(v)"
|
||||
style="width: 200px"
|
||||
:options="[
|
||||
{ title: 'English', value: 'en' },
|
||||
{ title: 'Español', value: 'es' },
|
||||
{ title: '한국어', value: 'ko' },
|
||||
{ title: '日本語', value: 'ja' },
|
||||
{ title: 'Polski', value: 'pl' },
|
||||
{ title: '简体中文', value: 'zh-Hans' },
|
||||
]"
|
||||
size="small"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
></Select>
|
||||
</div>
|
||||
<SelectButton
|
||||
style="height: 50px"
|
||||
v-model="client.scaleModel"
|
||||
:options="[
|
||||
{ title: 'S', size: '0.8em', value: 's' },
|
||||
{ title: 'M', size: '1.0em', value: 'm' },
|
||||
{ title: 'L', size: '1.2em', value: 'l' },
|
||||
{ title: 'XL', size: '1.4em', value: 'xl' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
><template #option="slotProps">
|
||||
<div :style="{ fontSize: slotProps.option.size }">
|
||||
{{ slotProps.option.title }}
|
||||
</div>
|
||||
</template></SelectButton
|
||||
>
|
||||
<SelectButton
|
||||
style="height: 50px"
|
||||
:model-value="client.theme"
|
||||
@update:model-value="(v) => client.setTheme(v)"
|
||||
:options="[
|
||||
{ title: 'System', value: 'system', icon: 'pi pi-home' },
|
||||
{ title: 'Light', value: 'light', icon: 'pi pi-sun' },
|
||||
{ title: 'Dark', value: 'dark', icon: 'pi pi-moon' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
><template #option="slotProps">
|
||||
<div :class="slotProps.option.icon"></div> </template
|
||||
></SelectButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -7,6 +7,9 @@ import * as path from '@tauri-apps/api/path';
|
||||
import { invoke } from '../invoke';
|
||||
import { useGeneralStore, usePrfStore } from '../stores';
|
||||
import { ProfileMeta } from '../types';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const general = useGeneralStore();
|
||||
const prf = usePrfStore();
|
||||
@ -60,18 +63,22 @@ const deleteProfile = async () => {
|
||||
|
||||
const promptDeleteProfile = async () => {
|
||||
confirmDialog.require({
|
||||
message: `Are you sure you want to delete ${props.p?.game}-${props.p?.name}?`,
|
||||
header: 'Delete profile',
|
||||
message: t('profile.reallyDelete', {
|
||||
profile: `${props.p?.game}-${props.p?.name}`,
|
||||
}),
|
||||
header: t('profile.delete'),
|
||||
accept: deleteProfile,
|
||||
});
|
||||
};
|
||||
|
||||
const dataExists = ref(false);
|
||||
|
||||
path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
|
||||
async (p) => {
|
||||
dataExists.value = await invoke('file_exists', { path: p });
|
||||
}
|
||||
general.dataDir.then((dataDir) =>
|
||||
path
|
||||
.join(dataDir, `profile-${props.p!.game}-${props.p!.name}`)
|
||||
.then(async (p) => {
|
||||
dataExists.value = await invoke('file_exists', { path: p });
|
||||
})
|
||||
);
|
||||
</script>
|
||||
|
||||
@ -140,11 +147,15 @@ path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
|
||||
class="self-center"
|
||||
style="width: 2rem; height: 2rem"
|
||||
@click="
|
||||
path
|
||||
.join(general.configDir, `profile-${p!.game}-${p!.name}`)
|
||||
.then(async (path) => {
|
||||
await invoke('open_file', { path });
|
||||
})
|
||||
async () =>
|
||||
path
|
||||
.join(
|
||||
await general.configDir,
|
||||
`profile-${p!.game}-${p!.name}`
|
||||
)
|
||||
.then(async (path) => {
|
||||
await invoke('open_file', { path });
|
||||
})
|
||||
"
|
||||
/>
|
||||
<Button
|
||||
@ -157,11 +168,15 @@ path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
|
||||
class="self-center"
|
||||
style="width: 2rem; height: 2rem"
|
||||
@click="
|
||||
path
|
||||
.join(general.dataDir, `profile-${p!.game}-${p!.name}`)
|
||||
.then(async (path) => {
|
||||
await invoke('open_file', { path });
|
||||
})
|
||||
async () =>
|
||||
path
|
||||
.join(
|
||||
await general.dataDir,
|
||||
`profile-${p!.game}-${p!.name}`
|
||||
)
|
||||
.then(async (path) => {
|
||||
await invoke('open_file', { path });
|
||||
})
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
@ -8,6 +8,9 @@ import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
import Onboarding from './Onboarding.vue';
|
||||
import { invoke } from '../invoke';
|
||||
import { useClientStore, usePrfStore } from '../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
const client = useClientStore();
|
||||
@ -24,22 +27,22 @@ const startline = async (force: boolean, refresh: boolean) => {
|
||||
if (start_check.length > 0) {
|
||||
const message = start_check.map((o) => {
|
||||
if ('MissingRemotePackage' in o) {
|
||||
return `Package missing: ${o.MissingRemotePackage}`;
|
||||
return `${t('start.error.package')}: ${o.MissingRemotePackage}`;
|
||||
} else if ('MissingLocalPackage' in o) {
|
||||
return `Package missing: ${o.MissingLocalPackage}`;
|
||||
return `${t('start.error.package')}: ${o.MissingLocalPackage}`;
|
||||
} else if ('MissingDependency' in o) {
|
||||
return `Dependency missing: ${(o.MissingDependency as string[]).join(' ')}`;
|
||||
return `${t('start.error.dependency')}: ${(o.MissingDependency as string[]).join(' ')}`;
|
||||
} else if ('MissingTool' in o) {
|
||||
return `Tool missing: ${o.MissingTool}`;
|
||||
return `${t('start.error.tool')}: ${o.MissingTool}`;
|
||||
} else {
|
||||
return 'Unknown error';
|
||||
return t('start.error.unknown');
|
||||
}
|
||||
});
|
||||
confirmDialog.require({
|
||||
message: message.join('\n'),
|
||||
header: 'Start check failed',
|
||||
acceptLabel: 'Run anyway',
|
||||
rejectLabel: 'Cancel',
|
||||
header: t('start.failed'),
|
||||
acceptLabel: t('start.accept'),
|
||||
rejectLabel: t('cancel'),
|
||||
accept: () => {
|
||||
startline(true, refresh);
|
||||
},
|
||||
@ -62,16 +65,16 @@ const kill = async () => {
|
||||
|
||||
const disabledTooltip = computed(() => {
|
||||
if (prf.current?.data.sgt.target.length === 0) {
|
||||
return 'The game path must be specified';
|
||||
return t('start.tooltip.game');
|
||||
}
|
||||
if (prf.current?.data.sgt.amfs.length === 0) {
|
||||
return 'The amfs path must be specified';
|
||||
return t('start.tooltip.amfs');
|
||||
}
|
||||
if (
|
||||
prf.current?.data.sgt.hook === null ||
|
||||
prf.current?.data.sgt.hook === undefined
|
||||
) {
|
||||
return 'A segatools hook package is necessary';
|
||||
return t('start.tooltip.segatools');
|
||||
}
|
||||
return null;
|
||||
});
|
||||
@ -96,32 +99,66 @@ const createShortcut = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: 'Refresh and start',
|
||||
icon: 'pi pi-sync',
|
||||
tooltip: 'test',
|
||||
command: async () => await startline(false, true),
|
||||
},
|
||||
{
|
||||
label: 'Start unchecked',
|
||||
icon: 'pi pi-exclamation-circle',
|
||||
command: async () => await startline(true, false),
|
||||
},
|
||||
{
|
||||
label: 'Create desktop shortcut',
|
||||
icon: 'pi pi-link',
|
||||
command: createShortcut,
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
icon: 'pi pi-question-circle',
|
||||
command: () => {
|
||||
onboardingFirstTime.value = false;
|
||||
onboardingVisible.value = true;
|
||||
const hasShortcut = ref(false);
|
||||
|
||||
(async () => {
|
||||
hasShortcut.value = (
|
||||
(await invoke('list_platform_capabilities')) as string[]
|
||||
).includes('shortcut');
|
||||
})();
|
||||
|
||||
const menuItems = computed(() => {
|
||||
let base = [
|
||||
{
|
||||
label: t('start.button.unchecked'),
|
||||
icon: 'pi pi-exclamation-circle',
|
||||
command: async () => await startline(true, false),
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
let baseTail = [
|
||||
{
|
||||
label: t('start.button.help'),
|
||||
icon: 'pi pi-question-circle',
|
||||
command: () => {
|
||||
onboardingFirstTime.value = false;
|
||||
onboardingVisible.value = true;
|
||||
},
|
||||
},
|
||||
];
|
||||
if (prf.current === null) {
|
||||
return [];
|
||||
}
|
||||
if (hasShortcut.value === true) {
|
||||
base = [
|
||||
...base,
|
||||
{
|
||||
label: t('start.button.shortcut'),
|
||||
icon: 'pi pi-link',
|
||||
command: createShortcut,
|
||||
},
|
||||
];
|
||||
}
|
||||
if (prf.current.meta.game === 'chunithm') {
|
||||
return [...base, ...baseTail];
|
||||
}
|
||||
if (prf.current.meta.game === 'ongeki') {
|
||||
return [
|
||||
{
|
||||
label: t('start.button.refresh'),
|
||||
icon: 'pi pi-sync',
|
||||
command: async () => await startline(false, true),
|
||||
},
|
||||
...base,
|
||||
{
|
||||
label: t('start.button.cache'),
|
||||
icon: 'pi pi-trash',
|
||||
command: async () => await invoke('clear_cache'),
|
||||
},
|
||||
...baseTail,
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
const menu = ref();
|
||||
|
||||
const showContextMenu = (event: Event) => {
|
||||
@ -166,7 +203,7 @@ const tryStart = () => {
|
||||
v-tooltip="disabledTooltip"
|
||||
:disabled="disabledTooltip !== null"
|
||||
icon="pi pi-play"
|
||||
label="START"
|
||||
:label="t('start.button.start')"
|
||||
aria-label="start"
|
||||
size="small"
|
||||
class="m-2.5"
|
||||
@ -177,7 +214,7 @@ const tryStart = () => {
|
||||
v-else-if="startStatus === 'preparing'"
|
||||
disabled
|
||||
icon="pi pi-spin pi-spinner"
|
||||
label="START"
|
||||
:label="t('start.button.start')"
|
||||
aria-label="start"
|
||||
size="small"
|
||||
class="m-2.5"
|
||||
@ -186,7 +223,7 @@ const tryStart = () => {
|
||||
v-else
|
||||
:disabled="false"
|
||||
icon="pi pi-ban"
|
||||
label="STOP"
|
||||
:label="t('start.button.stop')"
|
||||
aria-label="stop"
|
||||
size="small"
|
||||
class="m-2.5"
|
||||
|
@ -17,6 +17,7 @@ const install = async () => {
|
||||
await invoke('install_package', {
|
||||
key: pkgKey(props.pkg),
|
||||
force: true,
|
||||
enable: false,
|
||||
});
|
||||
} catch (err) {
|
||||
if (props.pkg !== undefined) {
|
||||
|
@ -12,6 +12,9 @@ import { invoke } from '../../invoke';
|
||||
import { usePkgStore, usePrfStore } from '../../stores';
|
||||
import { Feature } from '../../types';
|
||||
import { hasFeature, pkgKey } from '../../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const pkgs = usePkgStore();
|
||||
const prf = usePrfStore();
|
||||
@ -60,14 +63,18 @@ load();
|
||||
<template>
|
||||
<OptionCategory title="Aime">
|
||||
<OptionRow
|
||||
title="Aime type"
|
||||
tooltip="Additional Aime plugins can be downloaded from the package store."
|
||||
:title="t('cfg.aime.type')"
|
||||
:tooltip="
|
||||
t('cfg.segatools.installTooltip', {
|
||||
thing: t('cfg.aime.modules'),
|
||||
})
|
||||
"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.aime"
|
||||
:options="[
|
||||
{ title: 'hardware', value: 'Disabled' },
|
||||
{ title: 'segatools built-in emulation', value: 'BuiltIn' },
|
||||
{ title: t('cfg.hardware'), value: 'Disabled' },
|
||||
{ title: t('cfg.segatools.builtIn'), value: 'BuiltIn' },
|
||||
...pkgs.byFeature(Feature.Aime).map((p) => {
|
||||
return {
|
||||
title: pkgKey(p),
|
||||
@ -83,8 +90,8 @@ load();
|
||||
></Select>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Aime code"
|
||||
tooltip="Only applicable with the segatools built-in emulation or with compatible third-party packages"
|
||||
:title="t('cfg.aime.code')"
|
||||
:tooltip="t('cfg.aime.codeTooltip')"
|
||||
v-if="prf.current!.data.sgt.aime !== 'Disabled'"
|
||||
>
|
||||
<InputText
|
||||
@ -97,7 +104,7 @@ load();
|
||||
/>
|
||||
</OptionRow>
|
||||
<div v-if="prf.current!.data.sgt.aime?.hasOwnProperty('AMNet')">
|
||||
<OptionRow title="Server name">
|
||||
<OptionRow :title="t('cfg.aime.serverName')">
|
||||
<InputText
|
||||
class="shrink"
|
||||
size="small"
|
||||
@ -106,7 +113,7 @@ load();
|
||||
v-model="prf.current!.data.sgt.amnet.name"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow title="Server address">
|
||||
<OptionRow :title="t('cfg.network.address')">
|
||||
<InputText
|
||||
class="shrink"
|
||||
size="small"
|
||||
@ -116,22 +123,21 @@ load();
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Use AiMeDB for physical cards"
|
||||
tooltip="Whether physical cards should use AiMeDB to retrieve access codes. If the game is using a hosted network, enable this option to load the same account data/profile as you would get on a physical cab."
|
||||
:title="t('cfg.aime.aimedb')"
|
||||
:tooltip="t('cfg.aime.aimedbTooltip')"
|
||||
>
|
||||
<ToggleSwitch v-model="prf.current!.data.sgt.amnet.physical" />
|
||||
</OptionRow>
|
||||
</div>
|
||||
<OptionRow
|
||||
title="Aime serial port"
|
||||
tooltip="Ports can be checked in Devices and Printers or at googlechromelabs.github.io/serial-terminal
|
||||
For AIC Pico, the AIME port should be selected."
|
||||
:title="t('cfg.aime.serialPort')"
|
||||
:tooltip="t('cfg.aime.serialPortTooltip')"
|
||||
v-if="prf.current!.data.sgt.aime === 'Disabled'"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.aime_port"
|
||||
:options="[
|
||||
{ title: 'default', value: null },
|
||||
{ title: t('default'), value: null },
|
||||
...Object.entries(coms ?? {}).map(([title, value]) => {
|
||||
return {
|
||||
title,
|
||||
@ -139,7 +145,7 @@ load();
|
||||
};
|
||||
}),
|
||||
]"
|
||||
placeholder="default"
|
||||
:placeholder="t('default')"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
></Select>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { Ref, computed, ref } from 'vue';
|
||||
import { Ref, computed, onMounted, ref } from 'vue';
|
||||
import InputNumber from 'primevue/inputnumber';
|
||||
import Select from 'primevue/select';
|
||||
import SelectButton from 'primevue/selectbutton';
|
||||
@ -8,11 +8,14 @@ import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { invoke } from '../../invoke';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const capabilities: Ref<string[]> = ref([]);
|
||||
const displayList: Ref<{ title: string; value: string }[]> = ref([
|
||||
{
|
||||
title: 'Primary',
|
||||
title: t('cfg.display.primary'),
|
||||
value: 'default',
|
||||
},
|
||||
]);
|
||||
@ -25,7 +28,7 @@ const extraDisplayOptionsDisabled = computed(() => {
|
||||
const loadDisplays = () => {
|
||||
const newList = [
|
||||
{
|
||||
title: 'Primary',
|
||||
title: t('cfg.display.primary'),
|
||||
value: 'default',
|
||||
},
|
||||
];
|
||||
@ -62,19 +65,23 @@ const loadDisplays = () => {
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
loadDisplays();
|
||||
onMounted(() => {
|
||||
loadDisplays();
|
||||
});
|
||||
|
||||
const game = prf.current!.meta.game;
|
||||
const isVertical = game === 'ongeki';
|
||||
const adjustableRez = game === 'ongeki';
|
||||
const canSkipPrimarySwitch = game === 'ongeki';
|
||||
const game = computed(() => prf.current!.meta.game);
|
||||
const isVertical = computed(() => prf.current!.meta.game === 'ongeki');
|
||||
const adjustableRez = computed(() => prf.current!.meta.game === 'ongeki');
|
||||
const canSkipPrimarySwitch = computed(
|
||||
() => prf.current!.meta.game === 'ongeki'
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="Display">
|
||||
<OptionCategory :title="t('cfg.display.title')">
|
||||
<OptionRow
|
||||
v-if="capabilities.includes('display')"
|
||||
title="Target display"
|
||||
:title="t('cfg.display.target')"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.display.target"
|
||||
@ -87,7 +94,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
class="number-input"
|
||||
title="Game resolution"
|
||||
:title="t('cfg.display.resolution')"
|
||||
v-if="adjustableRez"
|
||||
>
|
||||
<InputNumber
|
||||
@ -108,13 +115,13 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
v-model="prf.current!.data.display.rez[1]"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow title="Display mode">
|
||||
<OptionRow :title="t('cfg.display.mode')">
|
||||
<SelectButton
|
||||
v-model="prf.current!.data.display.mode"
|
||||
:options="[
|
||||
{ title: 'Window', value: 'Window' },
|
||||
{ title: 'Borderless window', value: 'Borderless' },
|
||||
{ title: 'Fullscreen', value: 'Fullscreen' },
|
||||
{ title: t('cfg.display.window'), value: 'Window' },
|
||||
{ title: t('cfg.display.borderless'), value: 'Borderless' },
|
||||
{ title: t('cfg.display.fullscreen'), value: 'Fullscreen' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
@ -122,7 +129,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Display rotation"
|
||||
:title="t('cfg.display.rotation')"
|
||||
v-if="capabilities.includes('display')"
|
||||
>
|
||||
<SelectButton
|
||||
@ -130,12 +137,18 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
:options="
|
||||
isVertical
|
||||
? [
|
||||
{ title: 'Portrait', value: 90 },
|
||||
{ title: 'Portrait (flipped)', value: 270 },
|
||||
{ title: t('cfg.display.portrait'), value: 90 },
|
||||
{
|
||||
title: `${t('cfg.display.portrait')} (${t('cfg.display.flipped')})`,
|
||||
value: 270,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{ title: 'Landscape', value: 0 },
|
||||
{ title: 'Landscape (flipped)', value: 180 },
|
||||
{ title: t('cfg.display.landscape'), value: 0 },
|
||||
{
|
||||
title: `${t('cfg.display.landscape')} (${t('cfg.display.flipped')})`,
|
||||
value: 180,
|
||||
},
|
||||
]
|
||||
"
|
||||
:allow-empty="true"
|
||||
@ -147,7 +160,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
<OptionRow
|
||||
v-if="capabilities.includes('display')"
|
||||
class="number-input"
|
||||
title="Refresh Rate"
|
||||
:title="t('cfg.display.refreshRate')"
|
||||
>
|
||||
<InputNumber
|
||||
v-if="game === 'ongeki'"
|
||||
@ -169,13 +182,12 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
:disabled="extraDisplayOptionsDisabled"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Borderless fullscreen"
|
||||
:title="t('cfg.display.borderlessFullscreen')"
|
||||
v-if="capabilities.includes('display')"
|
||||
tooltip="Match display resolution with the game."
|
||||
:tooltip="t('cfg.display.borderlessFullscreenTooltip')"
|
||||
>
|
||||
<ToggleSwitch
|
||||
:disabled="
|
||||
@ -186,28 +198,31 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Skip switching primary display"
|
||||
:title="t('cfg.display.dontSwitchPrimary')"
|
||||
v-if="
|
||||
capabilities.includes('display') &&
|
||||
prf.current?.data.display.target !== 'default' &&
|
||||
(prf.current!.data.display.dont_switch_primary ||
|
||||
displayList.length > 2) &&
|
||||
canSkipPrimarySwitch
|
||||
!capabilities.includes('display') ||
|
||||
(prf.current?.data.display.target !== 'default' &&
|
||||
(prf.current!.data.display.dont_switch_primary ||
|
||||
displayList.length > 2) &&
|
||||
canSkipPrimarySwitch)
|
||||
"
|
||||
dangerous-tooltip="Only enable this option if switching the primary display causes issues. The monitors must have a matching refresh rate."
|
||||
:dangerous-tooltip="t('cfg.display.dontSwitchPrimaryTooltip')"
|
||||
>
|
||||
<ToggleSwitch
|
||||
:disabled="extraDisplayOptionsDisabled"
|
||||
:disabled="
|
||||
extraDisplayOptionsDisabled &&
|
||||
capabilities.includes('display')
|
||||
"
|
||||
v-model="prf.current!.data.display.dont_switch_primary"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Display index"
|
||||
:title="t('cfg.display.index')"
|
||||
class="number-input"
|
||||
v-if="
|
||||
capabilities.includes('display') &&
|
||||
prf.current?.data.display.target !== 'default' &&
|
||||
prf.current!.data.display.dont_switch_primary
|
||||
!capabilities.includes('display') ||
|
||||
(prf.current?.data.display.target !== 'default' &&
|
||||
prf.current!.data.display.dont_switch_primary)
|
||||
"
|
||||
>
|
||||
<InputNumber
|
||||
@ -216,8 +231,12 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
||||
:min="game === 'chunithm' ? 0 : 1"
|
||||
:max="32"
|
||||
:use-grouping="false"
|
||||
placeholder="1"
|
||||
v-model="prf.current!.data.display.monitor_index_override"
|
||||
:disabled="extraDisplayOptionsDisabled"
|
||||
:disabled="
|
||||
extraDisplayOptionsDisabled &&
|
||||
capabilities.includes('display')
|
||||
"
|
||||
:allow-empty="true"
|
||||
/>
|
||||
</OptionRow>
|
||||
|
@ -5,27 +5,27 @@ import KeyboardKey from '../KeyboardKey.vue';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="Keyboard">
|
||||
<OptionRow
|
||||
title="Enable"
|
||||
tooltip="Only applicable if the IO module is set to segatools built-in (keyboard) or a compatible third-party module (like mu3io.NET)"
|
||||
>
|
||||
<OptionCategory :title="t('cfg.keyboard.title')">
|
||||
<OptionRow :title="t('enable')" :tooltip="t('cfg.keyboard.tooltip')">
|
||||
<ToggleSwitch v-model="prf.current!.data.keyboard!.data.enabled" />
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Lever mode"
|
||||
:title="t('cfg.keyboard.leverMode')"
|
||||
v-if="prf.current!.data.keyboard!.game === 'Ongeki'"
|
||||
>
|
||||
<SelectButton
|
||||
v-model="prf.current!.data.keyboard!.data.use_mouse"
|
||||
:options="[
|
||||
{ title: 'XInput', value: false },
|
||||
{ title: 'Mouse', value: true },
|
||||
{ title: t('cfg.keyboard.mouse'), value: true },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
@ -95,7 +95,7 @@ const prf = usePrfStore();
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="prf.current?.meta.game === 'chunithm'">
|
||||
<div class="absolute left-1/2 top-1/5">
|
||||
<div class="absolute left-9/17 top-1/12">
|
||||
<div
|
||||
class="flex flex-row flex-nowrap gap-2 self-center w-full"
|
||||
>
|
||||
@ -108,6 +108,7 @@ const prf = usePrfStore();
|
||||
button="ir"
|
||||
:index="idx - 1"
|
||||
:tooltip="`ir${idx}`"
|
||||
tall
|
||||
small
|
||||
color="rgba(0, 255, 0, 0.2)"
|
||||
/>
|
||||
|
@ -1,24 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import FileEditor from '../FileEditor.vue';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { invoke } from '../../invoke';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const extension = ref('');
|
||||
|
||||
invoke('list_platform_capabilities').then(async (v: unknown) => {
|
||||
if (Array.isArray(v)) {
|
||||
if (v.includes('preload-sh')) {
|
||||
extension.value = 'sh';
|
||||
} else if (v.includes('preload-bat')) {
|
||||
extension.value = 'bat';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const prf = usePrfStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="Misc">
|
||||
<OptionRow title="OpenSSL bug workaround for Intel ≥10th gen">
|
||||
<OptionCategory :title="t('cfg.misc.title')">
|
||||
<OptionRow
|
||||
:title="t('cfg.misc.intel')"
|
||||
:dangerous-tooltip="t('cfg.misc.intelTooltip')"
|
||||
>
|
||||
<ToggleSwitch v-model="prf.current!.data.sgt.intel" />
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="More segatools options"
|
||||
tooltip="Advanced options not covered by STARTLINER"
|
||||
:title="t('cfg.misc.other')"
|
||||
:tooltip="t('cfg.misc.otherTooltip')"
|
||||
>
|
||||
<!-- <Button icon="pi pi-refresh" size="small" /> -->
|
||||
<FileEditor filename="segatools-base.ini" />
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
:title="t('cfg.misc.prescript')"
|
||||
:tooltip="t('cfg.misc.prescriptTooltip')"
|
||||
>
|
||||
<FileEditor
|
||||
v-if="extension === 'bat'"
|
||||
filename="pre.bat"
|
||||
:defaultValue="`@echo off\n\nREM This script will launch before (and alongside) the game\n`"
|
||||
/>
|
||||
<FileEditor
|
||||
v-else-if="extension === 'sh'"
|
||||
filename="pre.sh"
|
||||
:defaultValue="`#!/bin/sh\n\n# This script will launch before (and alongside) the game\n`"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
:title="t('cfg.misc.postscript')"
|
||||
:tooltip="t('cfg.misc.postscriptTooltip')"
|
||||
>
|
||||
<FileEditor
|
||||
v-if="extension === 'bat'"
|
||||
filename="post.bat"
|
||||
:defaultValue="`@echo off\n\nREM This script will launch after the game has died\n`"
|
||||
/>
|
||||
<FileEditor
|
||||
v-else-if="extension === 'sh'"
|
||||
filename="post.sh"
|
||||
:defaultValue="`#!/bin/sh\n\n# This script will launch after the game has died\n`"
|
||||
/>
|
||||
</OptionRow>
|
||||
</OptionCategory>
|
||||
</template>
|
||||
|
@ -6,18 +6,21 @@ import FilePicker from '../FilePicker.vue';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { usePrfStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="Network">
|
||||
<OptionRow title="Network type">
|
||||
<OptionCategory :title="t('cfg.network.title')">
|
||||
<OptionRow :title="t('cfg.network.type')">
|
||||
<SelectButton
|
||||
v-model="prf.current!.data.network.network_type"
|
||||
:options="[
|
||||
{ title: 'Remote', value: 'Remote' },
|
||||
{ title: 'Local (ARTEMiS)', value: 'Artemis' },
|
||||
{ title: t('cfg.network.remote'), value: 'Remote' },
|
||||
{ title: t('cfg.network.localArtemis'), value: 'Artemis' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
@ -25,8 +28,8 @@ const prf = usePrfStore();
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
v-if="prf.current!.data.network.network_type == 'Artemis'"
|
||||
title="ARTEMiS path"
|
||||
v-if="prf.current!.data.network.network_type === 'Artemis'"
|
||||
:title="t('cfg.network.artemisPath')"
|
||||
>
|
||||
<FilePicker
|
||||
:directory="false"
|
||||
@ -47,7 +50,7 @@ const prf = usePrfStore();
|
||||
</OptionRow> -->
|
||||
<OptionRow
|
||||
v-if="prf.current!.data.network.network_type == 'Remote'"
|
||||
title="Server address"
|
||||
:title="t('cfg.network.address')"
|
||||
>
|
||||
<InputText
|
||||
class="shrink"
|
||||
@ -58,7 +61,7 @@ const prf = usePrfStore();
|
||||
/> </OptionRow
|
||||
><OptionRow
|
||||
v-if="prf.current!.data.network.network_type == 'Remote'"
|
||||
title="Keychip"
|
||||
:title="t('cfg.network.keychip')"
|
||||
>
|
||||
<InputText
|
||||
class="shrink"
|
||||
@ -67,7 +70,7 @@ const prf = usePrfStore();
|
||||
placeholder="A123-01234567890"
|
||||
v-model="prf.current!.data.network.keychip"
|
||||
/> </OptionRow
|
||||
><OptionRow title="Subnet">
|
||||
><OptionRow :title="t('cfg.network.subnet')">
|
||||
<InputText
|
||||
class="shrink"
|
||||
size="small"
|
||||
@ -76,7 +79,7 @@ const prf = usePrfStore();
|
||||
v-model="prf.current!.data.network.subnet"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow title="Address suffix">
|
||||
<OptionRow :title="t('cfg.network.addrSuffix')">
|
||||
<InputNumber
|
||||
class="shrink"
|
||||
size="small"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { Ref, computed, ref } from 'vue';
|
||||
import Select from 'primevue/select';
|
||||
import { useConfirm } from 'primevue/useconfirm';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
@ -11,11 +11,22 @@ import { invoke } from '../../invoke';
|
||||
import { usePkgStore, usePrfStore } from '../../stores';
|
||||
import { Feature } from '../../types';
|
||||
import { pkgKey } from '../../util';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const prf = usePrfStore();
|
||||
const pkgs = usePkgStore();
|
||||
const confirmDialog = useConfirm();
|
||||
|
||||
const capabilities: Ref<string[]> = ref([]);
|
||||
|
||||
invoke('list_platform_capabilities').then(async (v: unknown) => {
|
||||
if (Array.isArray(v)) {
|
||||
capabilities.value.push(...v);
|
||||
}
|
||||
});
|
||||
|
||||
const names = computed(() => {
|
||||
switch (prf.current?.meta.game) {
|
||||
case 'ongeki': {
|
||||
@ -32,8 +43,6 @@ const names = computed(() => {
|
||||
io: 'chuniio',
|
||||
};
|
||||
}
|
||||
case undefined:
|
||||
throw new Error('Option tab without a profile');
|
||||
}
|
||||
});
|
||||
|
||||
@ -54,16 +63,16 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="General">
|
||||
<OptionCategory :title="t('cfg.segatools.general')">
|
||||
<OptionRow
|
||||
:title="names.exe"
|
||||
tooltip="STARTLINER expects unpacked executables put into otherwise clean data."
|
||||
:title="names?.exe"
|
||||
:tooltip="t('cfg.segatools.targetTooltip')"
|
||||
>
|
||||
<FilePicker
|
||||
:directory="false"
|
||||
:promptname="names.exe"
|
||||
:promptname="names?.exe"
|
||||
extension="exe"
|
||||
:value="prf.current!.data.sgt.target"
|
||||
:value="prf.current?.data.sgt.target"
|
||||
:callback="
|
||||
(value: string) => (
|
||||
(prf.current!.data.sgt.target = value),
|
||||
@ -77,7 +86,7 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
<FilePicker
|
||||
:directory="true"
|
||||
placeholder="amfs"
|
||||
:value="prf.current!.data.sgt.amfs"
|
||||
:value="prf.current?.data.sgt.amfs"
|
||||
:callback="
|
||||
(value: string) => (prf.current!.data.sgt.amfs = value)
|
||||
"
|
||||
@ -103,8 +112,12 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
></FilePicker>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
:title="names.hook"
|
||||
tooltip="Hooks can be downloaded from the package store."
|
||||
:title="names?.hook"
|
||||
:tooltip="
|
||||
t('cfg.segatools.installTooltip', {
|
||||
thing: t('cfg.segatools.hooks'),
|
||||
})
|
||||
"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.hook"
|
||||
@ -125,15 +138,18 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
></Select>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
:title="names.io"
|
||||
tooltip="IO plugins can be downloaded from the package store."
|
||||
:title="names?.io"
|
||||
:tooltip="`${t('cfg.segatools.ioModulesDesc')}
|
||||
${t('cfg.segatools.installTooltip', {
|
||||
thing: t('cfg.segatools.ioModules'),
|
||||
})}`"
|
||||
>
|
||||
<Select
|
||||
v-model="prf.current!.data.sgt.io2"
|
||||
:options="[
|
||||
{ title: 'native io4', value: 'hardware' },
|
||||
{ title: t('cfg.segatools.io4'), value: 'hardware' },
|
||||
{
|
||||
title: 'segatools built-in (keyboard)',
|
||||
title: t('cfg.segatools.ioBuiltIn'),
|
||||
value: 'segatools_built_in',
|
||||
},
|
||||
...pkgs
|
||||
@ -153,5 +169,29 @@ const checkSegatoolsIni = async (target: string) => {
|
||||
option-value="value"
|
||||
></Select>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
v-if="capabilities.includes('wine')"
|
||||
:title="t('cfg.wine.runtime')"
|
||||
>
|
||||
<FilePicker
|
||||
:directory="false"
|
||||
:value="prf.current!.data.wine.runtime"
|
||||
:callback="
|
||||
(value: string) => (prf.current!.data.wine.runtime = value)
|
||||
"
|
||||
></FilePicker>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
v-if="capabilities.includes('wine')"
|
||||
:title="t('cfg.wine.prefix')"
|
||||
>
|
||||
<FilePicker
|
||||
:directory="true"
|
||||
:value="prf.current!.data.wine.prefix"
|
||||
:callback="
|
||||
(value: string) => (prf.current!.data.wine.prefix = value)
|
||||
"
|
||||
></FilePicker>
|
||||
</OptionRow>
|
||||
</OptionCategory>
|
||||
</template>
|
||||
|
@ -1,92 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import SelectButton from 'primevue/selectbutton';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import OptionCategory from '../OptionCategory.vue';
|
||||
import OptionRow from '../OptionRow.vue';
|
||||
import { useClientStore } from '../../stores';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const client = useClientStore();
|
||||
|
||||
const offlineModel = computed({
|
||||
get() {
|
||||
return client.offlineMode;
|
||||
},
|
||||
async set(value: boolean) {
|
||||
await client.setOfflineMode(value);
|
||||
},
|
||||
});
|
||||
|
||||
const updatesModel = computed({
|
||||
get() {
|
||||
return client.enableAutoupdates;
|
||||
},
|
||||
async set(value: boolean) {
|
||||
await client.setAutoupdates(value);
|
||||
},
|
||||
});
|
||||
|
||||
const verboseModel = computed({
|
||||
get() {
|
||||
return client.verbose;
|
||||
},
|
||||
async set(value: boolean) {
|
||||
await client.setVerbose(value);
|
||||
},
|
||||
});
|
||||
|
||||
const themeModel = computed({
|
||||
get() {
|
||||
return client.theme;
|
||||
},
|
||||
async set(value: 'light' | 'dark' | 'system') {
|
||||
await client.setTheme(value);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OptionCategory title="STARTLINER">
|
||||
<OptionRow title="UI scaling">
|
||||
<SelectButton
|
||||
v-model="client.scaleModel"
|
||||
:options="[
|
||||
{ title: 'S', value: 's' },
|
||||
{ title: 'M', value: 'm' },
|
||||
{ title: 'L', value: 'l' },
|
||||
{ title: 'XL', value: 'xl' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
<OptionRow
|
||||
:title="t('cfg.startliner.offlineMode')"
|
||||
:tooltip="`${t('cfg.startliner.offlineModeTooltip')} ${t('cfg.afterRestart')}`"
|
||||
>
|
||||
<ToggleSwitch
|
||||
:model-value="client.offlineMode"
|
||||
@update:model-value="
|
||||
async (v) => await client.setOfflineMode(v)
|
||||
"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Offline mode"
|
||||
tooltip="Disables the package store. Applies after a restart."
|
||||
>
|
||||
<ToggleSwitch v-model="offlineModel" />
|
||||
</OptionRow>
|
||||
<OptionRow title="Enable automatic updates">
|
||||
<ToggleSwitch v-model="updatesModel" />
|
||||
<OptionRow :title="t('cfg.startliner.autoUpdate')">
|
||||
<ToggleSwitch
|
||||
:model-value="client.enableAutoupdates"
|
||||
@update:model-value="
|
||||
async (v) => await client.setAutoupdates(v)
|
||||
"
|
||||
></ToggleSwitch>
|
||||
</OptionRow>
|
||||
<OptionRow
|
||||
title="Enable detailed logs"
|
||||
tooltip="Applies after a restart."
|
||||
:title="t('cfg.startliner.verbose')"
|
||||
:tooltip="t('cfg.afterRestart')"
|
||||
>
|
||||
<ToggleSwitch v-model="verboseModel" />
|
||||
</OptionRow>
|
||||
<OptionRow title="Theme">
|
||||
<SelectButton
|
||||
v-model="themeModel"
|
||||
:options="[
|
||||
{ title: 'System', value: 'system' },
|
||||
{ title: 'Light', value: 'light' },
|
||||
{ title: 'Dark', value: 'dark' },
|
||||
]"
|
||||
:allow-empty="false"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
<ToggleSwitch
|
||||
:model-value="client.verbose"
|
||||
@update:model-value="async (v) => await client.setVerbose(v)"
|
||||
/>
|
||||
</OptionRow>
|
||||
</OptionCategory>
|
||||
|
27
src/i18n.ts
Normal file
27
src/i18n.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import en from './i18n/en';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
export type Locale = 'en' | 'ja' | 'pl' | 'zh-Hans' | 'es' | 'ko';
|
||||
|
||||
const loadLocaleMessages = async (locale: Locale) => {
|
||||
return (await import(`./i18n/${locale}.ts`)).default;
|
||||
};
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
fallbackLocale: 'en',
|
||||
warnHtmlInMessage: false,
|
||||
warnHtmlMessage: false,
|
||||
messages: { en, ja: {}, pl: {}, 'zh-Hans': {}, es: {}, ko: {} },
|
||||
});
|
||||
|
||||
const setLocale = async (locale: Locale) => {
|
||||
if (locale !== 'en') {
|
||||
const messages = await loadLocaleMessages(locale);
|
||||
i18n.global.setLocaleMessage(locale, messages);
|
||||
}
|
||||
i18n.global.locale.value = locale;
|
||||
};
|
||||
|
||||
export { i18n, setLocale };
|
256
src/i18n/en.ts
Normal file
256
src/i18n/en.ts
Normal file
@ -0,0 +1,256 @@
|
||||
export default {
|
||||
ok: 'OK',
|
||||
cancel: 'Cancel',
|
||||
enable: 'Enable',
|
||||
disable: 'Disable',
|
||||
default: 'Default',
|
||||
search: 'Search',
|
||||
next: 'Next',
|
||||
skip: 'Skip',
|
||||
close: 'Close',
|
||||
by: 'by {namespace}',
|
||||
updateAll: 'UPDATE ALL',
|
||||
start: {
|
||||
failed: 'Start check failed',
|
||||
accept: 'Run anyway',
|
||||
error: {
|
||||
package: 'Package missing',
|
||||
dependency: 'Dependency missing',
|
||||
tool: 'Tool missing',
|
||||
unknown: 'Unknown error',
|
||||
},
|
||||
tooltip: {
|
||||
game: 'The game path must be specified',
|
||||
amfs: 'The amfs path must be specified',
|
||||
segatools: 'A segatools hook package is necessary',
|
||||
},
|
||||
button: {
|
||||
start: 'START',
|
||||
stop: 'STOP',
|
||||
unchecked: 'Skip checks and start',
|
||||
shortcut: 'Create desktop shortcut',
|
||||
help: 'Help',
|
||||
refresh: 'Reapply mods and start',
|
||||
cache: 'Clear mod cache',
|
||||
},
|
||||
},
|
||||
game: {
|
||||
ongeki: 'O.N.G.E.K.I.',
|
||||
chunithm: 'CHUNITHM',
|
||||
},
|
||||
profile: {
|
||||
welcome: 'Welcome to STARTLINER! Start by creating a profile.',
|
||||
create: '{game} profile',
|
||||
delete: 'Delete profile',
|
||||
reallyDelete: 'Are you sure you want to delete {profile}?',
|
||||
template: 'STARTLINER template',
|
||||
importTemplate: 'Import template',
|
||||
exportTemplate: 'Export profile',
|
||||
export: 'Export',
|
||||
standardExport: 'Template',
|
||||
diagnostic: 'Diagnostic',
|
||||
},
|
||||
creator: {
|
||||
header: 'Package creator',
|
||||
basic: 'Basic information',
|
||||
name: 'Name',
|
||||
description: 'Description',
|
||||
website: 'Website',
|
||||
type: 'Package type',
|
||||
rainy: 'Standard',
|
||||
segatools: 'Segatools',
|
||||
native: 'Native',
|
||||
games: 'Games',
|
||||
packageFormat: 'Package format spec',
|
||||
},
|
||||
store: {
|
||||
installRecommended: 'Install recommended packages',
|
||||
installed: 'Show installed',
|
||||
deprecated: 'Show deprecated',
|
||||
nsfw: 'Show NSFW',
|
||||
incompatible: 'This package is currently incompatible with STARTLINER.',
|
||||
|
||||
includeCategories: 'Include categories',
|
||||
excludeCategories: 'Exclude categories',
|
||||
},
|
||||
pkglist: {
|
||||
missing: 'Missing',
|
||||
local: 'Local packages',
|
||||
namespace: 'By namespace',
|
||||
type: 'By type',
|
||||
category: 'By category',
|
||||
standard: 'Standard mods',
|
||||
native: 'Native mods',
|
||||
segatools: 'segatools',
|
||||
unsupported: 'Unsupported',
|
||||
exclusions: 'Exclusions:',
|
||||
},
|
||||
patch: {
|
||||
loading: 'Loading...',
|
||||
noneFound:
|
||||
"No compatible patches found. Make sure you're using unpacked and unpatched files.",
|
||||
forceLoad: 'Force load',
|
||||
// Example patch name override
|
||||
// 'standard-no-encryption': 'No encryption',
|
||||
// 'standard-no-encryption-tooltip': 'Will also disable TLS',
|
||||
// It is also possible to add a tooltip where there normally is none
|
||||
// 'standard-maximum-tracks-tooltip': 'The number of tracks per credit',
|
||||
// For more info check https://gitea.tendokyu.moe/akanyan/STARTLINER/wiki/Translation-%26-Localization
|
||||
},
|
||||
cfg: {
|
||||
afterRestart: 'Applied after a restart',
|
||||
hardware: 'Hardware',
|
||||
segatools: {
|
||||
general: 'General',
|
||||
builtIn: 'Segatools built-in emulation',
|
||||
targetTooltip:
|
||||
'STARTLINER expects unpacked executables put into otherwise clean data.',
|
||||
hooks: 'Hooks',
|
||||
ioModules: 'IO modules',
|
||||
ioModulesDesc: 'This should match your desired input method.',
|
||||
ioBuiltIn: 'segatools built-in (keyboard)',
|
||||
io4: 'Native IO4',
|
||||
installTooltip: '{thing} can be downloaded from the package store.',
|
||||
},
|
||||
display: {
|
||||
title: 'Display',
|
||||
resolution: 'Game resolution',
|
||||
primary: 'Primary',
|
||||
target: 'Target display',
|
||||
mode: 'Mode',
|
||||
rotation: 'Rotation',
|
||||
refreshRate: 'Refresh rate',
|
||||
borderlessFullscreen: 'Borderless fullscreen',
|
||||
borderlessFullscreenTooltip:
|
||||
'Match display resolution with the game.',
|
||||
dontSwitchPrimary: 'Skip switching primary display',
|
||||
dontSwitchPrimaryTooltip:
|
||||
'Only enable this option if switching the primary display causes issues. The monitors must have a matching refresh rate.',
|
||||
index: 'Display index',
|
||||
portrait: 'Portrait',
|
||||
landscape: 'Landscape',
|
||||
flipped: 'flipped',
|
||||
window: 'Window',
|
||||
borderless: 'Borderless window',
|
||||
fullscreen: 'Fullscreen',
|
||||
},
|
||||
network: {
|
||||
title: 'Network',
|
||||
type: 'Network type',
|
||||
remote: 'Remote',
|
||||
localArtemis: 'Local (ARTEMiS)',
|
||||
artemisPath: 'ARTEMiS path',
|
||||
address: 'Server address',
|
||||
keychip: 'Keychip',
|
||||
subnet: 'Subnet',
|
||||
addrSuffix: 'Address suffix',
|
||||
},
|
||||
aime: {
|
||||
type: 'Aime type',
|
||||
modules: 'Aime modules',
|
||||
code: 'Aime code',
|
||||
codeTooltip:
|
||||
'Only applicable with the segatools built-in emulation or with compatible third-party packages',
|
||||
aimedb: 'Use AiMeDB for physical cards',
|
||||
aimedbTooltip:
|
||||
'Whether physical cards should use AiMeDB to retrieve access codes. If the game is using a hosted network, enable this option to load the same account data/profile as you would get on a physical cab.',
|
||||
serialPort: 'Aime serial port',
|
||||
serialPortTooltip: `Ports can be checked in Devices and Printers or at googlechromelabs.github.io/serial-terminal
|
||||
For AIC Pico, the AIME port should be selected.`,
|
||||
serverName: 'Server name',
|
||||
},
|
||||
misc: {
|
||||
title: 'Miscellaneous',
|
||||
intel: 'OpenSSL bug workaround for Intel ≥10th gen',
|
||||
intelTooltip: 'It is recommended to patch amdaemon instead.',
|
||||
other: 'Other segatools options',
|
||||
otherTooltip:
|
||||
'Advanced or situational options not covered by STARTLINER',
|
||||
prescript: 'Launch script',
|
||||
prescriptTooltip: 'Optional script that runs before the game.',
|
||||
postscript: 'End script',
|
||||
postscriptTooltip:
|
||||
'Optional script that runs after the game has ended.',
|
||||
},
|
||||
extensions: {
|
||||
title: 'Extensions',
|
||||
bepInExConsole: 'BepInEx console',
|
||||
audioMode: 'Audio mode',
|
||||
audioTooltip:
|
||||
'Exclusive 2-channel mode requires 7EVENDAYSHOLIDAYS-ExclusiveAudio',
|
||||
audioShared: 'Shared',
|
||||
audio6Ch: 'Exclusive 6-channel',
|
||||
audio2Ch: 'Exclusive 2-channel',
|
||||
sampleRate: 'Sample rate',
|
||||
blacklist: 'Song ID blacklist',
|
||||
blacklistTooltip:
|
||||
'Scores on charts within this ID range will not be saved nor uploaded',
|
||||
bonusTracks: 'Unlock bonus tracks',
|
||||
bonusTracksTooltip:
|
||||
'Disabling this option can help declutter the song list',
|
||||
saekawa: 'Saekawa configuration file',
|
||||
inohara: 'Inohara configuration file',
|
||||
},
|
||||
keyboard: {
|
||||
title: 'Keyboard',
|
||||
tooltip:
|
||||
'Only applicable if the IO module is set to segatools built-in (keyboard) or a compatible third-party module (like mu3io.NET)',
|
||||
leverMode: 'Lever mode',
|
||||
mouse: 'Mouse',
|
||||
irTooltip:
|
||||
'When playing on an actual keyboard, only bind ir1; leave the rest unbound',
|
||||
},
|
||||
wine: {
|
||||
prefix: 'Wine prefix',
|
||||
runtime: 'Wine runtime',
|
||||
},
|
||||
startliner: {
|
||||
offlineMode: 'Offline mode',
|
||||
offlineModeTooltip: 'Disables the package store.',
|
||||
autoUpdate: 'Automatic updates',
|
||||
verbose: 'Detailed logs',
|
||||
},
|
||||
},
|
||||
onboarding: {
|
||||
or: 'or',
|
||||
backButton: 'a button on the back of the controller',
|
||||
standard: `
|
||||
You might get stuck on the following screen:
|
||||
|
||||
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||
|
||||
In which case, you should go to the test menu, and in game settings {black}ゲーム設定{end} switch from "follow the standard machine" {black}基準機に従う{end} to "standard machine" {black}基準機{end}.
|
||||
|
||||
The test menu can be accessed with %TESTMENU%.
|
||||
`,
|
||||
|
||||
'ongeki-system-processing': `
|
||||
You might get stuck on this screen for several minutes. _This is normal_. The game just takes a long time to load data.
|
||||
|
||||
If you install <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, subsequent launches will be much faster.
|
||||
`,
|
||||
|
||||
'ongeki-lever': `
|
||||
You also have to calibrate the lever, or you may get the error 3301.
|
||||
|
||||
Go to lever settings ({black}レバー設定{end}), move the lever to both edges, then press "end" ({black}終了{end}) and "save" ({black}保存する{end}).
|
||||
`,
|
||||
|
||||
'chunithm-server': `
|
||||
If you're stuck on this screen, restart the game.
|
||||
|
||||
If the problem persists, {link}check your network configuration{endlink}
|
||||
`,
|
||||
|
||||
finale: `
|
||||
You can access this page any time by right-clicking the START button.
|
||||
|
||||
Additional resources:
|
||||
|
||||
- {segaguide}SEGAguide{endlink}
|
||||
- {twotorial}two-torial{endlink}
|
||||
|
||||
## Have fun
|
||||
`,
|
||||
},
|
||||
};
|
283
src/i18n/es.ts
Normal file
283
src/i18n/es.ts
Normal file
@ -0,0 +1,283 @@
|
||||
export default {
|
||||
ok: 'Aceptar',
|
||||
cancel: 'Cancelar',
|
||||
enable: 'Activar',
|
||||
disable: 'Desactivar',
|
||||
default: 'Predeterminado',
|
||||
search: 'Buscar',
|
||||
next: 'Siguiente',
|
||||
skip: 'Omitir',
|
||||
close: 'Cerrar',
|
||||
by: 'por {namespace}',
|
||||
updateAll: 'ACTUALIZAR TODO',
|
||||
start: {
|
||||
failed: 'Verificación inicial fallida',
|
||||
accept: 'Ejecutar de todos modos',
|
||||
error: {
|
||||
package: 'Paquete faltante',
|
||||
dependency: 'Dependencia faltante',
|
||||
tool: 'Herramienta faltante',
|
||||
unknown: 'Error desconocido',
|
||||
},
|
||||
tooltip: {
|
||||
game: 'La ruta del juego debe especificarse',
|
||||
amfs: 'La ruta de amfs debe especificarse',
|
||||
segatools: 'Es necesario un paquete de segatools',
|
||||
},
|
||||
button: {
|
||||
start: 'INICIAR',
|
||||
stop: 'DETENER',
|
||||
unchecked: 'Omitir verificaciones e iniciar',
|
||||
shortcut: 'Crear acceso directo en escritorio',
|
||||
help: 'Ayuda',
|
||||
refresh: 'Reaplicar mods e iniciar',
|
||||
cache: 'Limpiar caché de mods',
|
||||
},
|
||||
},
|
||||
game: {
|
||||
ongeki: 'O.N.G.E.K.I.',
|
||||
chunithm: 'CHUNITHM',
|
||||
},
|
||||
profile: {
|
||||
welcome: '¡Bienvenido a STARTLINER! Comienza creando un perfil.',
|
||||
create: 'Perfil de {game}',
|
||||
delete: 'Eliminar perfil',
|
||||
reallyDelete: '¿Estás seguro de que quieres eliminar {profile}?',
|
||||
template: 'Plantilla de STARTLINER',
|
||||
importTemplate: 'Importar plantilla',
|
||||
exportTemplate: 'Exportar perfil',
|
||||
export: 'Exportar',
|
||||
standardExport: 'Plantilla',
|
||||
diagnostic: 'Diagnósticar',
|
||||
},
|
||||
creator: {
|
||||
header: 'Creador de paquetes',
|
||||
basic: 'Información básica',
|
||||
name: 'Nombre',
|
||||
description: 'Descripción',
|
||||
website: 'Sitio web',
|
||||
type: 'Tipo de paquete',
|
||||
rainy: 'Estándar',
|
||||
segatools: 'Segatools',
|
||||
native: 'Nativo',
|
||||
games: 'Juegos',
|
||||
packageFormat: 'Especificación de formato de paquete',
|
||||
},
|
||||
store: {
|
||||
installRecommended: 'Instalar paquetes recomendados',
|
||||
installed: 'Mostrar instalados',
|
||||
deprecated: 'Mostrar obsoletos',
|
||||
nsfw: 'Mostrar NSFW',
|
||||
incompatible: 'Este paquete actualmente es incompatible con STARTLINER.',
|
||||
|
||||
includeCategories: 'Incluir categorías',
|
||||
excludeCategories: 'Excluir categorías',
|
||||
},
|
||||
pkglist: {
|
||||
missing: 'Faltante',
|
||||
local: 'Paquetes locales',
|
||||
namespace: 'Por espacio de nombres',
|
||||
type: 'Por tipo',
|
||||
category: 'Por categoría',
|
||||
standard: 'Mods estándar',
|
||||
native: 'Mods nativos',
|
||||
segatools: 'segatools',
|
||||
unsupported: 'No compatible',
|
||||
exclusions: 'Exclusiones:',
|
||||
},
|
||||
patch: {
|
||||
loading: 'Cargando...',
|
||||
noneFound:
|
||||
'No se encontraron parches compatibles. Asegúrate de estar usando archivos desempaquetados y sin parches.',
|
||||
forceLoad: 'Forzar carga',
|
||||
'standard-shared-audio': 'Forzar modo de audio compartido, la frecuencia de muestreo del audio del sistema deber ser de 48000Hz',
|
||||
'standard-shared-audio-tooltip': 'Mejora la compatibilidad, pero puede incrementar la latencia',
|
||||
'standard-2ch': 'Forzar salida de audio de 2 canales',
|
||||
'standard-2ch-tooltip': 'Puede causar carga excesiva de bajos',
|
||||
'standard-song-timer': 'Desactivar temporizador de selección de pista',
|
||||
'standard-map-timer': 'Temporizador de seleccion de mapa',
|
||||
'standard-map-timer-tooltip': 'Si se fija en negativo, el temporizador será de 968 + valor (ej: 968 + -1 = 967)',
|
||||
'standard-ticket-timer': 'Temporizador de seleccion de tickets',
|
||||
'standard-ticket-timer-tooltip': 'Si se fija en negativo, el temporizador será de 968 + valor (ej: 968 + -1 = 967)',
|
||||
'standard-course-timer': 'Temporizador de seleccion de curso',
|
||||
'standard-course-timer-tooltip': 'Si se fija en negativo, el temporizador será de 968 + valor (ej: 968 + -1 = 967)',
|
||||
'standard-unlimited-tracks': 'Pistas maximas ilimitadas',
|
||||
'standard-unlimited-tracks-tooltip': 'Debe fijarse para reproducir más de 7 pistas por crédito',
|
||||
'standard-maximum-tracks': 'Pistas maximas',
|
||||
'standard-no-encryption': 'No cifrar',
|
||||
'standard-no-encryption-tooltip': 'Támbien desactivará TLS',
|
||||
'standard-no-tls': 'Sin TLS',
|
||||
'standard-no-tls-tooltip': 'Solucion alternativa para el servidor de títulos',
|
||||
'standard-head-to-head': 'Parche para juego cara a cara',
|
||||
'standard-head-to-head-tooltip': 'Soluciona la sincronización infinita al intentar conectarse al juego cara a cara',
|
||||
'standard-bypass-1080p': 'Omitir verificación de monitor 1080p',
|
||||
'standard-bypass-120hz': 'Omitir verificación de monitor de 120hz',
|
||||
'standard-force-free-play-text': 'Forzar texto de FREE PLAY',
|
||||
'standard-force-free-play-text-tooltip': 'Reemplaza el contador de creditos con FREE PLAY',
|
||||
'standard-custom-free-play-length': 'Longitud personalizada de texto FREE PLAY',
|
||||
'standard-custom-free-play-length-tooltip': 'Cambia la longitud del texto mostrado cuando se activa Forzar texto FREE PLAY',
|
||||
'standard-custom-free-play-text': 'Texto FREE PLAY personalizado',
|
||||
'standard-custom-free-play-text-tooltip': 'Reemplazar el texto FREE PLAY al utilizar Creditos Infinitos',
|
||||
'standard-localhost': 'Permitir 127.0.0.1/localhost como servidor de red',
|
||||
'standard-credit-freeze': 'Congelar créditos',
|
||||
'standard-credit-freeze-tooltip': 'Evita que se usen créditos. Debe haber al menos un crédito disponible para iniciar el juego o comprar boletos premium.',
|
||||
'standard-openssl-fix': 'Solucion a crasheo SHA de OpenSSL',
|
||||
'standard-openssl-fix-tooltip': 'Soluciona crasheos en CPUs Intel de 10ma generacion a mas recientes',
|
||||
},
|
||||
cfg: {
|
||||
afterRestart: 'Aplicado después de reiniciar',
|
||||
hardware: 'Hardware',
|
||||
segatools: {
|
||||
general: 'General',
|
||||
builtIn: 'Emulación integrada de Segatools',
|
||||
targetTooltip:
|
||||
'STARTLINER espera ejecutables desempaquetados colocados en datos de lo contrario limpios.',
|
||||
hooks: 'Hooks',
|
||||
ioModules: 'Módulos IO',
|
||||
ioModulesDesc: 'Esto debe coincidir con tu método de entrada deseado.',
|
||||
ioBuiltIn: 'segatools integrado (teclado)',
|
||||
io4: 'IO4 nativo',
|
||||
installTooltip: '{thing} puede descargarse desde la tienda de paquetes.',
|
||||
},
|
||||
display: {
|
||||
title: 'Pantalla',
|
||||
resolution: 'Resolución del juego',
|
||||
primary: 'Principal',
|
||||
target: 'Pantalla objetivo',
|
||||
mode: 'Modo',
|
||||
rotation: 'Rotación',
|
||||
refreshRate: 'Tasa de refresco',
|
||||
borderlessFullscreen: 'Pantalla completa sin bordes',
|
||||
borderlessFullscreenTooltip:
|
||||
'Coincidir la resolución de la pantalla con el juego.',
|
||||
dontSwitchPrimary: 'Omitir cambio de pantalla principal',
|
||||
dontSwitchPrimaryTooltip:
|
||||
'Solo habilitar esta opción si hay problemas al cambiar a la principal. Los monitores deben tener una tasa de refresco compartida.',
|
||||
index: 'Índice de pantalla',
|
||||
portrait: 'Vertical',
|
||||
landscape: 'Horizontal',
|
||||
flipped: 'invertido',
|
||||
window: 'Ventana',
|
||||
borderless: 'Ventana sin bordes',
|
||||
fullscreen: 'Pantalla completa',
|
||||
},
|
||||
network: {
|
||||
title: 'Red',
|
||||
type: 'Tipo de red',
|
||||
remote: 'Remoto',
|
||||
localArtemis: 'Local (ARTEMiS)',
|
||||
artemisPath: 'Ruta de ARTEMiS',
|
||||
address: 'Dirección del servidor',
|
||||
keychip: 'Keychip',
|
||||
subnet: 'Subred',
|
||||
addrSuffix: 'Sufijo de dirección',
|
||||
},
|
||||
aime: {
|
||||
type: 'Tipo de Aime',
|
||||
modules: 'Módulos Aime',
|
||||
code: 'Código Aime',
|
||||
codeTooltip:
|
||||
'Solo aplicable con la emulación integrada de segatools o con paquetes de terceros compatibles',
|
||||
aimedb: 'Usar AiMeDB para tarjetas físicas',
|
||||
aimedbTooltip:
|
||||
'Ya sea si las tarjetas físicas deben usar AiMeDB para recuperar códigos de acceso. Si el juego está usando una red alojada, habilitar esta opción para cargar los mismos datos de cuenta/perfil que obtendrías en un cabinete físico.',
|
||||
serialPort: 'Puerto serial Aime',
|
||||
serialPortTooltip: `Los puertos pueden verificarse en Dispositivos e Impresoras o en googlechromelabs.github.io/serial-terminal
|
||||
Para AIC Pico, debe seleccionarse el puerto AIME.`,
|
||||
serverName: 'Nombre del servidor',
|
||||
},
|
||||
misc: {
|
||||
title: 'Misceláneo',
|
||||
intel: 'Solución alternativa para el error de OpenSSL en Intel ≥10ma gen',
|
||||
intelTooltip: 'Es recomendable parchear amdaemon en su lugar.',
|
||||
other: 'Otras opciones de segatools',
|
||||
otherTooltip:
|
||||
'Opciones avanzadas o situacionales no cubiertas por STARTLINER',
|
||||
prescript: 'Script de inicio',
|
||||
prescriptTooltip: 'Script opcional que se ejecuta antes del juego.',
|
||||
postscript: 'Script de finalización',
|
||||
postscriptTooltip:
|
||||
'Script opcional que se ejecuta después de que el juego haya terminado.',
|
||||
},
|
||||
extensions: {
|
||||
title: 'Extensiones',
|
||||
bepInExConsole: 'Consola BepInEx',
|
||||
audioMode: 'Modo de audio',
|
||||
audioTooltip:
|
||||
'El modo exclusivo de 2 canales requiere 7EVENDAYSHOLIDAYS-ExclusiveAudio',
|
||||
audioShared: 'Compartido',
|
||||
audio6Ch: 'Exclusivo de 6 canales',
|
||||
audio2Ch: 'Exclusivo de 2 canales',
|
||||
sampleRate: 'Tasa de muestreo',
|
||||
blacklist: 'Lista negra de ID de canciones',
|
||||
blacklistTooltip:
|
||||
'Las puntuaciones en pistas dentro de este rango de ID no se guardarán ni subirán',
|
||||
bonusTracks: 'Desbloquear pistas adicionales',
|
||||
bonusTracksTooltip:
|
||||
'Desactivar esta opción puede ayudar a descongestionar la lista de canciones',
|
||||
saekawa: 'Archivo de configuración de Saekawa',
|
||||
inohara: 'Archivo de configuración de Inohara',
|
||||
},
|
||||
keyboard: {
|
||||
title: 'Teclado',
|
||||
tooltip:
|
||||
'Solo aplicable si el módulo IO está configurado como segatools integrado (teclado) o un módulo de terceros compatible (como mu3io.NET)',
|
||||
leverMode: 'Modo de palanca',
|
||||
mouse: 'Ratón',
|
||||
irTooltip:
|
||||
'Cuando juegues con un teclado real, solo vincula ir1; deja el resto sin vincular',
|
||||
},
|
||||
wine: {
|
||||
prefix: 'Prefijo de Wine',
|
||||
runtime: 'Runtime de Wine',
|
||||
},
|
||||
startliner: {
|
||||
offlineMode: 'Modo sin conexión',
|
||||
offlineModeTooltip: 'Desactiva la tienda de paquetes.',
|
||||
autoUpdate: 'Actualizaciones automáticas',
|
||||
verbose: 'Registros detallados',
|
||||
},
|
||||
},
|
||||
onboarding: {
|
||||
or: 'o',
|
||||
backButton: 'un botón en la parte trasera del controlador',
|
||||
standard: `
|
||||
Es posible que te quedes atascado en la siguiente pantalla:
|
||||
|
||||
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||
|
||||
En ese caso, debes ir al menú de prueba, y en la configuración del juego {black}ゲーム設定{end} cambiar de "seguir la máquina estándar" {black}基準機に従う{end} a "máquina estándar" {black}基準機{end}.
|
||||
|
||||
Se puede acceder al menú de prueba con %TESTMENU%.
|
||||
`,
|
||||
|
||||
'ongeki-system-processing': `
|
||||
Es posible que te quedes atascado en esta pantalla durante varios minutos. _Esto es normal_. El juego simplemente tarda mucho en cargar datos.
|
||||
|
||||
Si instalas <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, los arranques siguientes serán mucho más rápidos.
|
||||
`,
|
||||
|
||||
'ongeki-lever': `
|
||||
También tienes que calibrar la palanca, o podrías obtener el error 3301.
|
||||
|
||||
Ve a la configuración de palanca ({black}レバー設定{end}), mueve la palanca hacia ambos extremos, luego presiona "finalizar" ({black}終了{end}) y "guardar" ({black}保存する{end}).
|
||||
`,
|
||||
|
||||
'chunithm-server': `
|
||||
Si estás atascado en esta pantalla, reinicia el juego.
|
||||
|
||||
Si el problema persiste, {link}comprueba tu configuración de red{endlink}
|
||||
`,
|
||||
|
||||
finale: `
|
||||
Puedes acceder a esta página en cualquier momento haciendo clic derecho en el botón INICIAR.
|
||||
|
||||
Recursos adicionales:
|
||||
|
||||
- {segaguide}SEGAguide{endlink}
|
||||
- {twotorial}two-torial{endlink}
|
||||
|
||||
## Diviértete
|
||||
`,
|
||||
},
|
||||
};
|
294
src/i18n/ja.ts
Normal file
294
src/i18n/ja.ts
Normal file
@ -0,0 +1,294 @@
|
||||
export default {
|
||||
ok: 'OK',
|
||||
cancel: 'キャンセル',
|
||||
enable: '有効にする',
|
||||
disable: '無効にする',
|
||||
default: 'デフォルト',
|
||||
search: '検索',
|
||||
next: '次へ',
|
||||
skip: 'スキップ',
|
||||
close: '閉じる',
|
||||
by: '{namespace}作',
|
||||
updateAll: 'すべてを更新',
|
||||
start: {
|
||||
failed: '起動確認に失敗',
|
||||
accept: 'とにかく実行',
|
||||
error: {
|
||||
package: 'パッケージが見つかりません',
|
||||
dependency: '依存関係が見つかりません',
|
||||
tool: 'ツールが見つかりません',
|
||||
unknown: '不明なエラー',
|
||||
},
|
||||
tooltip: {
|
||||
game: 'ゲームのパスを指定してください',
|
||||
amfs: 'amfsのパスを指定してください',
|
||||
segatools: 'segatoolsフックパッケージが必要です',
|
||||
},
|
||||
button: {
|
||||
start: '開始',
|
||||
stop: '停止',
|
||||
unchecked: 'チェックをスキップして起動',
|
||||
shortcut: 'デスクトップショートカットを作成',
|
||||
help: 'ヘルプ',
|
||||
refresh: 'MODを再適用して起動',
|
||||
cache: 'MODキャッシュのクリア',
|
||||
},
|
||||
},
|
||||
game: {
|
||||
ongeki: 'オンゲキ',
|
||||
chunithm: 'チュウニズム',
|
||||
},
|
||||
profile: {
|
||||
welcome: 'STARTLINERへようこそ! プロフィルの作成から始めよう。',
|
||||
create: '{game}のプロフィル',
|
||||
delete: 'プロフィル削除',
|
||||
reallyDelete: '本当に{profile}を削除しますか?',
|
||||
template: 'STARTLINERのテンプレート',
|
||||
importTemplate: 'テンプレートのインポート',
|
||||
exportTemplate: 'プロフィルのエクスポート',
|
||||
export: 'エクスポート',
|
||||
standardExport: 'テンプレート',
|
||||
diagnostic: '診断',
|
||||
},
|
||||
creator: {
|
||||
header: 'パッケージ製作者',
|
||||
basic: '基本情報',
|
||||
name: '名前',
|
||||
description: '説明',
|
||||
website: 'ウェブサイト',
|
||||
type: 'パッケージタイプ',
|
||||
rainy: 'スタンダード',
|
||||
segatools: 'segatools',
|
||||
native: 'ネイティブ',
|
||||
games: 'ゲーム',
|
||||
packageFormat: 'パッケージフォーマット仕様',
|
||||
},
|
||||
store: {
|
||||
installRecommended: 'おすすめパッケージをインストール',
|
||||
installed: 'インストール済みを表示',
|
||||
deprecated: '非推奨を表示',
|
||||
nsfw: '閲覧注意コンテンツを表示',
|
||||
incompatible: 'このパッケージは現在STARTLINERと互換性がありません。',
|
||||
includeCategories: 'カテゴリーを含める',
|
||||
excludeCategories: 'カテゴリーを除く',
|
||||
},
|
||||
pkglist: {
|
||||
missing: '見つからない',
|
||||
local: 'ローカルパッケージ',
|
||||
namespace: '名前空間順',
|
||||
type: 'タイプ順',
|
||||
category: 'カテゴリ順',
|
||||
standard: 'スタンダードMOD',
|
||||
native: 'ネイティブMOD',
|
||||
segatools: 'segatools',
|
||||
unsupported: '未対応',
|
||||
exclusions: '除外:',
|
||||
},
|
||||
patch: {
|
||||
loading: 'ロード中...',
|
||||
noneFound:
|
||||
'互換性のあるパッチが見つかりません。アンパック済みでパッチが適用されていないファイルを使用していることを確認してください。',
|
||||
forceLoad: '強制ロード',
|
||||
'standard-shared-audio':
|
||||
'共有オーディオモードを強制、システムオーディオのサンプルレートは48000Hzである必要があります',
|
||||
'standard-shared-audio-tooltip':
|
||||
'互換性は向上しますが、遅延が増加する可能性があります',
|
||||
'standard-2ch': '2チャンネルオーディオ出力を強制',
|
||||
'standard-2ch-tooltip': '低音の過負荷を引き起こす可能性があります',
|
||||
'standard-song-timer': '楽曲選択タイマーを無効にする',
|
||||
'standard-map-timer': 'マップ選択タイマー',
|
||||
'standard-map-timer-tooltip':
|
||||
'負の値を設定すると、タイマーは968 + 値となります(例:968 + -1 = 967)',
|
||||
'standard-ticket-timer': 'チケット選択タイマー',
|
||||
'standard-ticket-timer-tooltip':
|
||||
'負の値を設定すると、タイマーは968 + 値となります(例:968 + -1 = 967)',
|
||||
'standard-course-timer': 'コース選択タイマー',
|
||||
'standard-course-timer-tooltip':
|
||||
'負の値を設定すると、タイマーは968 + 値となります(例:968 + -1 = 967)',
|
||||
'standard-unlimited-tracks': '最大トラック数無制限',
|
||||
'standard-unlimited-tracks-tooltip':
|
||||
'1クレジットにつき7曲以上プレイする場合はチェックが必要です',
|
||||
'standard-maximum-tracks': '最大トラック数',
|
||||
'standard-no-encryption': '暗号化無し',
|
||||
'standard-no-encryption-tooltip': 'TLSも無効にします',
|
||||
'standard-no-tls': 'TLS無し',
|
||||
'standard-no-tls-tooltip': 'タイトルサーバーの回避策',
|
||||
'standard-head-to-head': 'ヘッド・トゥ・ヘッドパッチ',
|
||||
'standard-head-to-head-tooltip':
|
||||
'ヘッド・トゥ・ヘッドプレイ接続時の無限同期問題を修正',
|
||||
'standard-bypass-1080p': '1080pモニターチェックをバイパス',
|
||||
'standard-bypass-120hz': '120Hzモニターチェックをバイパス',
|
||||
'standard-force-free-play-text': 'FREE PLAYクレジットテキストを強制',
|
||||
'standard-force-free-play-text-tooltip':
|
||||
'クレジット数をFREE PLAYに置き換える',
|
||||
'standard-custom-free-play-length': 'カスタムFREE PLAYテキスト長',
|
||||
'standard-custom-free-play-length-tooltip':
|
||||
'FREE PLAYクレジット表示を強制が有効な場合に表示されるテキストの長さを変更します。',
|
||||
'standard-custom-free-play-text': 'カスタムFREE PLAYテキスト',
|
||||
'standard-custom-free-play-text-tooltip':
|
||||
'無限クレジット使用時、FREE PLAYのテキストを置き換えます。',
|
||||
'standard-localhost':
|
||||
'ネットワークサーバーとして127.0.0.1/localhostを許可',
|
||||
'standard-credit-freeze': 'クレジット凍結',
|
||||
'standard-credit-freeze-tooltip':
|
||||
'クレジットの使用を防ぎます。ゲームを開始したり、プレミアムチケットを購入したりするには、少なくとも1クレジットが使用可能である必要があります。',
|
||||
'standard-openssl-fix': 'OpenSSL SHAクラッシュのバグ修正',
|
||||
'standard-openssl-fix-tooltip':
|
||||
'第10世代以降のIntel CPUでのクラッシュを修正します',
|
||||
},
|
||||
cfg: {
|
||||
afterRestart: '再起動後に適用',
|
||||
hardware: 'ハードウェア',
|
||||
segatools: {
|
||||
general: '一般',
|
||||
builtIn: 'segatools内蔵エミュレーション',
|
||||
targetTooltip:
|
||||
'STARTLINERは、アンパック済みで改造されていない実行可能ファイルの使用を想定しています。',
|
||||
hooks: 'フック',
|
||||
ioModules: 'IOモジュール',
|
||||
ioModulesDesc: '希望する入力方法と一致させる必要があります。',
|
||||
ioBuiltIn: 'segatools内蔵(キーボード)',
|
||||
io4: 'ネイティブIO4',
|
||||
installTooltip:
|
||||
'{thing}はパッケージストアからダウンロードできます。',
|
||||
},
|
||||
display: {
|
||||
title: 'ディスプレイ',
|
||||
resolution: 'ゲーム解像度',
|
||||
primary: 'メインディスプレイ',
|
||||
target: 'ターゲットディスプレイ',
|
||||
mode: 'モード',
|
||||
rotation: '画面の向き',
|
||||
refreshRate: 'リフレッシュレート',
|
||||
borderlessFullscreen: 'ボーダレスフルスクリーン',
|
||||
borderlessFullscreenTooltip:
|
||||
'ディスプレイの解像度をゲームに合わせる。',
|
||||
dontSwitchPrimary: 'メインディスプレイの切り替えをスキップ',
|
||||
dontSwitchPrimaryTooltip:
|
||||
'メインディスプレイの切り替えで問題が発生する場合にのみ、このオプションを有効にしてください。モニターのリフレッシュレートは一致している必要があります。',
|
||||
index: 'ディスプレイインデックス',
|
||||
portrait: '縦',
|
||||
landscape: '横',
|
||||
flipped: '対称移動',
|
||||
window: 'ウィンドウ',
|
||||
borderless: 'ボーダレスウィンドウ',
|
||||
fullscreen: 'フルスクリーン',
|
||||
},
|
||||
network: {
|
||||
title: 'ネットワーク',
|
||||
type: 'ネットワークタイプ',
|
||||
remote: 'リモート',
|
||||
localArtemis: 'ローカル(ARTEMiS)',
|
||||
artemisPath: 'ARTEMiSパス',
|
||||
address: 'サーバーアドレス',
|
||||
keychip: 'キーチップ',
|
||||
subnet: 'サブネット',
|
||||
addrSuffix: 'アドレスサフィックス',
|
||||
},
|
||||
aime: {
|
||||
type: 'Aimeタイプ',
|
||||
modules: 'Aimeモジュール',
|
||||
code: 'アクセスコード',
|
||||
codeTooltip:
|
||||
'segatools内蔵エミュレーションまたは互換性のあるサードパーティ製パッケージでのみ使用可能。',
|
||||
aimedb: '物理カードにはAiMeDBを使う',
|
||||
aimedbTooltip:
|
||||
'物理カードがアクセスコードを取得するためにAiMeDBを使用するかどうか。ゲームがホストされたネットワークを使用している場合、このオプションを有効にすると、物理筐体で取得するのと同じアカウントデータ/プロフィルがロードされます。',
|
||||
serialPort: 'Aimeシリアルポート',
|
||||
serialPortTooltip: `ポートはデバイスとプリンター、またはgooglechromelabs.github.io/serial-terminalで確認できます
|
||||
AIC Picoの場合は、AIMEポートを選択する。`,
|
||||
serverName: 'サーバー名',
|
||||
},
|
||||
misc: {
|
||||
title: 'その他',
|
||||
intel: '第10世代以降Intel CPU向けOpenSSLバグ回避策',
|
||||
intelTooltip: '代わりにamdaemonにパッチを当てることを推奨します。',
|
||||
other: 'その他のsegatools設定',
|
||||
otherTooltip: 'STARTLINERでカバーされていない上級者向けまたは状況別設定。',
|
||||
prescript: '起動前スクリプト',
|
||||
prescriptTooltip: 'ゲームの起動前に実行されるスクリプト。',
|
||||
postscript: '終了後スクリプト',
|
||||
postscriptTooltip: 'ゲーム終了後に実行されるスクリプト。',
|
||||
},
|
||||
extensions: {
|
||||
title: 'エクステンション',
|
||||
bepInExConsole: 'BepInExコンソール',
|
||||
audioMode: 'オーディオモード',
|
||||
audioTooltip:
|
||||
'排他2チャンネルモードには7EVENDAYSHOLIDAYS-ExclusiveAudioが必要です',
|
||||
audioShared: '共有',
|
||||
audio6Ch: '排他6チャンネル',
|
||||
audio2Ch: '排他2チャンネル',
|
||||
sampleRate: 'サンプルレート',
|
||||
blacklist: '楽曲IDブラックリスト',
|
||||
blacklistTooltip:
|
||||
'このID範囲内の譜面のスコアは保存もアップロードもされません。',
|
||||
bonusTracks: 'ボーナストラックのアンロック',
|
||||
bonusTracksTooltip:
|
||||
'このオプションを無効にすると、楽曲リストを整理するのに役立ちます。',
|
||||
saekawa: 'Saekawa設定ファイル',
|
||||
inohara: 'Inohara設定ファイル',
|
||||
},
|
||||
keyboard: {
|
||||
title: 'キーボード',
|
||||
tooltip:
|
||||
'IOモジュールがsegatools内蔵(キーボード)または互換性のあるサードパーティモジュール(mu3io.NETなど)に設定されている場合のみ適用可能。',
|
||||
leverMode: 'レバーモード',
|
||||
mouse: 'マウス',
|
||||
irTooltip:
|
||||
'実際のキーボードでプレイする場合は、ir1のみをバインドし、残りはバインドしないでください。',
|
||||
},
|
||||
wine: {
|
||||
prefix: 'Wineプレフィックス',
|
||||
runtime: 'Wineランタイム',
|
||||
},
|
||||
startliner: {
|
||||
offlineMode: 'オフラインモード',
|
||||
offlineModeTooltip: 'パッケージストアを無効にする。',
|
||||
autoUpdate: '自動更新',
|
||||
verbose: '詳細ログ',
|
||||
},
|
||||
},
|
||||
onboarding: {
|
||||
or: 'または',
|
||||
backButton: 'コントローラー背面のボタン',
|
||||
standard: `
|
||||
以下のような画面で止まる可能性があります:
|
||||
|
||||
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||
|
||||
その場合、テストメニューに移動し、{black}ゲーム設定{end}の{black}基準に従う{end}から{black}基準機{end}に切り替える必要があります。
|
||||
|
||||
テストメニューは%TESTMENU%でアクセスできます。
|
||||
`,
|
||||
|
||||
'ongeki-system-processing': `
|
||||
この画面で数分間止まる可能性があります。_これは正常です_。ゲームがデータをロードするのに時間がかかるだけです。
|
||||
|
||||
<code>7EVENDAYSHOLIDAYS/LoadBoost</code>をインストールすれば、それ以降の起動はるかに速くなります。
|
||||
`,
|
||||
|
||||
'ongeki-lever': `
|
||||
レバーのキャリブレーションを行わないと、エラー3301が発生する可能性があります。
|
||||
|
||||
{black}レバー設定{end}に移動し、レバーを両端に動かしてから、{black}終了{end}を押してから{black}保存する{end}を押します。
|
||||
`,
|
||||
|
||||
'chunithm-server': `
|
||||
この画面で止まっている場合は、ゲームを再起動してください。
|
||||
|
||||
問題が解決しない場合は、{link}ネットワーク設定を確認してください{endlink}
|
||||
`,
|
||||
|
||||
finale: `
|
||||
STARTボタンを右クリックすれば、いつでもこのページにアクセスできます。
|
||||
|
||||
その他のリソース:
|
||||
|
||||
- {segaguide}SEGAguide{endlink}
|
||||
- {twotorial}two-torial{endlink}
|
||||
|
||||
## 楽しもう!
|
||||
`,
|
||||
},
|
||||
};
|
284
src/i18n/ko.ts
Normal file
284
src/i18n/ko.ts
Normal file
@ -0,0 +1,284 @@
|
||||
export default {
|
||||
ok: '확인',
|
||||
cancel: '취소',
|
||||
enable: '활성화',
|
||||
disable: '비활성화',
|
||||
default: '기본값',
|
||||
search: '검색',
|
||||
next: '다음',
|
||||
skip: '건너뛰기',
|
||||
close: '닫기',
|
||||
by: '제작자 {namespace}',
|
||||
updateAll: '모두 업데이트',
|
||||
start: {
|
||||
failed: '시작 확인 실패',
|
||||
accept: '계속하기',
|
||||
error: {
|
||||
package: '패키지 누락',
|
||||
dependency: '의존성 누락',
|
||||
tool: '도구 없음',
|
||||
unknown: '알 수 없는 오류',
|
||||
},
|
||||
tooltip: {
|
||||
game: '게임 경로를 지정해야 합니다',
|
||||
amfs: 'amfs 경로를 지정해야 합니다',
|
||||
segatools: 'segatools 훅 패키지가 필요합니다',
|
||||
},
|
||||
button: {
|
||||
start: '시작',
|
||||
stop: '중지',
|
||||
unchecked: '확인을 건너뛰고 시작',
|
||||
shortcut: '바탕화면 바로가기 만들기',
|
||||
help: '도움말',
|
||||
refresh: '모드를 다시 적용하고 시작',
|
||||
cache: '모드 캐시 지우기',
|
||||
},
|
||||
},
|
||||
game: {
|
||||
ongeki: 'O.N.G.E.K.I.',
|
||||
chunithm: 'CHUNITHM',
|
||||
},
|
||||
profile: {
|
||||
welcome: 'STARTLINER에 오신 것을 환영합니다! 프로필을 생성하여 시작하세요.',
|
||||
create: '{game} 프로필',
|
||||
delete: '프로필 삭제',
|
||||
reallyDelete: '정말로 {profile}을(를) 삭제하시겠습니까?',
|
||||
template: 'STARTLINER 템플릿',
|
||||
importTemplate: '템플릿 가져오기',
|
||||
exportTemplate: '프로필 내보내기',
|
||||
export: '내보내기',
|
||||
standardExport: '템플릿',
|
||||
diagnostic: '진단',
|
||||
},
|
||||
creator: {
|
||||
header: '패키지 제작자',
|
||||
basic: '기본 정보',
|
||||
name: '이름',
|
||||
description: '설명',
|
||||
website: '웹사이트',
|
||||
type: '패키지 유형',
|
||||
rainy: '기본',
|
||||
segatools: 'Segatools',
|
||||
native: '네이티브',
|
||||
games: '게임',
|
||||
packageFormat: '패키지 형식 사양',
|
||||
},
|
||||
store: {
|
||||
installRecommended: '권장 패키지 설치',
|
||||
installed: '설치된 항목 표시',
|
||||
deprecated: '더 이상 사용되지 않는 항목 표시',
|
||||
nsfw: '부적절한 콘텐츠 표시',
|
||||
incompatible: '이 패키지는 현재 STARTLINER와 호환되지 않습니다.',
|
||||
|
||||
includeCategories: '카테고리 포함',
|
||||
excludeCategories: '카테고리 제외',
|
||||
},
|
||||
pkglist: {
|
||||
missing: '없음',
|
||||
local: '로컬 패키지',
|
||||
namespace: '네임스페이스별',
|
||||
type: '유형별',
|
||||
category: '카테고리별',
|
||||
standard: '표준 모드',
|
||||
native: '네이티브 모드',
|
||||
segatools: 'Segatools',
|
||||
unsupported: '지원되지 않음',
|
||||
exclusions: '제외 항목:',
|
||||
},
|
||||
patch: {
|
||||
loading: '로딩 중...',
|
||||
noneFound:
|
||||
"호환되는 패치가 없습니다. 언팩이 된 패치되지 않은 파일을 사용하고 있는지 확인하세요.",
|
||||
forceLoad: '강제 로드',
|
||||
'standard-shared-audio': '공유 오디오 모드 강제 활성화. 시스템 오디오 샘플 레이트는 48000Hz여야 합니다.',
|
||||
'standard-shared-audio-tooltip': '호환성을 개선하지만 대기 시간이 증가할 수 있습니다.',
|
||||
'standard-2ch': '2채널 오디오 출력 강제 활성화',
|
||||
'standard-2ch-tooltip': '과도한 저음을 유발할 수 있습니다.',
|
||||
'standard-song-timer': '곡 선택 타이머 비활성화',
|
||||
'standard-map-timer': '맵 선택 타이머',
|
||||
'standard-map-timer-tooltip': '음수가 설정되면 타이머는 968 + 값이 됩니다 (예: 968 + -1 = 967)',
|
||||
'standard-ticket-timer': '티켓 선택 타이머',
|
||||
'standard-ticket-timer-tooltip': '음수가 설정되면 타이머는 968 + 값이 됩니다 (예: 968 + -1 = 967)',
|
||||
'standard-course-timer': '코스 선택 타이머',
|
||||
'standard-course-timer-tooltip': '음수가 설정되면 타이머는 968 + 값이 됩니다 (예: 968 + -1 = 967)',
|
||||
'standard-unlimited-tracks': '무제한 최대 트랙',
|
||||
'standard-unlimited-tracks-tooltip': '7개 이상의 트랙을 재생하려면 체크해야 합니다.',
|
||||
'standard-maximum-tracks': '최대 트랙',
|
||||
'standard-no-encryption': '암호화 없음',
|
||||
'standard-no-encryption-tooltip': 'TLS도 비활성화됩니다.',
|
||||
'standard-no-tls': 'TLS 없음',
|
||||
'standard-no-tls-tooltip': '타이틀 서버 우회',
|
||||
'standard-head-to-head': '대결 플레이 패치',
|
||||
'standard-head-to-head-tooltip': '대결 플레이에 연결할 때 무한 동기화 문제를 수정합니다.',
|
||||
'standard-bypass-1080p': '1080p 모니터 확인 우회',
|
||||
'standard-bypass-120hz': '120Hz 모니터 확인 우회',
|
||||
'standard-force-free-play-text': 'FREE PLAY 크레딧 텍스트 강제 표시',
|
||||
'standard-force-free-play-text-tooltip': '크레딧 수를 FREE PLAY로 표시합니다.',
|
||||
'standard-custom-free-play-length': '사용자 지정 FREE PLAY 텍스트 길이',
|
||||
'standard-custom-free-play-length-tooltip': '사용자 지정 FREE PLAY 크레딧 패치가 활성화될 때 표시되는 텍스트의 길이를 변경합니다.',
|
||||
'standard-custom-free-play-text': '사용자 지정 FREE PLAY 텍스트',
|
||||
'standard-custom-free-play-text-tooltip': '무제한 크레딧을 사용할 때 FREE PLAY 텍스트를 대체합니다.',
|
||||
'standard-localhost': '네트워크 서버로 127.0.0.1/localhost 사용 허용',
|
||||
'standard-credit-freeze': '크레딧 잠금',
|
||||
'standard-credit-freeze-tooltip': '크레딧 사용을 방지합니다. 게임 시작 또는 프리미엄 티켓 구매를 위해서는 최소 1크레딧이 있어야 합니다.',
|
||||
'standard-openssl-fix': 'OpenSSL SHA 충돌 버그 수정',
|
||||
'standard-openssl-fix-tooltip': '10세대 이상 Intel CPU에서 발생하는 충돌을 수정합니다.',
|
||||
|
||||
},
|
||||
cfg: {
|
||||
afterRestart: '재시작 후 적용됩니다',
|
||||
hardware: '하드웨어',
|
||||
segatools: {
|
||||
general: '일반',
|
||||
builtIn: 'Segatools 내장 에뮬레이션',
|
||||
targetTooltip:
|
||||
'STARTLINER를 사용하려면, 언팩된 실행 파일을 별도의 수정이 없는 데이터와 함께 사용해야 합니다.',
|
||||
hooks: '훅',
|
||||
ioModules: 'IO 모듈',
|
||||
ioModulesDesc: '원하는 입력 방식과 일치해야 합니다.',
|
||||
ioBuiltIn: 'Segatools 내장 (키보드)',
|
||||
io4: '네이티브 IO4',
|
||||
installTooltip: '패키지 스토어에서 {thing}을(를) 다운로드하실 수 있습니다.',
|
||||
},
|
||||
display: {
|
||||
title: '디스플레이',
|
||||
resolution: '게임 해상도',
|
||||
primary: '주 디스플레이',
|
||||
target: '대상 디스플레이',
|
||||
mode: '모드',
|
||||
rotation: '회전',
|
||||
refreshRate: '주사율',
|
||||
borderlessFullscreen: '테두리 없는 전체 화면',
|
||||
borderlessFullscreenTooltip:
|
||||
'게임과 디스플레이 해상도를 일치시킵니다.',
|
||||
dontSwitchPrimary: '주 디스플레이 전환 건너뛰기',
|
||||
dontSwitchPrimaryTooltip:
|
||||
'주 디스플레이 전환 시 문제가 발생하는 경우에만 이 옵션을 활성화하세요. 모니터의 주사율이 일치해야 합니다.',
|
||||
index: '디스플레이 번호',
|
||||
portrait: '세로',
|
||||
landscape: '가로',
|
||||
flipped: '대칭 이동',
|
||||
window: '창',
|
||||
borderless: '테두리 없는 창',
|
||||
fullscreen: '전체 화면',
|
||||
},
|
||||
network: {
|
||||
title: '네트워크',
|
||||
type: '네트워크 유형',
|
||||
remote: '원격',
|
||||
localArtemis: '로컬 (ARTEMiS)',
|
||||
artemisPath: 'ARTEMiS 경로',
|
||||
address: '서버 주소',
|
||||
keychip: '키칩',
|
||||
subnet: '서브넷',
|
||||
addrSuffix: '주소 접미사',
|
||||
},
|
||||
aime: {
|
||||
type: 'Aime 유형',
|
||||
modules: 'Aime 모듈',
|
||||
code: 'Aime 코드',
|
||||
codeTooltip:
|
||||
'Segatools 내장 에뮬레이션 또는 호환 가능한 패키지에서만 적용됩니다.',
|
||||
aimedb: '실물 카드에 AiMeDB 사용',
|
||||
aimedbTooltip:
|
||||
'실물 카드가 접속 코드를 가져올 때 AiMeDB를 사용할지 여부입니다. 게임이 호스팅된 네트워크를 사용하는 경우, 실제 아케이드 캐비닛에서 얻을 수 있는 것과 동일한 계정 데이터/프로필을 불러오려면 이 옵션을 활성화하세요.',
|
||||
serialPort: 'Aime 리더 포트',
|
||||
serialPortTooltip: `포트는 장치 및 프린터 또는 googlechromelabs.github.io/serial-terminal에서 확인할 수 있습니다.
|
||||
AIC Pico의 경우, AIME 포트를 선택해야 합니다.`,
|
||||
serverName: '서버 이름',
|
||||
},
|
||||
misc: {
|
||||
title: '기타',
|
||||
intel: '인텔 10세대 이상 CPU OpenSSL 버그 우회',
|
||||
intelTooltip: '대신 amdaemon을 패치하는 것이 권장됩니다.',
|
||||
other: '기타 Segatools 옵션',
|
||||
otherTooltip:
|
||||
'STARTLINER에서 다루지 않는 고급 또는 특정 상황용 옵션입니다.',
|
||||
prescript: '시작 스크립트',
|
||||
prescriptTooltip: '게임 실행 전에 실행되는 선택적 스크립트입니다.',
|
||||
postscript: '종료 스크립트',
|
||||
postscriptTooltip:
|
||||
'게임이 종료된 후에 실행되는 선택적 스크립트입니다.',
|
||||
},
|
||||
extensions: {
|
||||
title: '확장',
|
||||
bepInExConsole: 'BepInEx 콘솔',
|
||||
audioMode: '오디오 모드',
|
||||
audioTooltip:
|
||||
'전용 2채널 모드는 7EVENDAYSHOLIDAYS-ExclusiveAudio를 필요로 합니다.',
|
||||
audioShared: '공유',
|
||||
audio6Ch: '전용 6채널',
|
||||
audio2Ch: '전용 2채널',
|
||||
sampleRate: '샘플 레이트',
|
||||
blacklist: '노래 ID 제외 목록',
|
||||
blacklistTooltip:
|
||||
'이 ID 범위 내의 차트 점수는 저장되거나 업로드되지 않습니다.',
|
||||
bonusTracks: '보너스 트랙 잠금 해제',
|
||||
bonusTracksTooltip:
|
||||
'이 옵션을 비활성화하면 곡 목록을 정리하는 데 도움이 될 수 있습니다.',
|
||||
saekawa: 'Saekawa 설정 파일',
|
||||
inohara: 'Inohara 설정 파일',
|
||||
},
|
||||
keyboard: {
|
||||
title: '키보드',
|
||||
tooltip:
|
||||
'IO 모듈이 segatools 내장 (키보드) 또는 호환 가능한 모듈 (예: mu3io.NET)로 설정된 경우에만 적용됩니다.',
|
||||
leverMode: '레버 모드',
|
||||
mouse: '마우스',
|
||||
irTooltip:
|
||||
'실제 키보드로 플레이할 경우, ir1만 할당하고 나머지는 할당하지 마세요.',
|
||||
},
|
||||
wine: {
|
||||
prefix: 'Wine 프리픽스',
|
||||
runtime: 'Wine 런타임',
|
||||
},
|
||||
startliner: {
|
||||
offlineMode: '오프라인 모드',
|
||||
offlineModeTooltip: '패키지 스토어를 비활성화합니다.',
|
||||
autoUpdate: '자동 업데이트',
|
||||
verbose: '상세 로그',
|
||||
},
|
||||
},
|
||||
onboarding: {
|
||||
or: '또는',
|
||||
backButton: '컨트롤러 후면의 버튼',
|
||||
standard: `
|
||||
다음 화면에서 멈출 수 있습니다:
|
||||
|
||||
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||
|
||||
이 경우, 테스트 메뉴로 이동하여 게임 설정 {black}ゲーム設定{end}에서 "기준기 따르기" {black}基準機に従う{end}를 "기준기" {black}基準機{end}로 변경해야 합니다.
|
||||
|
||||
테스트 메뉴는 %TESTMENU%을 사용하여 접근할 수 있습니다.
|
||||
`,
|
||||
|
||||
'ongeki-system-processing': `
|
||||
이 화면에서 몇 분간 멈출 수 있습니다. _이는 정상입니다_. 게임이 데이터를 로드하는 데 시간이 오래 걸릴 뿐입니다.
|
||||
|
||||
<code>7EVENDAYSHOLIDAYS/LoadBoost</code>를 설치하면 이후 실행 시 훨씬 빨라집니다.
|
||||
`,
|
||||
|
||||
'ongeki-lever': `
|
||||
또한 레버를 보정해야 합니다. 그렇지 않으면 에러 3301이 발생할 수 있습니다.
|
||||
|
||||
레버 설정 ({black}レバー設定{end})으로 이동하여 레버를 양쪽 끝으로 움직인 다음, "종료" ({black}終了{end})를 누르고 "저장" ({black}保存する{end})을 누르세요.
|
||||
`,
|
||||
|
||||
'chunithm-server': `
|
||||
이 화면에서 멈춘 경우, 게임을 다시 시작하세요.
|
||||
|
||||
문제가 계속되면, {link}네트워크 설정을 확인하세요{endlink}
|
||||
`,
|
||||
|
||||
finale: `
|
||||
이 페이지는 언제든지 시작 버튼을 오른쪽 클릭하여 접근할 수 있습니다.
|
||||
|
||||
추가 자료:
|
||||
|
||||
- {segaguide}SEGAguide{endlink}
|
||||
- {twotorial}two-torial{endlink}
|
||||
|
||||
## 즐
|
||||
`,
|
||||
},
|
||||
};
|
296
src/i18n/pl.ts
Normal file
296
src/i18n/pl.ts
Normal file
@ -0,0 +1,296 @@
|
||||
export default {
|
||||
ok: 'OK',
|
||||
cancel: 'Anuluj',
|
||||
enable: 'Włącz',
|
||||
disable: 'Wyłącz',
|
||||
default: 'Domyślne',
|
||||
search: 'Wyszukaj',
|
||||
next: 'Dalej',
|
||||
skip: 'Pomiń',
|
||||
close: 'Zamknij',
|
||||
by: 'od {namespace}',
|
||||
updateAll: 'ZAKTUALIZUJ WSZYSTKO',
|
||||
start: {
|
||||
failed: 'Uruchomienie nie powiodło się',
|
||||
accept: 'Uruchom mimo to',
|
||||
error: {
|
||||
package: 'Brakujący pakiet',
|
||||
dependency: 'Brakująca dependencja',
|
||||
tool: 'Brakujące narzędzie',
|
||||
unknown: 'Nieznany błąd',
|
||||
},
|
||||
tooltip: {
|
||||
game: 'Należy najpierw wskazać lokalizację gry',
|
||||
amfs: 'Należy najpierw wskazać lokalizację amfs',
|
||||
segatools: 'Należy dodać hook segatools',
|
||||
},
|
||||
button: {
|
||||
start: 'START',
|
||||
stop: 'STOP',
|
||||
unchecked: 'Uruchom bez sprawdzania',
|
||||
shortcut: 'Utwórz skrót',
|
||||
help: 'Pomoc',
|
||||
refresh: 'Uruchom po re-aplikacji modów',
|
||||
cache: 'Wyczyść mod cache',
|
||||
},
|
||||
},
|
||||
game: {
|
||||
ongeki: 'O.N.G.E.K.I.',
|
||||
chunithm: 'CHUNITHM',
|
||||
},
|
||||
profile: {
|
||||
welcome: 'Witaj w STARTLINERZE! Zacznij od utworzenia profilu',
|
||||
create: 'Profil {game}',
|
||||
delete: 'Usuń profil',
|
||||
reallyDelete: 'Czy na pewno chcesz usunąć {profile}?',
|
||||
template: 'Szablon',
|
||||
importTemplate: 'Importuj szablon',
|
||||
exportTemplate: 'Eksportuj profil',
|
||||
export: 'Eksportuj',
|
||||
standardExport: 'Szablon',
|
||||
diagnostic: 'Diagnostyka',
|
||||
},
|
||||
creator: {
|
||||
header: 'Kreator pakietów',
|
||||
basic: 'Podstawowe informacje',
|
||||
name: 'Nazwa',
|
||||
description: 'Opis',
|
||||
website: 'Strona internetowa',
|
||||
type: 'Typ',
|
||||
rainy: 'Standardowy',
|
||||
segatools: 'Segatools',
|
||||
native: 'Natywny',
|
||||
games: 'Gry',
|
||||
packageFormat: 'Specyfikacja formatu',
|
||||
},
|
||||
store: {
|
||||
installRecommended: 'Dodaj zalecane pakiety',
|
||||
installed: 'Pokaż zainstalowane',
|
||||
deprecated: 'Pokaż przestarzałe',
|
||||
nsfw: 'Pokaż mityczny O.N.G.E.K.I. Sex Mod dlaczego ta opcja w ogóle tu jest',
|
||||
incompatible:
|
||||
'Ten pakiet jest obecnie niekompatybilny ze STARTLINEREM.',
|
||||
includeCategories: 'Włącz kategorie',
|
||||
excludeCategories: 'Wyłącz kategorie',
|
||||
},
|
||||
pkglist: {
|
||||
missing: 'Niedostępne',
|
||||
local: 'Lokalne pakiety',
|
||||
namespace: 'Po przestrzeni nazw',
|
||||
type: 'Po typie',
|
||||
category: 'Po kategorii',
|
||||
standard: 'Standardowe mody',
|
||||
native: 'Natywne mody',
|
||||
segatools: 'segatools',
|
||||
unsupported: 'Niewspierane',
|
||||
exclusions: 'Czarna lista:',
|
||||
},
|
||||
patch: {
|
||||
loading: 'Wczytuję...',
|
||||
noneFound:
|
||||
'Brak kompatybilnych łatek. Upewnij się, że używasz czystych odpakowanych plików.',
|
||||
forceLoad: 'Wymuś załadowanie',
|
||||
'standard-shared-audio':
|
||||
'Wymuś współdzielony tryb dźwięku; częstotliwość w systemie musi wynosić 48kHz',
|
||||
'standard-shared-audio-tooltip':
|
||||
'Poprawia kompatybilność, ale może zwiększyć opóźnienie',
|
||||
'standard-2ch': 'Wymuś stereo',
|
||||
'standard-2ch-tooltip': 'Może powodować bass overload',
|
||||
'standard-song-timer': 'Wyłącz timer wyboru utworu',
|
||||
'standard-map-timer': 'Timer wyboru mapy',
|
||||
'standard-map-timer-tooltip':
|
||||
'Jeśli ustawiony na wartość ujemną, timer wyniesie 968 + wartość (np. 968 + -1 = 967)',
|
||||
'standard-ticket-timer': 'Timer wyboru biletu',
|
||||
'standard-ticket-timer-tooltip':
|
||||
'Jeśli ustawiony na wartość ujemną, timer wyniesie 968 + wartość (np. 968 + -1 = 967)',
|
||||
'standard-course-timer': 'Timer wyboru dana',
|
||||
'standard-course-timer-tooltip':
|
||||
'Jeśli ustawiony na wartość ujemną, timer wyniesie 968 + wartość (np. 968 + -1 = 967)',
|
||||
'standard-unlimited-tracks': 'Nieograniczona maksymalna liczba utworów',
|
||||
'standard-unlimited-tracks-tooltip':
|
||||
'Konieczne do grania więcej niż 7 utworów na kredyt',
|
||||
'standard-maximum-tracks': 'Maksymalna liczba utworów',
|
||||
'standard-no-encryption': 'Wyłącz szyfrowanie',
|
||||
'standard-no-encryption-tooltip': 'Wyłączy również TLS',
|
||||
'standard-no-tls': 'Wyłącz TLS',
|
||||
'standard-no-tls-tooltip': 'Obejście problemów z serwerem tytułowym',
|
||||
'standard-head-to-head': 'Napraw head to head',
|
||||
'standard-head-to-head-tooltip':
|
||||
'Naprawia nieskończoną synchronizację podczas próby połączenia w trybie head to head',
|
||||
'standard-bypass-1080p': 'Obejdź sprawdzenie 1080p',
|
||||
'standard-bypass-120hz': 'Obejdź sprawdzenie 120Hz',
|
||||
'standard-force-free-play-text': 'Wymuś tekst kredytu FREE PLAY',
|
||||
'standard-force-free-play-text-tooltip':
|
||||
'Zastępuje liczbę kredytów tekstem FREE PLAY',
|
||||
'standard-custom-free-play-length': 'Długość tekstu FREE PLAY',
|
||||
'standard-custom-free-play-length-tooltip':
|
||||
'Zmienia długość tekstu wyświetlanego, gdy włączony jest wymuszony tekst kredytu FREE PLAY',
|
||||
'standard-custom-free-play-text': 'Customowy tekst FREE PLAY',
|
||||
'standard-custom-free-play-text-tooltip': 'Zastąp tekst FREE PLAY',
|
||||
'standard-localhost':
|
||||
'Zezwól na serwer pod adresem 127.0.0.1/localhost',
|
||||
'standard-credit-freeze': 'Zamroź kredyty',
|
||||
'standard-credit-freeze-tooltip':
|
||||
'Zapobiega używaniu kredytów. Co najmniej jeden kredyt musi być dostępny, aby rozpocząć grę lub zakupić bilety premium.',
|
||||
'standard-openssl-fix': 'Napraw błąd OpenSSL SHA',
|
||||
'standard-openssl-fix-tooltip':
|
||||
'Naprawia crash na procesorach Intel 10. generacji i nowszych',
|
||||
},
|
||||
cfg: {
|
||||
afterRestart: 'Wymaga restartu.',
|
||||
hardware: 'Prawdziwy czytnik',
|
||||
segatools: {
|
||||
general: 'Ogólne',
|
||||
builtIn: 'Wbudowany emulator',
|
||||
targetTooltip:
|
||||
'STARTLINER oczekuje czystych danych, pomijając odpakowane exe.',
|
||||
hooks: 'Hooki',
|
||||
ioModules: 'Moduły IO',
|
||||
ioModulesDesc:
|
||||
'Powinien odpowiadać twojej preferowanej metodzie wejścia.',
|
||||
ioBuiltIn: 'Wbudowany emulator (klawiatura)',
|
||||
io4: 'Natywne IO4',
|
||||
installTooltip: '{thing} można pobrać z pobierajki pakietów.',
|
||||
},
|
||||
display: {
|
||||
title: 'Ekran',
|
||||
resolution: 'Rozdzielczość',
|
||||
primary: 'Główny',
|
||||
target: 'Docelowy wyświetlacz',
|
||||
mode: 'Tryb',
|
||||
rotation: 'Obrót',
|
||||
refreshRate: 'Częstotliwość odświeżania',
|
||||
borderlessFullscreen: 'Bezramkowy tryb pełnoekranowy',
|
||||
borderlessFullscreenTooltip:
|
||||
'Dopasuj rozdzielczość wyświetlacza do gry.',
|
||||
dontSwitchPrimary: 'Pomiń przełączanie głównego wyświetlacza',
|
||||
dontSwitchPrimaryTooltip:
|
||||
'Włącz tę opcję tylko wtedy, gdy przełączanie głównego wyświetlacza powoduje problemy. Monitory muszą mieć dopasowaną częstotliwość odświeżania.',
|
||||
index: 'Indeks wyświetlacza',
|
||||
portrait: 'Pion',
|
||||
landscape: 'Poziom',
|
||||
flipped: 'Odwrócony',
|
||||
window: 'Okno',
|
||||
borderless: 'Okno bez ramki',
|
||||
fullscreen: 'Pełny ekran',
|
||||
},
|
||||
network: {
|
||||
title: 'Sieć',
|
||||
type: 'Typ sieci',
|
||||
remote: 'Zdalny',
|
||||
localArtemis: 'Lokalny (ARTEMiS)',
|
||||
artemisPath: 'Lokalizacja ARTEMiSa',
|
||||
address: 'Adres serwera',
|
||||
keychip: 'Keychip',
|
||||
subnet: 'Podsieć',
|
||||
addrSuffix: 'Sufiks adresu',
|
||||
},
|
||||
aime: {
|
||||
type: 'Typ Aime',
|
||||
modules: 'Moduły Aime',
|
||||
code: 'Kod Aime',
|
||||
codeTooltip:
|
||||
'Dotyczy tylko wbudowanej emulacji lub zgodnych pakietów',
|
||||
aimedb: 'Użyj AiMeDB dla kart fizycznych',
|
||||
aimedbTooltip:
|
||||
'Decyduje czy karty fizyczne powinny używać AiMeDB do pobierania kodów dostępu. Jeśli łączysz się z hostowaną siecią, włącz tę opcję, aby załadować te same dane konta, jakie uzyskałxbyś na fizycznym cabie.',
|
||||
serialPort: 'Port szeregowy Aime',
|
||||
serialPortTooltip: `Porty można sprawdzić w Urządzeniach i drukarkach lub na googlechromelabs.github.io/serial-terminal
|
||||
Dla AIC Pico powinien być wybrany port AIME.`,
|
||||
serverName: 'Nazwa serwera',
|
||||
},
|
||||
misc: {
|
||||
title: 'Różne',
|
||||
intel: 'Obejście buga OpenSSL dla procesorów Intel ≥10 generacji',
|
||||
intelTooltip: 'Zaleca się zamiast tego załatać amdaemon.',
|
||||
other: 'Inne opcje segatools',
|
||||
otherTooltip:
|
||||
'Zaawansowane lub sytuacyjne opcje, które nie są objęte przez STARTLINERA',
|
||||
prescript: 'Skrypt startowy',
|
||||
prescriptTooltip: 'Opcjonalny skrypt uruchamiany przed grą.',
|
||||
postscript: 'Skrypt końcowy',
|
||||
postscriptTooltip:
|
||||
'Opcjonalny skrypt uruchamiany po zakończeniu gry.',
|
||||
},
|
||||
extensions: {
|
||||
title: 'Rozszerzenia',
|
||||
bepInExConsole: 'Konsola BepInExa',
|
||||
audioMode: 'Tryb audio',
|
||||
audioTooltip:
|
||||
'Tryb ekskluzywny 2-kanałowy wymaga 7EVENDAYSHOLIDAYS-ExclusiveAudio',
|
||||
audioShared: 'Współdzielony',
|
||||
audio6Ch: 'Ekskluzywny 6-kanałowy',
|
||||
audio2Ch: 'Ekskluzywny 2-kanałowy',
|
||||
sampleRate: 'Częstotliwość',
|
||||
blacklist: 'Czarna lista utworów',
|
||||
blacklistTooltip:
|
||||
'Utwory w tym zakresie ID nie będą zapisywane ani przesyłane',
|
||||
bonusTracks: 'Odblokuj Bonusowe Utwory',
|
||||
bonusTracksTooltip:
|
||||
'Wyłączenie tej opcji może pomóc w uporządkowaniu listy utworów',
|
||||
saekawa: 'Plik konfiguracyjny Saekawy',
|
||||
inohara: 'Plik konfiguracyjny Inohary',
|
||||
},
|
||||
keyboard: {
|
||||
title: 'Klawiatura',
|
||||
tooltip:
|
||||
'Dotyczy tylko wtedy, gdy moduł IO jest ustawiony na wbudowaną emulację lub zgodny moduł (np. mu3io.NET)',
|
||||
leverMode: 'Tryb wajchy',
|
||||
mouse: 'Mysz',
|
||||
irTooltip:
|
||||
'Jeśli grasz na klawiaturze, ustaw tylko ir1; pozostałe zostaw wyłączone',
|
||||
},
|
||||
wine: {
|
||||
prefix: 'Wine prefix',
|
||||
runtime: 'Lokalizacja Wine',
|
||||
},
|
||||
startliner: {
|
||||
offlineMode: 'Tryb offline',
|
||||
offlineModeTooltip: 'Wyłącza pobierajkę pakietów.',
|
||||
autoUpdate: 'Automatyczne aktualizacje',
|
||||
verbose: 'Szczegółowe logi',
|
||||
},
|
||||
},
|
||||
onboarding: {
|
||||
or: 'lub',
|
||||
backButton: 'przycisku z tyłu',
|
||||
standard: `
|
||||
Możesz utknąć na następującym ekranie:
|
||||
|
||||
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||
|
||||
Wówczas musisz przejść do menu testowego i w ustawieniach gry {black}ゲーム設定{end} przełączyć z "podążaj za standardem" {black}基準機に従う{end} na "standard" {black}基準機{end}.
|
||||
|
||||
Do menu testowego możesz dostać się za pomocą %TESTMENU%.
|
||||
`,
|
||||
|
||||
'ongeki-system-processing': `
|
||||
Możesz utknąć na tym ekranie przez kilka(naście) minut. _To jest normalne_. Gra po prostu potrzebuje dużo czasu na załadowanie danych.
|
||||
|
||||
Jeśli zainstalujesz <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, kolejne uruchomienia będą znacznie szybsze.
|
||||
`,
|
||||
|
||||
'ongeki-lever': `
|
||||
Musisz również skalibrować wajchę; w przeciwnym razie możesz otrzymać błąd 3301.
|
||||
|
||||
Przejdź do ustawień wajchy ({black}レバー設定{end}), przesuń wajchę do obu krawędzi, a następnie naciśnij "koniec" ({black}終了{end}) i "zapisz" ({black}保存する{end}).
|
||||
`,
|
||||
|
||||
'chunithm-server': `
|
||||
Jeśli utkniesz na tym ekranie, zrestartuj grę.
|
||||
|
||||
Jeśli problem będzie się powtarzał, {link}sprawdź swoją konfigurację sieciową{endlink}.
|
||||
`,
|
||||
|
||||
finale: `
|
||||
Możesz uzyskać dostęp do tej strony w każdej chwili, klikając prawym przyciskiem myszy przycisk START.
|
||||
|
||||
Dodatkowe zasoby:
|
||||
|
||||
- {segaguide}SEGAguide{endlink}
|
||||
- {twotorial}two-torial{endlink}
|
||||
|
||||
## Miłej zabawy
|
||||
`,
|
||||
},
|
||||
};
|
256
src/i18n/zh-Hans.ts
Normal file
256
src/i18n/zh-Hans.ts
Normal file
@ -0,0 +1,256 @@
|
||||
export default {
|
||||
ok: '确定',
|
||||
cancel: '取消',
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
default: '默认',
|
||||
search: '搜索',
|
||||
next: '下一个',
|
||||
skip: '跳过',
|
||||
close: '关闭',
|
||||
by: '来自 {namespace}',
|
||||
updateAll: '更新全部',
|
||||
start: {
|
||||
failed: '启动检查失败',
|
||||
accept: '仍要运行',
|
||||
error: {
|
||||
package: 'Package缺失',
|
||||
dependency: '依赖缺失',
|
||||
tool: 'Tools缺失',
|
||||
unknown: '未知错误',
|
||||
},
|
||||
tooltip: {
|
||||
game: '需要指定游戏路径',
|
||||
amfs: '需要指定amfs路径',
|
||||
segatools: '需要segatools hook package',
|
||||
},
|
||||
button: {
|
||||
start: '启动',
|
||||
stop: '停止',
|
||||
unchecked: '跳过检查并启动',
|
||||
shortcut: '创建桌面快捷方式',
|
||||
help: '帮助',
|
||||
refresh: '重新应用MOD并启动',
|
||||
cache: '清空MOD缓存',
|
||||
},
|
||||
},
|
||||
game: {
|
||||
ongeki: '音击',
|
||||
chunithm: '中二节奏',
|
||||
},
|
||||
profile: {
|
||||
welcome: '欢迎来到STARTLINER! 创建一个配置文件以开始.',
|
||||
create: '{game} 配置文件',
|
||||
delete: '删除配置文件',
|
||||
reallyDelete: '确定删除 {profile}?',
|
||||
template: 'STARTLINER 模板',
|
||||
importTemplate: '导入模板',
|
||||
exportTemplate: '导出配置文件',
|
||||
export: '导出',
|
||||
standardExport: '模板',
|
||||
diagnostic: '诊断',
|
||||
},
|
||||
creator: {
|
||||
header: 'Package作者',
|
||||
basic: '基本信息',
|
||||
name: '名称',
|
||||
description: '介绍',
|
||||
website: '网站',
|
||||
type: 'Package类型',
|
||||
rainy: '标准',
|
||||
segatools: 'Segatools',
|
||||
native: '原生',
|
||||
games: '游戏',
|
||||
packageFormat: 'Package格式规范',
|
||||
},
|
||||
store: {
|
||||
installRecommended: '安装推荐的Packages',
|
||||
installed: '显示已安装',
|
||||
deprecated: '显示已弃用',
|
||||
nsfw: '显示NSFW',
|
||||
incompatible: 'STARTLINER暂不支持此Package.',
|
||||
|
||||
includeCategories: '包含类别',
|
||||
excludeCategories: '排除类别',
|
||||
},
|
||||
pkglist: {
|
||||
missing: '缺失',
|
||||
local: '本地Packages',
|
||||
namespace: '按名称',
|
||||
type: '按类型',
|
||||
category: '按类别',
|
||||
standard: '标准MOD',
|
||||
native: '原生MOD',
|
||||
segatools: 'Segatools',
|
||||
unsupported: '不支持',
|
||||
exclusions: '排除项:',
|
||||
},
|
||||
patch: {
|
||||
loading: '加载中...',
|
||||
noneFound:
|
||||
"未找到兼容的Patch. 请确认你使用的是已解密且未经修补的文件.",
|
||||
forceLoad: '强制加载',
|
||||
// Example patch name override
|
||||
// 'standard-no-encryption': 'No encryption',
|
||||
// 'standard-no-encryption-tooltip': 'Will also disable TLS',
|
||||
// It is also possible to add a tooltip where there normally is none
|
||||
// 'standard-maximum-tracks-tooltip': 'The number of tracks per credit',
|
||||
// For more info check https://gitea.tendokyu.moe/akanyan/STARTLINER/wiki/Translation-%26-Localization
|
||||
},
|
||||
cfg: {
|
||||
afterRestart: '将在重新启动后应用',
|
||||
hardware: '硬件',
|
||||
segatools: {
|
||||
general: '通用',
|
||||
builtIn: 'Segatools内置模拟',
|
||||
targetTooltip:
|
||||
'STARTLINER希望将已解密的可执行文件放入其他干净的数据中.',
|
||||
hooks: 'Hook',
|
||||
ioModules: 'IO模块',
|
||||
ioModulesDesc: '此处应符合您希望使用的输入方式.',
|
||||
ioBuiltIn: 'Segatools内置(键盘)',
|
||||
io4: '原生IO4',
|
||||
installTooltip: '{thing} 可从Package Store下载.',
|
||||
},
|
||||
display: {
|
||||
title: '显示',
|
||||
resolution: '游戏分辨率',
|
||||
primary: '主显示器',
|
||||
target: '目标显示器',
|
||||
mode: '模式',
|
||||
rotation: '旋转',
|
||||
refreshRate: '刷新率',
|
||||
borderlessFullscreen: '无边框全屏',
|
||||
borderlessFullscreenTooltip:
|
||||
'将显示器的分辨率调整为游戏分辨率.',
|
||||
dontSwitchPrimary: '跳过主显示器切换',
|
||||
dontSwitchPrimaryTooltip:
|
||||
'仅在更换到主显示器遇到问题时启用此选项,显示器必须具有匹配的刷新率.',
|
||||
index: '显示器索引',
|
||||
portrait: '纵向',
|
||||
landscape: '横向',
|
||||
flipped: '翻转',
|
||||
window: '窗口化',
|
||||
borderless: '无边框窗口化',
|
||||
fullscreen: '全屏',
|
||||
},
|
||||
network: {
|
||||
title: '网络',
|
||||
type: '服务器类型',
|
||||
remote: '在线',
|
||||
localArtemis: '本地 (ARTEMiS)',
|
||||
artemisPath: 'ARTEMiS路径',
|
||||
address: '服务器地址',
|
||||
keychip: '加密狗号 (Keychip)',
|
||||
subnet: '子网 (Subnet)',
|
||||
addrSuffix: '地址后缀 (Address suffix)',
|
||||
},
|
||||
aime: {
|
||||
type: 'Aime读卡器类型',
|
||||
modules: 'AimeIO',
|
||||
code: 'Aime卡号',
|
||||
codeTooltip:
|
||||
'仅适用于Segatools内置模拟或第三方AimeIO',
|
||||
aimedb: '对实体卡使用AiMeDB',
|
||||
aimedbTooltip:
|
||||
'实体卡需要使用AiMeDB来解析真实卡号,如果您想要获取卡片背面印刷的真实卡号,请启用此选项.',
|
||||
serialPort: '读卡器端口',
|
||||
serialPortTooltip: `端口号可在 设备和打印机 或 设备管理器 中查看
|
||||
对于AIC Pico,应选择AIME Port.`,
|
||||
serverName: '服务器名称',
|
||||
},
|
||||
misc: {
|
||||
title: '杂项',
|
||||
intel: '修复Intel 10代及以上CPU存在的OpenSSL问题',
|
||||
intelTooltip: '推荐使用该选项来代替给amdaemon打补丁.',
|
||||
other: '其他segatools选项',
|
||||
otherTooltip:
|
||||
'未被STARTLINER覆盖的高级选项',
|
||||
prescript: '启动脚本',
|
||||
prescriptTooltip: '在游戏启动前运行的脚本.',
|
||||
postscript: '结束脚本',
|
||||
postscriptTooltip:
|
||||
'在游戏进程结束后运行的脚本.',
|
||||
},
|
||||
extensions: {
|
||||
title: '扩展',
|
||||
bepInExConsole: 'BepInEx控制台',
|
||||
audioMode: '音频模式',
|
||||
audioTooltip:
|
||||
'独占双声道音频需要MOD: 7EVENDAYSHOLIDAYS-ExclusiveAudio',
|
||||
audioShared: '共享',
|
||||
audio6Ch: '独占六声道',
|
||||
audio2Ch: '独占双声道',
|
||||
sampleRate: '采样率',
|
||||
blacklist: '歌曲ID黑名单',
|
||||
blacklistTooltip:
|
||||
'黑名单中的歌曲分数不会被保存和上传',
|
||||
bonusTracks: '解锁Bonus Track',
|
||||
bonusTracksTooltip:
|
||||
'禁用此选项可帮助你整理歌曲列表',
|
||||
saekawa: 'Saekawa配置文件',
|
||||
inohara: 'Inohara配置文件',
|
||||
},
|
||||
keyboard: {
|
||||
title: '键盘',
|
||||
tooltip:
|
||||
'仅适用于Segatools内置(键盘)或兼容的第三方IO(如mu3io.NET)',
|
||||
leverMode: '摇杆模式',
|
||||
mouse: '鼠标',
|
||||
irTooltip:
|
||||
'当使用键盘游玩时,请只绑定ir1;其余的请设置为未绑定',
|
||||
},
|
||||
wine: {
|
||||
prefix: 'Wine前缀',
|
||||
runtime: 'Wine运行时',
|
||||
},
|
||||
startliner: {
|
||||
offlineMode: '离线模式',
|
||||
offlineModeTooltip: '禁用Package Store.',
|
||||
autoUpdate: '自动更新',
|
||||
verbose: '详细日志',
|
||||
},
|
||||
},
|
||||
onboarding: {
|
||||
or: '或',
|
||||
backButton: '控制器背后的按钮',
|
||||
standard: `
|
||||
你可能会卡在这个界面:
|
||||
|
||||
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||
|
||||
在这种情况下, 你需要跳转到测试模式(Test), 在游戏设定中 {black}ゲーム設定{end} 将 "从机" {black}基準機に従う{end} 切换到 "基准机" {black}基準機{end}.
|
||||
|
||||
测试模式可通过 %TESTMENU% 进入.
|
||||
`,
|
||||
|
||||
'ongeki-system-processing': `
|
||||
你可能会在这个界面上停留一段时间. _这是正常的_. 这个游戏加载数据需要很长时间.
|
||||
|
||||
如果你安装了 <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, 后续启动会变得更快.
|
||||
`,
|
||||
|
||||
'ongeki-lever': `
|
||||
你需要校准你的摇杆, 不然你会看到错误3301.
|
||||
|
||||
前往摇杆设定 ({black}レバー設定{end}), 将摇杆移动至两边, 然后按下"结束" ({black}終了{end}) 和 "保存" ({black}保存する{end}).
|
||||
`,
|
||||
|
||||
'chunithm-server': `
|
||||
如果你卡在这个界面, 请重启游戏.
|
||||
|
||||
如果问题依旧存在, {link}请检查你的网络配置{endlink}
|
||||
`,
|
||||
|
||||
finale: `
|
||||
您随时都可以通过右键点击START按钮重新回到这个页面.
|
||||
|
||||
附录:
|
||||
|
||||
- {segaguide}SEGAguide{endlink}
|
||||
- {twotorial}two-torial{endlink}
|
||||
|
||||
## 玩得愉快
|
||||
`,
|
||||
},
|
||||
};
|
@ -6,14 +6,15 @@ import PrimeVue from 'primevue/config';
|
||||
import ConfirmationService from 'primevue/confirmationservice';
|
||||
import Tooltip from 'primevue/tooltip';
|
||||
import App from './components/App.vue';
|
||||
import { i18n } from './i18n';
|
||||
import { changePrimaryColor } from './util';
|
||||
|
||||
const pinia = createPinia();
|
||||
const app = createApp(App);
|
||||
|
||||
const Preset = definePreset(Theme, {});
|
||||
|
||||
app.use(pinia);
|
||||
app.use(i18n);
|
||||
app.use(PrimeVue, {
|
||||
theme: {
|
||||
preset: Preset,
|
||||
|
@ -4,6 +4,7 @@ import { listen } from '@tauri-apps/api/event';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import { PhysicalSize, getCurrentWindow } from '@tauri-apps/api/window';
|
||||
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
|
||||
import { Locale, setLocale as actualSetLocale } from './i18n';
|
||||
import { invoke, invoke_nopopup } from './invoke';
|
||||
import { Dirs, Feature, Game, Package, Profile, ProfileMeta } from './types';
|
||||
import {
|
||||
@ -31,23 +32,24 @@ export const useGeneralStore = defineStore('general', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const configDir = computed(() => {
|
||||
const loadDirs = async () => {
|
||||
if (dirs.value === null) {
|
||||
throw new Error('Invalid directory access');
|
||||
const d = (await invoke('list_directories')) as Dirs;
|
||||
dirs.value = d;
|
||||
}
|
||||
return dirs.value.config_dir;
|
||||
};
|
||||
|
||||
const configDir = computed(async () => {
|
||||
await loadDirs();
|
||||
return dirs.value!.config_dir;
|
||||
});
|
||||
const dataDir = computed(() => {
|
||||
if (dirs.value === null) {
|
||||
throw new Error('Invalid directory access');
|
||||
}
|
||||
return dirs.value.data_dir;
|
||||
const dataDir = computed(async () => {
|
||||
await loadDirs();
|
||||
return dirs.value!.data_dir;
|
||||
});
|
||||
const cacheDir = computed(() => {
|
||||
if (dirs.value === null) {
|
||||
throw new Error('Invalid directory access');
|
||||
}
|
||||
return dirs.value.cache_dir;
|
||||
const cacheDir = computed(async () => {
|
||||
await loadDirs();
|
||||
return dirs.value!.cache_dir;
|
||||
});
|
||||
|
||||
return {
|
||||
@ -187,7 +189,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
await this.reloadAll();
|
||||
},
|
||||
|
||||
async install(pkg: Package | undefined) {
|
||||
async install(pkg: Package | undefined, enable: boolean) {
|
||||
if (pkg === undefined) {
|
||||
return;
|
||||
}
|
||||
@ -196,6 +198,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
await invoke('install_package', {
|
||||
key: pkgKey(pkg),
|
||||
force: true,
|
||||
enable,
|
||||
});
|
||||
} catch (err) {
|
||||
if (pkg !== undefined) {
|
||||
@ -209,6 +212,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
await invoke('install_package', {
|
||||
key,
|
||||
force: true,
|
||||
enable: false,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -219,7 +223,7 @@ export const usePkgStore = defineStore('pkg', {
|
||||
const list = [];
|
||||
for (const pkg of this.allLocal) {
|
||||
if (pkg.rmt && pkg.rmt.version > pkg.loc!.version) {
|
||||
list.push(this.install(pkg));
|
||||
list.push(this.install(pkg, false));
|
||||
}
|
||||
}
|
||||
await Promise.all(list);
|
||||
@ -320,9 +324,10 @@ export const usePrfStore = defineStore('prf', () => {
|
||||
const generalStore = useGeneralStore();
|
||||
|
||||
const configDir = computed(async () => {
|
||||
return await path.join(
|
||||
generalStore.configDir,
|
||||
`profile-${current.value?.meta.game}-${current.value?.meta.name}`
|
||||
const title = `profile-${current.value?.meta.game}-${current.value?.meta.name}`;
|
||||
return path.join(
|
||||
await generalStore.configDir,
|
||||
title
|
||||
);
|
||||
});
|
||||
|
||||
@ -371,6 +376,11 @@ export const useClientStore = defineStore('client', () => {
|
||||
const verbose = ref(false);
|
||||
const theme: Ref<'light' | 'dark' | 'system'> = ref('system');
|
||||
const onboarded: Ref<Game[]> = ref([]);
|
||||
const locale: Ref<Locale> = ref('en');
|
||||
const currentTab: Ref<string> = ref('users');
|
||||
const pkgListMode: Ref<'namespace' | 'type' | 'category'> =
|
||||
ref('namespace');
|
||||
const hiddenCategories: Ref<string[]> = ref([]);
|
||||
|
||||
const _scaleValue = (value: ScaleType) =>
|
||||
value === 's' ? 1 : value === 'm' ? 1.25 : value === 'l' ? 1.5 : 2;
|
||||
@ -410,7 +420,7 @@ export const useClientStore = defineStore('client', () => {
|
||||
const input = JSON.parse(
|
||||
await readTextFile(
|
||||
await path.join(
|
||||
generalStore.configDir,
|
||||
await generalStore.configDir,
|
||||
'client-options.json'
|
||||
)
|
||||
)
|
||||
@ -433,6 +443,23 @@ export const useClientStore = defineStore('client', () => {
|
||||
if (input.onboarded) {
|
||||
onboarded.value = input.onboarded;
|
||||
}
|
||||
|
||||
if (input.locale) {
|
||||
locale.value = input.locale;
|
||||
}
|
||||
|
||||
if (input.currentTab) {
|
||||
currentTab.value = input.currentTab;
|
||||
}
|
||||
|
||||
if (input.pkgListMode) {
|
||||
pkgListMode.value = input.pkgListMode;
|
||||
}
|
||||
|
||||
if (input.hiddenCategories) {
|
||||
hiddenCategories.value = input.hiddenCategories;
|
||||
}
|
||||
await setLocale(locale.value);
|
||||
await setTheme(theme.value);
|
||||
} catch (e) {
|
||||
console.error(`Error reading client options: ${e}`);
|
||||
@ -457,7 +484,10 @@ export const useClientStore = defineStore('client', () => {
|
||||
const size = await w.innerSize();
|
||||
|
||||
await writeTextFile(
|
||||
await path.join(generalStore.configDir, 'client-options.json'),
|
||||
await path.join(
|
||||
await generalStore.configDir,
|
||||
'client-options.json'
|
||||
),
|
||||
JSON.stringify({
|
||||
scaleFactor: scaleFactor.value,
|
||||
windowSize: {
|
||||
@ -466,6 +496,10 @@ export const useClientStore = defineStore('client', () => {
|
||||
},
|
||||
theme: theme.value,
|
||||
onboarded: onboarded.value,
|
||||
locale: locale.value,
|
||||
currentTab: currentTab.value,
|
||||
pkgListMode: pkgListMode.value,
|
||||
hiddenCategories: hiddenCategories.value,
|
||||
})
|
||||
);
|
||||
};
|
||||
@ -518,6 +552,12 @@ export const useClientStore = defineStore('client', () => {
|
||||
await save();
|
||||
};
|
||||
|
||||
const setLocale = async (loc: Locale) => {
|
||||
locale.value = loc;
|
||||
await save();
|
||||
await actualSetLocale(loc);
|
||||
};
|
||||
|
||||
getCurrentWindow().onResized(async ({ payload }) => {
|
||||
// For whatever reason this is 0 when minimized
|
||||
if (payload.width > 0) {
|
||||
@ -532,8 +572,12 @@ export const useClientStore = defineStore('client', () => {
|
||||
verbose,
|
||||
theme,
|
||||
onboarded,
|
||||
locale,
|
||||
timeout,
|
||||
scaleModel,
|
||||
currentTab,
|
||||
pkgListMode,
|
||||
hiddenCategories,
|
||||
_scaleValue,
|
||||
scaleValue,
|
||||
load,
|
||||
@ -544,5 +588,6 @@ export const useClientStore = defineStore('client', () => {
|
||||
setVerbose,
|
||||
setTheme,
|
||||
setOnboarded,
|
||||
setLocale,
|
||||
};
|
||||
});
|
||||
|
@ -56,6 +56,7 @@ export interface ProfileData {
|
||||
display: DisplayConfig;
|
||||
network: NetworkConfig;
|
||||
bepinex: BepInExConfig;
|
||||
wine: WineConfig;
|
||||
mu3_ini: Mu3IniConfig | undefined;
|
||||
keyboard: KeyboardConfig | undefined;
|
||||
patches: {
|
||||
@ -105,6 +106,11 @@ export interface BepInExConfig {
|
||||
console: boolean;
|
||||
}
|
||||
|
||||
export interface WineConfig {
|
||||
runtime: string;
|
||||
prefix: string;
|
||||
}
|
||||
|
||||
export interface Mu3IniConfig {
|
||||
audio?: 'Shared' | 'Excl6Ch' | 'Excl2Ch';
|
||||
sample_rate: number;
|
||||
@ -167,7 +173,7 @@ export interface Patch {
|
||||
id: string;
|
||||
name: string;
|
||||
tooltip: string;
|
||||
type: undefined | 'number';
|
||||
type: undefined | 'number' | 'hex';
|
||||
default: number;
|
||||
min: number;
|
||||
max: number;
|
||||
|
Reference in New Issue
Block a user