mirror of
https://github.com/modrinth/code.git
synced 2026-08-28 18:45:15 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9de420d57 | ||
|
|
ab7359a4c5 | ||
|
|
97b5138672 | ||
|
|
579109a478 | ||
|
|
5f7493491f | ||
|
|
755825b09a | ||
|
|
06b7c44dcc | ||
|
|
e087e571f3 | ||
|
|
fbdde8f3d8 | ||
|
|
290bd2b934 | ||
|
|
9ecbe8eaa6 | ||
|
|
549b333eb2 | ||
|
|
4b82cca3bf | ||
|
|
734fd9cdb3 | ||
|
|
2fd4495104 | ||
|
|
552bc3f739 | ||
|
|
4758cabbf9 | ||
|
|
6ec979a076 | ||
|
|
c34bd26f87 | ||
|
|
2a43792fd9 | ||
|
|
2d567b93ce | ||
|
|
26e05ee9e5 | ||
|
|
ca8c5a717f | ||
|
|
759f67a551 | ||
|
|
66628fd69d |
@@ -59,6 +59,14 @@ apps/frontend/src/generated
|
||||
.turbo
|
||||
target
|
||||
generated
|
||||
!apps/app-frontend/src/generated/
|
||||
!apps/app-frontend/src/generated/app-events/
|
||||
!apps/app-frontend/src/generated/app-events/*.ts
|
||||
!apps/app-frontend/src/generated/app-events/README.md
|
||||
!apps/app-frontend/src/generated/app-events/postcard/
|
||||
!apps/app-frontend/src/generated/app-events/postcard/index.d.ts
|
||||
!apps/app-frontend/src/generated/app-events/postcard/index.js
|
||||
!apps/app-frontend/src/generated/app-events/postcard/package.json
|
||||
.env
|
||||
|
||||
# app testing dir
|
||||
|
||||
Generated
+11
@@ -17,6 +17,17 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-maxmind/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-util/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/muralpay/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/async-minecraft-ping/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/async-minecraft-ping/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/async-minecraft-ping/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/labrinth-derive/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-content-management/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-content-management/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/neverbounce/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/serde-binhum/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/sqlx-tracing/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/sqlx-tracing/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/xredis/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
||||
Generated
+190
-2
@@ -2116,7 +2116,7 @@ checksum = "ff6669899e23cb87b43daf7996f0ea3b9c07d0fb933d745bb7b815b052515ae3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"serde_derive_internals 0.29.1",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
@@ -2340,6 +2340,15 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.16.2"
|
||||
@@ -3991,6 +4000,28 @@ dependencies = [
|
||||
"x11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "genco"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ab846431e5d637791b3279e7242fe2b21e11c3d8b4cf6a99f645c5f16ba7c0"
|
||||
dependencies = [
|
||||
"genco-macros",
|
||||
"relative-path",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "genco-macros"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42a1fe5a699c7f1d36ea6e04ed680a5c787cabff4b610ae3b8954ea3bcefec1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.9"
|
||||
@@ -5347,6 +5378,16 @@ dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json5"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "733a844dbd6fef128e98cb4487b887cb55454d92cd9994b1bafe004fabbe670c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonptr"
|
||||
version = "0.6.3"
|
||||
@@ -7499,6 +7540,45 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postcard-bindgen"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e709af61573ae2563a00e760ff7db47f5c70b9d96c6dcb28993526fb8479f68"
|
||||
dependencies = [
|
||||
"postcard-bindgen-core",
|
||||
"postcard-bindgen-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postcard-bindgen-core"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f19cebcb145fdccb24b63ad410785aa7c2ff9364551646ca7a927422d2d0386"
|
||||
dependencies = [
|
||||
"convert_case 0.11.0",
|
||||
"genco",
|
||||
"tree-ds",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postcard-bindgen-derive"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0372f55dd7c15d73f7b0f7ca507ac3db5653f346b2b44a36537e2ad39f55441b"
|
||||
dependencies = [
|
||||
"convert_case 0.11.0",
|
||||
"genco",
|
||||
"postcard-bindgen-core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"regex-macro",
|
||||
"serde",
|
||||
"serde_derive_internals 0.30.0",
|
||||
"syn 3.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.3"
|
||||
@@ -8381,12 +8461,27 @@ version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da"
|
||||
|
||||
[[package]]
|
||||
name = "regex-macro"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d306632607af6ec61c0b117971d57a96381b6317cf18ae419b5558048fe016e"
|
||||
dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "relative-path"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
version = "0.4.2"
|
||||
@@ -9052,7 +9147,7 @@ checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"serde_derive_internals 0.29.1",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
@@ -9295,6 +9390,16 @@ dependencies = [
|
||||
"uuid 1.23.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sequential_gen"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d630b1418311e028ceb45e1e567845501a9d9c770a258b80d2edc025ffad17c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"uuid 1.23.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
@@ -9400,6 +9505,17 @@ dependencies = [
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_ini"
|
||||
version = "0.2.0"
|
||||
@@ -9840,6 +9956,9 @@ name = "spin"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
@@ -10267,6 +10386,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.2"
|
||||
@@ -10880,6 +11010,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testcontainers"
|
||||
version = "0.25.2"
|
||||
@@ -10959,6 +11098,7 @@ dependencies = [
|
||||
"image",
|
||||
"indicatif",
|
||||
"itertools 0.14.0",
|
||||
"json5",
|
||||
"modrinth-content-management",
|
||||
"notify",
|
||||
"notify-debouncer-mini",
|
||||
@@ -10968,6 +11108,8 @@ dependencies = [
|
||||
"path-util",
|
||||
"phf 0.13.1",
|
||||
"png 0.18.0",
|
||||
"postcard",
|
||||
"postcard-bindgen",
|
||||
"quartz_nbt",
|
||||
"quick-xml 0.38.3",
|
||||
"rand 0.8.5",
|
||||
@@ -10975,6 +11117,7 @@ dependencies = [
|
||||
"reqwest 0.12.24",
|
||||
"rgb",
|
||||
"serde",
|
||||
"serde-binhum",
|
||||
"serde_ini",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
@@ -10988,9 +11131,11 @@ dependencies = [
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"toml 0.9.8",
|
||||
"tracing",
|
||||
"tracing-error",
|
||||
"tracing-subscriber",
|
||||
"ts-rs",
|
||||
"url",
|
||||
"urlencoding",
|
||||
"uuid 1.23.3",
|
||||
@@ -11667,12 +11812,49 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-ds"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "710c388a2bb52d1a7186ae4aa2e92c6fae0606426bf4bdfb4106fa1e8e5c602e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"sequential_gen",
|
||||
"serde",
|
||||
"spin 0.10.0",
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "ts-rs"
|
||||
version = "12.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "756050066659291d47a554a9f558125db17428b073c5ffce1daf5dcb0f7231d8"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"thiserror 2.0.17",
|
||||
"ts-rs-macros",
|
||||
"uuid 1.23.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ts-rs-macros"
|
||||
version = "12.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d90eea51bc7988ef9e674bf80a85ba6804739e535e9cab48e4bb34a8b652aa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.27.0"
|
||||
@@ -11710,6 +11892,12 @@ version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.1.0"
|
||||
|
||||
@@ -113,6 +113,7 @@ indicatif = "0.18.0"
|
||||
itertools = "0.14.0"
|
||||
jemalloc_pprof = "0.8.1"
|
||||
json-patch = { version = "4.1.0", default-features = false }
|
||||
json5 = "1.3.1"
|
||||
lettre = { version = "0.11.19", default-features = false, features = [
|
||||
"aws-lc-rs",
|
||||
"builder",
|
||||
@@ -148,6 +149,7 @@ path-util = { path = "packages/path-util" }
|
||||
phf = { version = "0.13.1", features = ["macros"] }
|
||||
png = "0.18.0"
|
||||
postcard = { version = "1.1.3", default-features = false, features = ["alloc"] }
|
||||
postcard-bindgen = "0.8.0"
|
||||
proc-macro2 = { version = "1.0" }
|
||||
prometheus = "0.14.0"
|
||||
quartz_nbt = "0.2.9"
|
||||
@@ -224,12 +226,14 @@ tikv-jemallocator = "0.6.0"
|
||||
tokio = "1.47.1"
|
||||
tokio-stream = "0.1.17"
|
||||
tokio-util = "0.7.16"
|
||||
toml = "0.9.8"
|
||||
totp-rs = "5.7.0"
|
||||
tracing = "0.1.41"
|
||||
tracing-actix-web = { version = "0.7.19", default-features = false }
|
||||
tracing-ecs = "0.5.0"
|
||||
tracing-error = "0.2.1"
|
||||
tracing-subscriber = "0.3.20"
|
||||
ts-rs = "12.0.1"
|
||||
typed-path = "0.12.0"
|
||||
url = "2.5.7"
|
||||
urlencoding = "2.1.3"
|
||||
|
||||
@@ -24,3 +24,7 @@ gam = "gam"
|
||||
consts = "consts"
|
||||
# short for "Copy"
|
||||
Cpy = "Cpy"
|
||||
|
||||
[default.extend-identifiers]
|
||||
# Constant from the `zip` crate
|
||||
ZIP64_BYTES_THR = "ZIP64_BYTES_THR"
|
||||
|
||||
@@ -2,3 +2,7 @@
|
||||
*.gltf
|
||||
src/locales/
|
||||
src/assets/**/*.svg
|
||||
|
||||
# Generated app-event bindings
|
||||
src/generated/app-events/*.ts
|
||||
src/generated/app-events/postcard/**
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
import config from '@modrinth/tooling-config/eslint/nuxt.mjs'
|
||||
export default config
|
||||
|
||||
export default config.append([
|
||||
{
|
||||
ignores: ['src/generated/app-events/*.ts', 'src/generated/app-events/postcard/**'],
|
||||
},
|
||||
])
|
||||
|
||||
@@ -71,6 +71,7 @@ import AppActionBar from '@/components/ui/AppActionBar.vue'
|
||||
import Breadcrumbs from '@/components/ui/Breadcrumbs.vue'
|
||||
import ErrorModal from '@/components/ui/ErrorModal.vue'
|
||||
import FriendsList from '@/components/ui/friends/FriendsList.vue'
|
||||
import HostingUpdateRequired from '@/components/ui/HostingUpdateRequired.vue'
|
||||
import AddServerToInstanceModal from '@/components/ui/install_flow/AddServerToInstanceModal.vue'
|
||||
import UnknownPackWarningModal from '@/components/ui/install_flow/UnknownPackWarningModal.vue'
|
||||
import MinecraftAuthErrorModal from '@/components/ui/minecraft-auth-error-modal/MinecraftAuthErrorModal.vue'
|
||||
@@ -89,19 +90,19 @@ import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
import SurveyPopup from '@/components/ui/SurveyPopup.vue'
|
||||
import WindowControls from '@/components/ui/WindowControls.vue'
|
||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { config } from '@/config'
|
||||
import {
|
||||
ads_consent_listener,
|
||||
hide_ads_window,
|
||||
init_ads_window,
|
||||
perform_ads_consent_action,
|
||||
release_ads_window_hold,
|
||||
should_show_ads_consent_popup,
|
||||
show_ads_window,
|
||||
take_ads_window_hold,
|
||||
} from '@/helpers/ads.js'
|
||||
import { debugAnalytics, initAnalytics, trackEvent } from '@/helpers/analytics'
|
||||
import { check_reachable } from '@/helpers/auth.js'
|
||||
import { get_user, get_version } from '@/helpers/cache.js'
|
||||
import { command_listener, notification_listener, warning_listener } from '@/helpers/events.js'
|
||||
import { install_create_modpack_instance, install_get_modpack_preview } from '@/helpers/install'
|
||||
import { can_current_user_use_shared_instances, get as getInstance, run } from '@/helpers/instance'
|
||||
import { get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
|
||||
@@ -140,6 +141,7 @@ import {
|
||||
} from '@/providers/download-progress.ts'
|
||||
import { createServerInstall, provideServerInstall } from '@/providers/server-install'
|
||||
import { setupProviders } from '@/providers/setup'
|
||||
import { setupAppEventsProvider } from '@/providers/setup/app-events'
|
||||
import { setupAuthProvider } from '@/providers/setup/auth'
|
||||
import { setupLoadingStateProvider } from '@/providers/setup/loading-state'
|
||||
import { useError } from '@/store/error.js'
|
||||
@@ -155,6 +157,7 @@ import { appSettingsModalOpenProfileKey } from './providers/app-settings-modal'
|
||||
const themeStore = useTheming()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { channel: appEventChannel, events: appEvents } = setupAppEventsProvider()
|
||||
const breadcrumbManager = createBreadcrumbManager()
|
||||
provideBreadcrumbManager(breadcrumbManager)
|
||||
const canNavigateBack = ref(false)
|
||||
@@ -166,6 +169,25 @@ function updateHistoryNavigationState() {
|
||||
canNavigateForward.value = historyState?.forward != null
|
||||
}
|
||||
|
||||
let fullscreenAdsWindowHold = false
|
||||
|
||||
async function handleFullscreenChange() {
|
||||
const fullscreen = document.fullscreenElement !== null
|
||||
if (fullscreen === fullscreenAdsWindowHold) return
|
||||
|
||||
fullscreenAdsWindowHold = fullscreen
|
||||
try {
|
||||
if (fullscreen) {
|
||||
await take_ads_window_hold()
|
||||
} else {
|
||||
await release_ads_window_hold()
|
||||
}
|
||||
} catch (error) {
|
||||
fullscreenAdsWindowHold = !fullscreen
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
|
||||
updateHistoryNavigationState()
|
||||
|
||||
const APP_LEFT_NAV_WIDTH = '4rem'
|
||||
@@ -182,10 +204,19 @@ watch(
|
||||
},
|
||||
)
|
||||
const forceSidebar = computed(
|
||||
() => route.path.startsWith('/browse') || route.path.startsWith('/project'),
|
||||
() =>
|
||||
route.path.startsWith('/browse') ||
|
||||
route.path.startsWith('/project') ||
|
||||
route.path.startsWith('/user'),
|
||||
)
|
||||
const sidebarVisible = computed(() => sidebarToggled.value || forceSidebar.value)
|
||||
const hostingRouteActive = computed(() => route.path.startsWith('/hosting'))
|
||||
const hostingUpdateRequired = computed(
|
||||
() =>
|
||||
hostingRouteActive.value &&
|
||||
!!appUpdateState.availableUpdate.value &&
|
||||
appUpdateState.updatesEnabled.value,
|
||||
)
|
||||
const prideFundraiserEnabled = computed(
|
||||
() => themeStore.getFeatureFlag('pride_fundraiser') && Date.now() < PRIDE_FUNDRAISER_END_DATE,
|
||||
)
|
||||
@@ -196,7 +227,9 @@ const hostingIntercomIdentityKey = computed(() => {
|
||||
return `${userId}:${serverId ?? 'hosting'}`
|
||||
})
|
||||
const hostingIntercom = useHostingIntercom({
|
||||
enabled: computed(() => hostingRouteActive.value && !!credentials.value?.session),
|
||||
enabled: computed(
|
||||
() => hostingRouteActive.value && !hostingUpdateRequired.value && !!credentials.value?.session,
|
||||
),
|
||||
appId: 'ykeritl9',
|
||||
fetchToken: fetchIntercomToken,
|
||||
identityKey: hostingIntercomIdentityKey,
|
||||
@@ -211,11 +244,22 @@ const notificationManager = new AppNotificationManager()
|
||||
provideNotificationManager(notificationManager)
|
||||
const { handleError, addNotification } = notificationManager
|
||||
|
||||
useAppEvent(
|
||||
'warning',
|
||||
(event) =>
|
||||
addNotification({
|
||||
title: 'Warning',
|
||||
text: event.message,
|
||||
type: 'warning',
|
||||
}),
|
||||
appEvents,
|
||||
)
|
||||
|
||||
const popupNotificationManager = new AppPopupNotificationManager()
|
||||
providePopupNotificationManager(popupNotificationManager)
|
||||
const { addPopupNotification } = popupNotificationManager
|
||||
let adsConsentPopupId = null
|
||||
let unlistenAdsConsent
|
||||
useAppEvent('ads_consent_required', handleAdsConsentRequired, appEvents)
|
||||
|
||||
const appVersion = getVersion()
|
||||
const tauriApiClient = new TauriModrinthClient({
|
||||
@@ -284,8 +328,8 @@ providePageContext({
|
||||
})
|
||||
provideModalBehavior({
|
||||
noblur: computed(() => !themeStore.advancedRendering),
|
||||
onShow: () => hide_ads_window(),
|
||||
onHide: () => show_ads_window(),
|
||||
onShow: () => take_ads_window_hold(),
|
||||
onHide: () => release_ads_window_hold(),
|
||||
})
|
||||
|
||||
const {
|
||||
@@ -300,7 +344,7 @@ const {
|
||||
setModpackAlreadyInstalledModal,
|
||||
handleModpackDuplicateCreateAnyway,
|
||||
handleModpackDuplicateGoToInstance,
|
||||
} = setupProviders(notificationManager, popupNotificationManager)
|
||||
} = setupProviders(tauriApiClient, notificationManager, popupNotificationManager)
|
||||
|
||||
const news = ref([])
|
||||
const displayedServerInviteNotifications = new Set()
|
||||
@@ -352,7 +396,6 @@ const authUnreachable = computed(() => {
|
||||
onMounted(async () => {
|
||||
await useCheckDisableMouseover()
|
||||
try {
|
||||
unlistenAdsConsent = await ads_consent_listener(handleAdsConsentRequired)
|
||||
handleAdsConsentRequired(await should_show_ads_consent_popup())
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
@@ -360,6 +403,7 @@ onMounted(async () => {
|
||||
|
||||
document.querySelector('body').addEventListener('click', handleClick)
|
||||
document.querySelector('body').addEventListener('auxclick', handleAuxClick)
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange)
|
||||
|
||||
checkUpdates()
|
||||
})
|
||||
@@ -367,9 +411,13 @@ onMounted(async () => {
|
||||
onUnmounted(async () => {
|
||||
document.querySelector('body').removeEventListener('click', handleClick)
|
||||
document.querySelector('body').removeEventListener('auxclick', handleAuxClick)
|
||||
document.removeEventListener('fullscreenchange', handleFullscreenChange)
|
||||
clearDelayedUpdatePopup()
|
||||
|
||||
await unlistenAdsConsent?.()
|
||||
if (fullscreenAdsWindowHold) {
|
||||
fullscreenAdsWindowHold = false
|
||||
await release_ads_window_hold().catch(handleError)
|
||||
}
|
||||
await unlistenUpdateDownload?.()
|
||||
})
|
||||
|
||||
@@ -578,14 +626,6 @@ async function setupApp() {
|
||||
document.getElementsByTagName('html')[0].classList.add('windows')
|
||||
}
|
||||
|
||||
await warning_listener((e) =>
|
||||
addNotification({
|
||||
title: 'Warning',
|
||||
text: e.message,
|
||||
type: 'warning',
|
||||
}),
|
||||
)
|
||||
|
||||
fetch(`https://api.modrinth.com/appCriticalAnnouncement.json?version=${version}`)
|
||||
.then((response) => response.json())
|
||||
.then((res) => {
|
||||
@@ -634,7 +674,7 @@ async function setupApp() {
|
||||
}
|
||||
|
||||
const stateFailed = ref(false)
|
||||
initialize_state()
|
||||
initialize_state(appEventChannel)
|
||||
.then(() => {
|
||||
setupApp().catch((err) => {
|
||||
stateFailed.value = true
|
||||
@@ -764,7 +804,7 @@ const errorModal = ref()
|
||||
const minecraftAuthErrorModal = ref()
|
||||
const minecraftRequiredModal = ref()
|
||||
|
||||
const contentInstall = createContentInstall({ router, handleError })
|
||||
const contentInstall = createContentInstall({ router, handleError, appEvents })
|
||||
provideContentInstall(contentInstall)
|
||||
const {
|
||||
instances: contentInstallInstances,
|
||||
@@ -797,7 +837,12 @@ const {
|
||||
handleIncompatibilityWarningCancel: handleContentInstallIncompatibilityWarningCancel,
|
||||
} = contentInstall
|
||||
|
||||
const serverInstall = createServerInstall({ router, handleError, popupNotificationManager })
|
||||
const serverInstall = createServerInstall({
|
||||
router,
|
||||
handleError,
|
||||
popupNotificationManager,
|
||||
appEvents,
|
||||
})
|
||||
provideServerInstall(serverInstall)
|
||||
const {
|
||||
setInstallToPlayModal: setServerInstallToPlayModal,
|
||||
@@ -973,8 +1018,8 @@ onMounted(() => {
|
||||
const accounts = ref(null)
|
||||
provide('accountsCard', accounts)
|
||||
|
||||
command_listener(handleCommand)
|
||||
notification_listener(handleLiveNotification)
|
||||
useAppEvent('command', handleCommand, appEvents)
|
||||
useAppEvent('notification', handleLiveNotification, appEvents)
|
||||
|
||||
async function markLiveNotificationRead(notification) {
|
||||
try {
|
||||
@@ -1400,6 +1445,7 @@ async function downloadUpdate(versionToDownload) {
|
||||
handleError(e)
|
||||
})
|
||||
unlistenUpdateDownload = await subscribeToDownloadProgress(
|
||||
appEvents,
|
||||
appUpdateDownload,
|
||||
versionToDownload.version,
|
||||
)
|
||||
@@ -1758,7 +1804,8 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
>
|
||||
{{ formatMessage(messages.authUnreachableBody) }}
|
||||
</Admonition>
|
||||
<RouterView v-slot="{ Component }">
|
||||
<HostingUpdateRequired v-if="hostingUpdateRequired" />
|
||||
<RouterView v-else v-slot="{ Component }">
|
||||
<template v-if="Component">
|
||||
<Suspense @pending="onSuspensePending" @resolve="onSuspenseResolve">
|
||||
<component :is="Component"></component>
|
||||
|
||||
@@ -104,8 +104,9 @@ import {
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Ref } from 'vue'
|
||||
import { computed, onUnmounted, ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import {
|
||||
get_default_user,
|
||||
@@ -114,7 +115,6 @@ import {
|
||||
set_default_user,
|
||||
users,
|
||||
} from '@/helpers/auth'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { getPlayerHeadUrl } from '@/helpers/rendering/batch-skin-renderer.ts'
|
||||
import type { Skin } from '@/helpers/skins'
|
||||
import { get_available_skins } from '@/helpers/skins'
|
||||
@@ -251,16 +251,12 @@ async function logout(id: string) {
|
||||
trackEvent('AccountLogOut')
|
||||
}
|
||||
|
||||
const unlisten = await process_listener(async (e) => {
|
||||
useAppEvent('process', async (e) => {
|
||||
if (e.event === 'launched') {
|
||||
await refreshValues()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
unlisten()
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
notSignedIn: {
|
||||
id: 'minecraft-account.not-signed-in',
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<div class="flex gap-2 items-center">
|
||||
<IconButton
|
||||
v-if="hasActiveLoadingBars && !hasVisibleActiveDownloadToasts"
|
||||
v-tooltip="formatMessage(messages.viewActiveDownloads)"
|
||||
type="quiet"
|
||||
color="brand"
|
||||
:label="formatMessage(messages.viewActiveDownloads)"
|
||||
@click="openDownloadToast()"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</IconButton>
|
||||
<div v-if="downloadState.total > 0 || hasActiveLoadingBars" class="relative">
|
||||
<IconButton
|
||||
v-tooltip="downloadToggleLabel"
|
||||
:color="downloadState.hidden > 0 ? 'brand' : undefined"
|
||||
type="quiet"
|
||||
:label="downloadToggleLabel"
|
||||
@click="toggleDownloadNotifications"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
<div v-if="offline" class="flex items-center gap-1">
|
||||
<UnplugIcon class="text-secondary" />
|
||||
<span class="text-sm text-contrast"> {{ formatMessage(messages.offline) }} </span>
|
||||
@@ -147,8 +148,8 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
import AppUpdateButton from '@/components/ui/app-update-button/index.vue'
|
||||
import { useInstallJobNotifications } from '@/composables/browse/install-job-notifications'
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { loading_listener, process_listener } from '@/helpers/events'
|
||||
import { get_many as getInstances } from '@/helpers/instance'
|
||||
import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process'
|
||||
import type { LoadingBar } from '@/helpers/state'
|
||||
@@ -218,8 +219,35 @@ const messages = defineMessages({
|
||||
id: 'app.action-bar.view-active-downloads',
|
||||
defaultMessage: 'View active downloads',
|
||||
},
|
||||
hideDownloads: {
|
||||
id: 'app.action-bar.hide-downloads',
|
||||
defaultMessage: 'Hide active downloads',
|
||||
},
|
||||
showDownloads: {
|
||||
id: 'app.action-bar.show-downloads',
|
||||
defaultMessage: 'Show active downloads',
|
||||
},
|
||||
})
|
||||
|
||||
const downloadState = computed(() => popupNotificationManager.getDownloadState())
|
||||
const downloadToggleLabel = computed(() =>
|
||||
formatMessage(
|
||||
downloadState.value.hidden > 0
|
||||
? messages.showDownloads
|
||||
: downloadState.value.total > 0
|
||||
? messages.hideDownloads
|
||||
: messages.viewActiveDownloads,
|
||||
),
|
||||
)
|
||||
|
||||
function toggleDownloadNotifications(): void {
|
||||
if (downloadState.value.total > 0) {
|
||||
popupNotificationManager.toggleDownloadNotifications()
|
||||
} else if (hasActiveLoadingBars.value) {
|
||||
openDownloadToast()
|
||||
}
|
||||
}
|
||||
|
||||
const currentProcesses = ref<RunningProcess[]>([])
|
||||
const selectedProcess = ref<RunningProcess | undefined>()
|
||||
|
||||
@@ -266,7 +294,7 @@ onMounted(() => {
|
||||
window.addEventListener('online', handleOnline)
|
||||
})
|
||||
|
||||
const unlistenProcess = await process_listener(async () => {
|
||||
useAppEvent('process', async () => {
|
||||
await refresh()
|
||||
})
|
||||
|
||||
@@ -296,6 +324,7 @@ function goToTerminal(instanceId?: string) {
|
||||
const currentLoadingBars = ref<LoadingBar[]>([])
|
||||
const currentLoadingBarIconUrls = ref<Record<string, string | null>>({})
|
||||
const notificationId = ref<string | number | null>(null)
|
||||
const terminalNotificationIds = new Map<string, string | number>()
|
||||
const dismissed = ref(false)
|
||||
|
||||
function getLoadingBarKey(loadingBar: LoadingBar): string {
|
||||
@@ -341,6 +370,44 @@ function removeNotification(): void {
|
||||
notificationId.value = null
|
||||
}
|
||||
|
||||
function syncTerminalNotifications(): void {
|
||||
const terminalNotifications = installJobNotifications.terminalNotifications.value
|
||||
const currentJobIds = new Set(terminalNotifications.map((notification) => notification.id))
|
||||
|
||||
for (const terminal of terminalNotifications) {
|
||||
const popupId = terminalNotificationIds.get(terminal.id)
|
||||
let notification = popupId
|
||||
? popupNotificationManager.getNotifications().find((candidate) => candidate.id === popupId)
|
||||
: undefined
|
||||
|
||||
if (!notification) {
|
||||
notification = popupNotificationManager.addPopupNotification({
|
||||
title: terminal.title,
|
||||
text: terminal.text,
|
||||
type: terminal.type,
|
||||
buttons: terminal.buttons,
|
||||
onDismiss: terminal.onDismiss,
|
||||
autoCloseMs: null,
|
||||
})
|
||||
terminalNotificationIds.set(terminal.id, notification.id)
|
||||
continue
|
||||
}
|
||||
|
||||
notification.title = terminal.title
|
||||
notification.text = terminal.text
|
||||
notification.type = terminal.type
|
||||
notification.buttons = terminal.buttons
|
||||
notification.onDismiss = terminal.onDismiss
|
||||
}
|
||||
|
||||
for (const [jobId, popupId] of terminalNotificationIds) {
|
||||
if (!currentJobIds.has(jobId)) {
|
||||
popupNotificationManager.removeNotification(popupId)
|
||||
terminalNotificationIds.delete(jobId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildDownloadItems(): PopupNotificationProgressItem[] {
|
||||
return [
|
||||
...installJobNotifications.progressItems.value,
|
||||
@@ -358,12 +425,13 @@ function buildDownloadItems(): PopupNotificationProgressItem[] {
|
||||
]
|
||||
}
|
||||
|
||||
const hasVisibleActiveDownloadToasts = computed(() => !!getNotification())
|
||||
const hasActiveLoadingBars = computed(
|
||||
() => currentLoadingBars.value.length > 0 || installJobNotifications.active.value,
|
||||
)
|
||||
|
||||
function updateNotification(resummon = false): void {
|
||||
syncTerminalNotifications()
|
||||
|
||||
if (resummon) {
|
||||
dismissed.value = false
|
||||
}
|
||||
@@ -392,7 +460,6 @@ function updateNotification(resummon = false): void {
|
||||
: formatMessage(messages.downloads)
|
||||
notif.text = undefined
|
||||
notif.progressItems = progressItems
|
||||
notif.buttons = installJobNotifications.buttons.value
|
||||
notif.progress = undefined
|
||||
notif.waiting = undefined
|
||||
} else {
|
||||
@@ -403,7 +470,6 @@ function updateNotification(resummon = false): void {
|
||||
type: 'download',
|
||||
autoCloseMs: null,
|
||||
progressItems,
|
||||
buttons: installJobNotifications.buttons.value,
|
||||
})
|
||||
notificationId.value = notif.id
|
||||
}
|
||||
@@ -488,7 +554,7 @@ const installJobNotifications = await useInstallJobNotifications({
|
||||
|
||||
await refreshLoadingBars()
|
||||
|
||||
const unlistenLoading = await loading_listener(async () => {
|
||||
useAppEvent('loading', async () => {
|
||||
await refreshLoadingBars()
|
||||
})
|
||||
|
||||
@@ -502,11 +568,11 @@ function selectProcess(process: RunningProcess) {
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
removeNotification()
|
||||
terminalNotificationIds.forEach((id) => popupNotificationManager.removeNotification(id))
|
||||
terminalNotificationIds.clear()
|
||||
dismissed.value = false
|
||||
window.removeEventListener('offline', handleOffline)
|
||||
window.removeEventListener('online', handleOnline)
|
||||
unlistenProcess()
|
||||
unlistenLoading()
|
||||
installJobNotifications.dispose()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<script setup>
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import { FolderOpenIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
FileTreeSelect,
|
||||
injectNotificationManager,
|
||||
injectPopupNotificationManager,
|
||||
NewModal,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
@@ -15,8 +16,10 @@ import { ref, shallowRef } from 'vue'
|
||||
|
||||
import { PackageIcon } from '@/assets/icons'
|
||||
import { export_instance_mrpack, get_pack_export_candidates } from '@/helpers/instance'
|
||||
import { highlightInFolder } from '@/helpers/utils'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const popupNotificationManager = injectPopupNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -39,6 +42,14 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Enter modpack description...',
|
||||
},
|
||||
exportButton: { id: 'app.export-modal.export-button', defaultMessage: 'Export' },
|
||||
exportComplete: {
|
||||
id: 'app.export-modal.export-complete',
|
||||
defaultMessage: 'Export complete',
|
||||
},
|
||||
exportCompleteDescription: {
|
||||
id: 'app.export-modal.export-complete-description',
|
||||
defaultMessage: '{name} was exported successfully.',
|
||||
},
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
@@ -93,16 +104,35 @@ const exportPack = async () => {
|
||||
})
|
||||
|
||||
if (outputPath) {
|
||||
export_instance_mrpack(
|
||||
props.instance.id,
|
||||
outputPath,
|
||||
includedFilePaths.value,
|
||||
excludedFilePaths.value,
|
||||
versionInput.value,
|
||||
exportDescription.value,
|
||||
nameInput.value,
|
||||
).catch((err) => handleError(err))
|
||||
exportModal.value.hide()
|
||||
|
||||
try {
|
||||
await export_instance_mrpack(
|
||||
props.instance.id,
|
||||
outputPath,
|
||||
includedFilePaths.value,
|
||||
excludedFilePaths.value,
|
||||
versionInput.value,
|
||||
exportDescription.value,
|
||||
nameInput.value,
|
||||
)
|
||||
|
||||
const fileName = outputPath.split(/[\\/]/).pop() ?? outputPath
|
||||
popupNotificationManager.addPopupNotification({
|
||||
title: formatMessage(messages.exportComplete),
|
||||
text: formatMessage(messages.exportCompleteDescription, { name: fileName }),
|
||||
type: 'success',
|
||||
buttons: [
|
||||
{
|
||||
label: formatMessage(commonMessages.openInFolderButton),
|
||||
icon: FolderOpenIcon,
|
||||
action: () => highlightInFolder(outputPath).catch(handleError),
|
||||
},
|
||||
],
|
||||
})
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon, ExcitedRinthbot, RefreshCwIcon, ServerStackIcon } from '@modrinth/assets'
|
||||
import { Button, commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import {
|
||||
appUpdateState,
|
||||
downloadAvailableAppUpdate,
|
||||
installAvailableAppUpdate,
|
||||
} from '@/providers/app-update'
|
||||
import { useRootBreadcrumb } from '@/providers/breadcrumbs'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'app.hosting.update-required.title',
|
||||
defaultMessage: 'Modrinth App update required',
|
||||
},
|
||||
description: {
|
||||
id: 'app.hosting.update-required.description',
|
||||
defaultMessage: 'You need to update to use Modrinth Hosting through the Modrinth App',
|
||||
},
|
||||
downloadToUpdate: {
|
||||
id: 'app.hosting.update-required.download',
|
||||
defaultMessage: 'Download to update',
|
||||
},
|
||||
downloadingUpdate: {
|
||||
id: 'app.action-bar.downloading-update',
|
||||
defaultMessage: 'Downloading update',
|
||||
},
|
||||
reloadToUpdate: {
|
||||
id: 'app.action-bar.reload-to-update',
|
||||
defaultMessage: 'Reload to update',
|
||||
},
|
||||
excitedRinthbotAlt: {
|
||||
id: 'app.hosting.update-required.rinthbot-alt',
|
||||
defaultMessage: 'Excited Modrinth Bot',
|
||||
},
|
||||
})
|
||||
|
||||
useRootBreadcrumb({
|
||||
slot: 'root',
|
||||
id: 'servers',
|
||||
label: () => formatMessage(commonMessages.serversLabel),
|
||||
to: '/hosting/manage/',
|
||||
visual: { type: 'icon', component: ServerStackIcon },
|
||||
})
|
||||
|
||||
const { downloading, downloadPercent, downloadProgress, finishedDownloading } = appUpdateState
|
||||
|
||||
const isUpdateDownloading = computed(
|
||||
() =>
|
||||
downloading.value ||
|
||||
(downloadProgress.value > 0 && downloadProgress.value < 1 && !finishedDownloading.value),
|
||||
)
|
||||
|
||||
async function handleUpdateClick() {
|
||||
if (isUpdateDownloading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (finishedDownloading.value) {
|
||||
await installAvailableAppUpdate()
|
||||
} else {
|
||||
await downloadAvailableAppUpdate()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="box-border flex min-h-full items-center justify-center p-4">
|
||||
<div class="relative mx-auto w-full max-w-xl pt-28">
|
||||
<img
|
||||
:src="ExcitedRinthbot"
|
||||
:alt="formatMessage(messages.excitedRinthbotAlt)"
|
||||
class="absolute right-8 top-0 h-28 w-auto md:right-20"
|
||||
/>
|
||||
<div class="relative flex flex-col gap-5 rounded-lg bg-bg-raised p-7 shadow-lg">
|
||||
<div
|
||||
class="absolute left-0 top-0 h-px w-full bg-gradient-to-r from-transparent via-green-500 to-transparent opacity-40"
|
||||
style="
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent 2rem,
|
||||
var(--color-green) calc(100% - 13rem),
|
||||
var(--color-green) calc(100% - 5rem),
|
||||
transparent calc(100% - 2rem)
|
||||
);
|
||||
"
|
||||
></div>
|
||||
|
||||
<div class="flex flex-col gap-5">
|
||||
<h1 class="m-0 text-3xl font-extrabold">
|
||||
{{ formatMessage(messages.title) }}
|
||||
</h1>
|
||||
<p class="m-0 text-lg">
|
||||
{{ formatMessage(messages.description) }}
|
||||
</p>
|
||||
<Button
|
||||
type="colored"
|
||||
color="brand"
|
||||
:disabled="isUpdateDownloading"
|
||||
:aria-busy="isUpdateDownloading"
|
||||
@click="handleUpdateClick"
|
||||
>
|
||||
<RefreshCwIcon v-if="finishedDownloading" />
|
||||
<DownloadIcon v-else />
|
||||
<span v-if="isUpdateDownloading">
|
||||
{{ formatMessage(messages.downloadingUpdate) }}
|
||||
<span class="inline-block w-[3ch] text-right tabular-nums">
|
||||
{{ downloadPercent }}%
|
||||
</span>
|
||||
</span>
|
||||
<span v-else-if="finishedDownloading">
|
||||
{{ formatMessage(messages.reloadToUpdate) }}
|
||||
</span>
|
||||
<span v-else>{{ formatMessage(messages.downloadToUpdate) }}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -10,11 +10,11 @@ import {
|
||||
import { Avatar, IconButton, injectNotificationManager, useRelativeTime } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { install_existing_instance, install_pack_to_existing_instance } from '@/helpers/install'
|
||||
import { kill, run } from '@/helpers/instance'
|
||||
import { get_by_instance_id } from '@/helpers/process'
|
||||
@@ -136,7 +136,7 @@ defineExpose({
|
||||
|
||||
const currentEvent = ref(null)
|
||||
|
||||
const unlisten = await process_listener((e) => {
|
||||
useAppEvent('process', (e) => {
|
||||
if (e.instance_id === props.instance.id) {
|
||||
currentEvent.value = e.event
|
||||
if (e.event === 'finished') {
|
||||
@@ -148,7 +148,6 @@ const unlisten = await process_listener((e) => {
|
||||
onMounted(() => {
|
||||
checkProcess()
|
||||
})
|
||||
onUnmounted(() => unlisten())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -7,7 +7,7 @@ import dayjs from 'dayjs'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import NavButton from '@/components/ui/NavButton.vue'
|
||||
import { instance_listener } from '@/helpers/events.js'
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { list } from '@/helpers/instance'
|
||||
import { instanceKeys } from '@/pages/instance/query-options'
|
||||
|
||||
@@ -148,7 +148,7 @@ const getInstances = async () => {
|
||||
await getInstances()
|
||||
updateMaxAuto()
|
||||
|
||||
const unlistenInstance = await instance_listener(async (event) => {
|
||||
useAppEvent('instance', async (event) => {
|
||||
if (event.event !== 'synced') {
|
||||
await getInstances()
|
||||
}
|
||||
@@ -162,7 +162,6 @@ onUnmounted(() => {
|
||||
window.removeEventListener('resize', updateMaxAuto)
|
||||
document.body.classList.remove('quick-instance-dragging')
|
||||
clearOverdragFlash()
|
||||
unlistenInstance()
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
|
||||
@@ -82,7 +82,7 @@ import { injectLoadingState } from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||
import { loading_listener } from '@/helpers/events.js'
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
|
||||
const doneLoading = ref(false)
|
||||
const loadingProgress = ref(0)
|
||||
@@ -132,13 +132,10 @@ function fakeLoadingIncrease() {
|
||||
}
|
||||
}
|
||||
|
||||
loading_listener(async (e) => {
|
||||
useAppEvent('loading', (e) => {
|
||||
if (e.event.type === 'directory_move') {
|
||||
loadingProgress.value = 100 * (e.fraction ?? 1)
|
||||
message.value = 'Updating app directory...'
|
||||
} else if (e.event.type === 'checking_for_updates') {
|
||||
loadingProgress.value = 100 * (e.fraction ?? 1)
|
||||
message.value = 'Checking for updates...'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -3,12 +3,14 @@ import { NotepadTextIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { $fetch } from 'ofetch'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { release_ads_window_hold, take_ads_window_hold } from '@/helpers/ads.js'
|
||||
import { list } from '@/helpers/instance'
|
||||
import { get as getCreds } from '@/helpers/mr_auth.ts'
|
||||
|
||||
let adsWindowHold = false
|
||||
|
||||
type Survey = {
|
||||
id: string
|
||||
tally_id: string
|
||||
@@ -92,30 +94,44 @@ async function openSurvey() {
|
||||
onOpen: () => console.info('Opened user survey'),
|
||||
onClose: () => {
|
||||
console.info('Closed user survey')
|
||||
show_ads_window()
|
||||
if (adsWindowHold) {
|
||||
adsWindowHold = false
|
||||
release_ads_window_hold()
|
||||
}
|
||||
},
|
||||
onSubmit: () => console.info('Active user survey submitted'),
|
||||
}
|
||||
|
||||
try {
|
||||
hide_ads_window()
|
||||
await take_ads_window_hold()
|
||||
adsWindowHold = true
|
||||
if (tallyWindow.Tally?.openPopup) {
|
||||
console.info(`Opening Tally popup for user survey (form ID: ${formId})`)
|
||||
dismissSurvey()
|
||||
tallyWindow.Tally.openPopup(formId, popupOptions)
|
||||
} else {
|
||||
console.warn('Tally script not yet loaded')
|
||||
show_ads_window()
|
||||
adsWindowHold = false
|
||||
await release_ads_window_hold()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error opening Tally popup:', e)
|
||||
show_ads_window()
|
||||
if (adsWindowHold) {
|
||||
adsWindowHold = false
|
||||
await release_ads_window_hold()
|
||||
}
|
||||
}
|
||||
|
||||
console.info(`Found user survey to show with tally_id: ${formId}`)
|
||||
tallyWindow.Tally?.openPopup(formId, popupOptions)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (adsWindowHold) {
|
||||
adsWindowHold = false
|
||||
release_ads_window_hold()
|
||||
}
|
||||
})
|
||||
|
||||
function dismissSurvey() {
|
||||
if (!availableSurvey.value) return
|
||||
localStorage.setItem(`survey-${availableSurvey.value.id}-display`, String(new Date()))
|
||||
|
||||
+1
-8
@@ -10,7 +10,6 @@ import {
|
||||
import { Admonition, Button, ButtonLink, Collapsible, IconButton, NewModal } from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
|
||||
@@ -29,19 +28,13 @@ function show(errorVal: { message?: string }) {
|
||||
matchedError.value = findMinecraftAuthError(rawError.value)
|
||||
|
||||
debugCollapsed.value = true
|
||||
hide_ads_window()
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
onModalHide()
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
function onModalHide() {
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
hide,
|
||||
@@ -74,7 +67,7 @@ async function copyToClipboard(text: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NewModal ref="modal" header="Sign in Failed" :max-width="'548px'" @hide="onModalHide">
|
||||
<NewModal ref="modal" header="Sign in Failed" :max-width="'548px'">
|
||||
<div class="flex flex-col gap-6">
|
||||
<Admonition
|
||||
type="warning"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
ref="modal"
|
||||
:header="formatMessage(messages.installToPlay)"
|
||||
:closable="true"
|
||||
:on-hide="show_ads_window"
|
||||
max-width="544px"
|
||||
width="544px"
|
||||
>
|
||||
@@ -141,10 +140,11 @@
|
||||
</div>
|
||||
</NewModal>
|
||||
|
||||
<ModpackContentModal
|
||||
ref="modpackContentModal"
|
||||
:modpack-name="project?.name ?? ''"
|
||||
:modpack-icon-url="project?.icon_url ?? undefined"
|
||||
<ManagedContentModal
|
||||
ref="managedContentModal"
|
||||
:header="formatMessage(messages.modpackContent)"
|
||||
:source-name="project?.name ?? ''"
|
||||
:source-icon-url="project?.icon_url ?? undefined"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -159,7 +159,7 @@ import {
|
||||
type ContentItem,
|
||||
defineMessages,
|
||||
formatLoader,
|
||||
ModpackContentModal,
|
||||
ManagedContentModal,
|
||||
NewModal,
|
||||
Table,
|
||||
type TableColumn,
|
||||
@@ -169,7 +169,6 @@ import {
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads'
|
||||
import { get_project, get_project_many, get_version, get_version_many } from '@/helpers/cache.js'
|
||||
import { injectServerInstall } from '@/providers/server-install'
|
||||
|
||||
@@ -269,10 +268,10 @@ function handleReport() {
|
||||
}
|
||||
}
|
||||
|
||||
const modpackContentModal = ref<InstanceType<typeof ModpackContentModal>>()
|
||||
const managedContentModal = ref<InstanceType<typeof ManagedContentModal>>()
|
||||
|
||||
async function openViewContents() {
|
||||
modpackContentModal.value?.showLoading()
|
||||
managedContentModal.value?.showLoading()
|
||||
try {
|
||||
// Ensure version data is available — the useQuery may not have resolved yet
|
||||
const versionId = modpackVersionId.value
|
||||
@@ -330,10 +329,10 @@ async function openViewContents() {
|
||||
}
|
||||
},
|
||||
)
|
||||
modpackContentModal.value?.show(contentItems)
|
||||
managedContentModal.value?.show(contentItems)
|
||||
} catch (err) {
|
||||
console.error('Failed to load modpack contents:', err)
|
||||
modpackContentModal.value?.show([])
|
||||
managedContentModal.value?.show([])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,7 +351,6 @@ async function show(
|
||||
|
||||
if (modpackVersionIdVal) await fetchData(modpackVersionIdVal)
|
||||
|
||||
hide_ads_window()
|
||||
modal.value?.show(e)
|
||||
await nextTick()
|
||||
forceCheckTableScroll()
|
||||
@@ -363,6 +361,10 @@ function hide() {
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
modpackContent: {
|
||||
id: 'app.modal.install-to-play.managed-content.modpack-header',
|
||||
defaultMessage: 'Modpack content',
|
||||
},
|
||||
installToPlay: {
|
||||
id: 'app.modal.install-to-play.header',
|
||||
defaultMessage: 'Install to play',
|
||||
|
||||
@@ -34,6 +34,7 @@ import { get_project_many, get_version, get_version_many } from '@/helpers/cache
|
||||
import { wait_for_install_job } from '@/helpers/install'
|
||||
import { update_managed_modrinth_version } from '@/helpers/instance'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import { injectAppEvents } from '@/providers/app-events'
|
||||
import { injectServerInstall } from '@/providers/server-install'
|
||||
|
||||
type Dependency = Labrinth.Versions.v3.Dependency
|
||||
@@ -74,6 +75,7 @@ type ProjectInfo = {
|
||||
}
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const appEvents = injectAppEvents()
|
||||
const { startInstallingServer, stopInstallingServer } = injectServerInstall()
|
||||
type UpdateCompleteCallback = () => void | Promise<void>
|
||||
|
||||
@@ -253,7 +255,7 @@ async function handleUpdate() {
|
||||
try {
|
||||
if (modpackVersionId.value && instance.value) {
|
||||
const job = await update_managed_modrinth_version(instance.value.id, modpackVersionId.value)
|
||||
await wait_for_install_job(job.job_id)
|
||||
await wait_for_install_job(appEvents, job.job_id)
|
||||
await onUpdateComplete.value()
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
} from '@/helpers/install'
|
||||
import { useSharedInstanceErrors } from '@/helpers/shared-instance-errors'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import { injectAppEvents } from '@/providers/app-events'
|
||||
|
||||
type UpdateCompleteCallback = () => void | Promise<void>
|
||||
|
||||
@@ -54,6 +55,7 @@ const instance = ref<GameInstance | null>(null)
|
||||
const preview = ref<SharedInstanceUpdatePreview | null>(null)
|
||||
const onComplete = ref<UpdateCompleteCallback>(() => {})
|
||||
const { formatMessage } = useVIntl()
|
||||
const appEvents = injectAppEvents()
|
||||
const { notifySharedInstanceError } = useSharedInstanceErrors()
|
||||
const diffs = computed<ContentDiffItem[]>(
|
||||
() =>
|
||||
@@ -78,7 +80,7 @@ async function update() {
|
||||
try {
|
||||
if (instance.value) {
|
||||
const job = await install_update_shared_instance(instance.value.id)
|
||||
await wait_for_install_job(job.job_id)
|
||||
await wait_for_install_job(appEvents, job.job_id)
|
||||
await onComplete.value()
|
||||
successful = true
|
||||
}
|
||||
|
||||
+9
-23
@@ -229,11 +229,11 @@
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
<ModpackContentModal
|
||||
<ManagedContentModal
|
||||
ref="contentModal"
|
||||
:header="formatMessage(messages.sharedInstanceContent)"
|
||||
:modpack-name="preview?.name ?? ''"
|
||||
:modpack-icon-url="preview?.iconUrl ?? undefined"
|
||||
:source-name="preview?.name ?? ''"
|
||||
:source-icon-url="preview?.iconUrl ?? undefined"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -251,12 +251,13 @@ import {
|
||||
type ComboboxOption,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
formatReportType,
|
||||
injectAuth,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
ManagedContentModal,
|
||||
MarkdownEditor,
|
||||
ModpackContentModal,
|
||||
NewModal,
|
||||
Table,
|
||||
type TableColumn,
|
||||
@@ -268,7 +269,6 @@ import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
import { config } from '@/config'
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads'
|
||||
import { toError } from '@/helpers/errors'
|
||||
import type { SharedInstanceInstallPreview } from '@/helpers/install'
|
||||
import { create_report } from '@/helpers/reports'
|
||||
@@ -289,7 +289,7 @@ type SharedInstanceCreator = {
|
||||
}
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
const contentModal = ref<InstanceType<typeof ModpackContentModal>>()
|
||||
const contentModal = ref<InstanceType<typeof ManagedContentModal>>()
|
||||
const externalFileTable = ref<HTMLElement | null>(null)
|
||||
const preview = ref<SharedInstanceInstallPreview | null>(null)
|
||||
const creator = ref<SharedInstanceCreator | null>(null)
|
||||
@@ -329,9 +329,9 @@ const externalFileRows = computed<ExternalFileRow[]>(() =>
|
||||
.sort((left, right) => left.name.localeCompare(right.name)),
|
||||
)
|
||||
const reportReasonOptions = computed<ComboboxOption<ReportReason>[]>(() => [
|
||||
{ value: 'malicious', label: formatMessage(messages.maliciousReason) },
|
||||
{ value: 'inappropriate', label: formatMessage(messages.inappropriateReason) },
|
||||
{ value: 'spam', label: formatMessage(messages.spamReason) },
|
||||
{ value: 'malicious', label: formatReportType(formatMessage, 'malicious') },
|
||||
{ value: 'inappropriate', label: formatReportType(formatMessage, 'inappropriate') },
|
||||
{ value: 'spam', label: formatReportType(formatMessage, 'spam') },
|
||||
])
|
||||
const canSubmitReport = computed(
|
||||
() => Boolean(preview.value && additionalContext.value.trim()) && !submitLoading.value,
|
||||
@@ -448,7 +448,6 @@ function handleCancel() {
|
||||
function handleHide() {
|
||||
resetReportState()
|
||||
creator.value = null
|
||||
show_ads_window()
|
||||
}
|
||||
function resetReportState() {
|
||||
reportMode.value = false
|
||||
@@ -488,7 +487,6 @@ function showReport(
|
||||
}
|
||||
function showPreview(previewValue: SharedInstanceInstallPreview, event?: MouseEvent) {
|
||||
preview.value = previewValue
|
||||
hide_ads_window()
|
||||
modal.value?.show(event)
|
||||
void nextTick(() => forceCheckTableScroll())
|
||||
}
|
||||
@@ -543,18 +541,6 @@ const messages = defineMessages({
|
||||
id: 'app.modal.install-to-play.report-reason',
|
||||
defaultMessage: 'Which rule does this instance violate?',
|
||||
},
|
||||
maliciousReason: {
|
||||
id: 'app.modal.install-to-play.report-reason.malicious',
|
||||
defaultMessage: 'Malicious',
|
||||
},
|
||||
inappropriateReason: {
|
||||
id: 'app.modal.install-to-play.report-reason.inappropriate',
|
||||
defaultMessage: 'Inappropriate',
|
||||
},
|
||||
spamReason: {
|
||||
id: 'app.modal.install-to-play.report-reason.spam',
|
||||
defaultMessage: 'Spam',
|
||||
},
|
||||
additionalContext: {
|
||||
id: 'app.modal.install-to-play.additional-context',
|
||||
defaultMessage: 'Additional context',
|
||||
|
||||
@@ -21,12 +21,12 @@ import {
|
||||
import { capitalizeString } from '@modrinth/utils'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_project } from '@/helpers/cache'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { kill, run } from '@/helpers/instance'
|
||||
import { get_by_instance_id } from '@/helpers/process'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
@@ -108,7 +108,7 @@ const stop = async (event: MouseEvent) => {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const unlistenProcesses = await process_listener(async () => {
|
||||
useAppEvent('process', async () => {
|
||||
await checkProcess()
|
||||
})
|
||||
|
||||
@@ -121,10 +121,6 @@ const checkProcess = async () => {
|
||||
onMounted(() => {
|
||||
checkProcess()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
unlistenProcesses()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<SmartClickable>
|
||||
|
||||
@@ -5,12 +5,12 @@ import { GAME_MODES, injectNotificationManager } from '@modrinth/ui'
|
||||
import { platform } from '@tauri-apps/plugin-os'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import InstanceItem from '@/components/ui/world/InstanceItem.vue'
|
||||
import WorldItem from '@/components/ui/world/WorldItem.vue'
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { instance_listener, process_listener } from '@/helpers/events'
|
||||
import { kill, run } from '@/helpers/instance'
|
||||
import { get_all } from '@/helpers/process'
|
||||
import { get_game_versions } from '@/helpers/tags'
|
||||
@@ -215,11 +215,11 @@ async function stopInstance(path: string) {
|
||||
const currentInstance = ref<string>()
|
||||
const currentWorld = ref<string>()
|
||||
|
||||
const unlistenProcesses = await process_listener(async () => {
|
||||
useAppEvent('process', async () => {
|
||||
await checkProcesses()
|
||||
})
|
||||
|
||||
const unlistenInstances = await instance_listener(async () => {
|
||||
useAppEvent('instance', async () => {
|
||||
await populateJumpBackIn().catch(() => {
|
||||
console.error('Failed to populate jump back in')
|
||||
})
|
||||
@@ -251,11 +251,6 @@ onMounted(() => {
|
||||
checkProcesses()
|
||||
linuxPopulateCount.value = 0
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
unlistenProcesses()
|
||||
unlistenInstances()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -10,7 +10,6 @@ import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { Router } from 'vue-router'
|
||||
|
||||
import { install_job_listener } from '@/helpers/events'
|
||||
import {
|
||||
install_job_dismiss,
|
||||
install_job_list,
|
||||
@@ -23,6 +22,7 @@ import {
|
||||
type InstallProgress,
|
||||
} from '@/helpers/install'
|
||||
import { get_many as getInstances } from '@/helpers/instance'
|
||||
import { injectAppEvents } from '@/providers/app-events'
|
||||
import { useTheming } from '@/store/state'
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -234,6 +234,7 @@ export async function useInstallJobNotifications(opts: {
|
||||
handleError: (err: unknown) => void
|
||||
onChange: () => void
|
||||
}) {
|
||||
const appEvents = injectAppEvents()
|
||||
const { formatMessage } = useVIntl()
|
||||
const themeStore = useTheming()
|
||||
const jobs = ref<InstallJobSnapshot[]>([])
|
||||
@@ -404,8 +405,6 @@ export async function useInstallJobNotifications(opts: {
|
||||
}
|
||||
|
||||
function getProgress(job: InstallJobSnapshot): number {
|
||||
if (job.status === 'succeeded') return 1
|
||||
if (job.status === 'failed' || job.status === 'interrupted') return 0
|
||||
const progress = getEffectiveProgress(job)
|
||||
if (!progress || progress.total <= 0) return 0
|
||||
return Math.max(0, Math.min(1, progress.current / progress.total))
|
||||
@@ -526,8 +525,12 @@ export async function useInstallJobNotifications(opts: {
|
||||
)
|
||||
}
|
||||
|
||||
const activeJobs = computed(() =>
|
||||
jobs.value.filter((job) => job.status === 'queued' || job.status === 'running'),
|
||||
)
|
||||
|
||||
const progressItems = computed<PopupNotificationProgressItem[]>(() =>
|
||||
jobs.value.map((job) => {
|
||||
activeJobs.value.map((job) => {
|
||||
const progress = getEffectiveProgress(job)
|
||||
|
||||
return {
|
||||
@@ -536,20 +539,26 @@ export async function useInstallJobNotifications(opts: {
|
||||
text: getText(job),
|
||||
iconUrl: iconUrls.value[job.job_id] ?? null,
|
||||
progress: getProgress(job),
|
||||
waiting: !job.progress && ['queued', 'running'].includes(job.status),
|
||||
showProgress: !isTerminalJob(job),
|
||||
wrapText: isTerminalJob(job),
|
||||
progressType: isTerminalJob(job) ? undefined : getProgressType(job),
|
||||
progressCurrent: isTerminalJob(job) ? undefined : progress?.current,
|
||||
progressTotal: isTerminalJob(job) ? undefined : progress?.total,
|
||||
waiting: !job.progress && job.status === 'running',
|
||||
showProgress: job.status === 'running',
|
||||
progressType: getProgressType(job),
|
||||
progressCurrent: progress?.current,
|
||||
progressTotal: progress?.total,
|
||||
buttons: getButtons(job),
|
||||
dismissible: isTerminalJob(job),
|
||||
onDismiss: getDismissHandler(job),
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const buttons = computed<PopupNotificationButton[] | undefined>(() => undefined)
|
||||
const terminalNotifications = computed(() =>
|
||||
jobs.value.filter(isTerminalJob).map((job) => ({
|
||||
id: job.job_id,
|
||||
title: getTitle(job),
|
||||
text: getText(job),
|
||||
type: job.status === 'failed' ? ('error' as const) : ('warning' as const),
|
||||
buttons: getButtons(job),
|
||||
onDismiss: getDismissHandler(job),
|
||||
})),
|
||||
)
|
||||
|
||||
async function refreshMetadata(notify = true) {
|
||||
const request = ++metadataRequest
|
||||
@@ -627,14 +636,14 @@ export async function useInstallJobNotifications(opts: {
|
||||
void refreshMetadata()
|
||||
}
|
||||
|
||||
const unlisten = await install_job_listener((job: InstallJobSnapshot) => applyJobUpdate(job))
|
||||
const unlisten = appEvents.on('install_job', applyJobUpdate)
|
||||
await refresh(false)
|
||||
|
||||
return {
|
||||
active: computed(() => jobs.value.length > 0),
|
||||
active: computed(() => activeJobs.value.length > 0),
|
||||
title: computed(() => formatMessage(messages.installs)),
|
||||
progressItems,
|
||||
buttons,
|
||||
terminalNotifications,
|
||||
refresh,
|
||||
dispose: () => {
|
||||
for (const timeout of copiedResetTimeouts.values()) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
fetchCachedServerStatus,
|
||||
getFreshCachedServerStatus,
|
||||
} from '@/composables/instances/use-server-status-query'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { kill, list as listInstances } from '@/helpers/instance'
|
||||
import { get_by_instance_id } from '@/helpers/process'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
@@ -78,7 +78,6 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
const lastServerHits = shallowRef<Labrinth.Search.v3.ResultSearchProject[]>([])
|
||||
const contextMenuRef = ref<ContextMenuHandle | null>(null)
|
||||
let serverPingsActive = true
|
||||
let unlistenProcesses: (() => void) | null = null
|
||||
|
||||
async function checkServerRunningStates(hits: Labrinth.Search.v3.ResultSearchProject[]) {
|
||||
debugLog('checkServerRunningStates', { hitCount: hits.length })
|
||||
@@ -280,7 +279,7 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
process_listener((event: { event: string; instance_id: string }) => {
|
||||
useAppEvent('process', (event) => {
|
||||
debugLog('process event', event)
|
||||
if (event.event === 'finished') {
|
||||
const projectId = Object.entries(runningServerProjects.value).find(
|
||||
@@ -292,14 +291,9 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
}
|
||||
}
|
||||
})
|
||||
.then((unlisten) => {
|
||||
unlistenProcesses = unlisten
|
||||
})
|
||||
.catch(options.handleError)
|
||||
|
||||
onUnmounted(() => {
|
||||
serverPingsActive = false
|
||||
unlistenProcesses?.()
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { onScopeDispose } from 'vue'
|
||||
|
||||
import {
|
||||
type AppEventHandler,
|
||||
type AppEvents,
|
||||
type AppEventType,
|
||||
injectAppEvents,
|
||||
} from '@/providers/app-events'
|
||||
|
||||
export function useAppEvent<Type extends AppEventType>(
|
||||
type: Type,
|
||||
handler: AppEventHandler<Type>,
|
||||
events: AppEvents = injectAppEvents(),
|
||||
) {
|
||||
const unsubscribe = events.on(type, handler)
|
||||
onScopeDispose(unsubscribe)
|
||||
return unsubscribe
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { computed, type MaybeRefOrGetter, onUnmounted, toValue } from 'vue'
|
||||
import { computed, type MaybeRefOrGetter, toValue } from 'vue'
|
||||
|
||||
import { useAppEvent } from '@/composables/use-app-event'
|
||||
import { toError } from '@/helpers/errors'
|
||||
import { friend_listener } from '@/helpers/events.js'
|
||||
import {
|
||||
acceptCachedFriend,
|
||||
add_friend,
|
||||
@@ -127,13 +127,9 @@ export function useFriends(options: {
|
||||
)
|
||||
}
|
||||
|
||||
let unlisten: (() => void) | undefined
|
||||
void friend_listener(() => {
|
||||
useAppEvent('friend', () => {
|
||||
void queryClient.invalidateQueries({ queryKey: queryKey.value })
|
||||
}).then((listener) => {
|
||||
unlisten = listener
|
||||
})
|
||||
onUnmounted(() => unlisten?.())
|
||||
|
||||
return {
|
||||
query,
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { CommandPayload } from "./CommandPayload";
|
||||
import type { FriendPayload } from "./FriendPayload";
|
||||
import type { InstallJobSnapshot } from "./InstallJobSnapshot";
|
||||
import type { InstanceBulkUpdateProgressPayload } from "./InstanceBulkUpdateProgressPayload";
|
||||
import type { InstancePayload } from "./InstancePayload";
|
||||
import type { LoadingPayload } from "./LoadingPayload";
|
||||
import type { LogPayload } from "./LogPayload";
|
||||
import type { ProcessPayload } from "./ProcessPayload";
|
||||
import type { WarningPayload } from "./WarningPayload";
|
||||
|
||||
export type AppEvent = { "type": "loading", "payload": LoadingPayload } | { "type": "process", "payload": ProcessPayload } | { "type": "instance", "payload": InstancePayload } | { "type": "instance_bulk_update_progress", "payload": InstanceBulkUpdateProgressPayload } | { "type": "install_job", "payload": InstallJobSnapshot } | { "type": "command", "payload": CommandPayload } | { "type": "warning", "payload": WarningPayload } | { "type": "friend", "payload": FriendPayload } | { "type": "notification", "payload": unknown } | { "type": "log", "payload": LogPayload } | { "type": "ads_consent_required", "payload": boolean };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type CommandPayload = { "event": "InstallMod", id: string, } | { "event": "InstallVersion", id: string, } | { "event": "InstallModpack", id: string, } | { "event": "InstallServer", id: string, } | { "event": "LaunchInstance", id: string, server: string | null, singleplayer_world: string | null, } | { "event": "InstallSharedInstanceInvite", invite_id: string, } | { "event": "RunMRPack", path: string, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { FriendStatusPayload } from "./FriendStatusPayload";
|
||||
|
||||
export type FriendPayload = { "event": "friend_request", from: string, } | { "event": "user_offline", id: string, } | { "event": "status_update", user_status: FriendStatusPayload, } | { "event": "status_sync" };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type FriendStatusPayload = { user_id: string, profile_name: string | null, last_update: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ImportLauncherType = "MultiMC" | "PrismLauncher" | "ATLauncher" | "GDLauncher" | "Curseforge" | "Unknown";
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallApiErrorDetails = { error: string, status?: number, method?: string, url?: string, route?: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallErrorContext = { operation: string, source_path?: string, target_path?: string, file_path?: string, entry_path?: string, urls: Array<string>, expected_hash?: string, expected_size?: number, project_id?: string, version_id?: string, minecraft_version?: string, loader?: string, java_version?: number, os?: string, arch?: string, };
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { InstallApiErrorDetails } from "./InstallApiErrorDetails";
|
||||
import type { InstallErrorContext } from "./InstallErrorContext";
|
||||
import type { InstallPhaseId } from "./InstallPhaseId";
|
||||
import type { SharedInstanceUnavailableReason } from "./SharedInstanceUnavailableReason";
|
||||
|
||||
export type InstallErrorView = { code: string, phase?: InstallPhaseId, message: string, reason?: SharedInstanceUnavailableReason, api?: InstallApiErrorDetails, context?: InstallErrorContext, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallJavaStep = "resolving" | "fetching_metadata" | "downloading" | "extracting" | "validating";
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallJobDisplay = { title: string, icon: string | null, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallJobKind = "create_instance" | "create_modpack_instance" | "create_shared_instance" | "import_instance" | "duplicate_instance" | "install_existing_instance" | "install_pack_to_existing_instance" | "update_shared_instance";
|
||||
@@ -0,0 +1,11 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { InstallErrorView } from "./InstallErrorView";
|
||||
import type { InstallJobDisplay } from "./InstallJobDisplay";
|
||||
import type { InstallJobKind } from "./InstallJobKind";
|
||||
import type { InstallJobStatus } from "./InstallJobStatus";
|
||||
import type { InstallPhaseDetails } from "./InstallPhaseDetails";
|
||||
import type { InstallPhaseId } from "./InstallPhaseId";
|
||||
import type { InstallProgress } from "./InstallProgress";
|
||||
import type { InstallTarget } from "./InstallTarget";
|
||||
|
||||
export type InstallJobSnapshot = { job_id: string, instance_id: string | null, kind: InstallJobKind, status: InstallJobStatus, target: InstallTarget, phase: InstallPhaseId, progress: InstallProgress | null, details: InstallPhaseDetails, display: InstallJobDisplay | null, error: InstallErrorView | null, rollback_error: InstallErrorView | null, created: string, modified: string, finished: string | null, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallJobStatus = "queued" | "running" | "succeeded" | "failed" | "interrupted" | "canceled";
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ImportLauncherType } from "./ImportLauncherType";
|
||||
import type { InstallJavaStep } from "./InstallJavaStep";
|
||||
import type { ModLoader } from "./ModLoader";
|
||||
|
||||
export type InstallPhaseDetails = { "type": "empty" } | { "type": "instance", name: string, } | { "type": "minecraft", game_version: string, loader: ModLoader, } | { "type": "java", major_version: number, step: InstallJavaStep, } | { "type": "modpack", project_id: string | null, version_id: string | null, title: string | null, } | { "type": "import", launcher_type: ImportLauncherType, instance_folder: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallPhaseId = "preparing_instance" | "resolving_pack" | "downloading_pack_file" | "reading_pack_manifest" | "downloading_content" | "extracting_overrides" | "resolving_minecraft" | "resolving_loader" | "preparing_java" | "downloading_minecraft" | "running_loader_processors" | "finalizing" | "rolling_back";
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { InstallProgressSecondary } from "./InstallProgressSecondary";
|
||||
|
||||
export type InstallProgress = { current: number, total: number, secondary?: InstallProgressSecondary, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallProgressSecondary = { current: number, total: number, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstallTarget = { "type": "new_instance", instance_id: string | null, } | { "type": "existing_instance", instance_id: string, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { InstanceBulkUpdateProgressStage } from "./InstanceBulkUpdateProgressStage";
|
||||
|
||||
export type InstanceBulkUpdateProgressPayload = { instanceId: string, stage: InstanceBulkUpdateProgressStage, current: number, total: number, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstanceBulkUpdateProgressStage = "resolving_versions" | "downloading" | "finishing";
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstancePayload = { instance_id: string, } & ({ "event": "created" } | { "event": "synced" } | { "event": "servers_updated" } | { "event": "world_updated", world: string, } | { "event": "server_joined", host: string, port: number, timestamp: string, } | { "event": "edited" } | { "event": "content_install_finished", project_ids: Array<string>, } | { "event": "content_install_failed", project_ids: Array<string>, message: string, } | { "event": "removed" });
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type LoadingBarType = { "type": "legacy_data_migration" } | { "type": "directory_move", old: string, new: string, } | { "type": "java_download", version: number, } | { "type": "pack_file_download", instance_id: string, pack_name: string, icon: string | null, pack_version: string, } | { "type": "pack_download", instance_id: string, pack_name: string, icon: string | null, pack_id: string | null, pack_version: string | null, } | { "type": "minecraft_download", instance_id: string, instance_name: string, } | { "type": "instance_update", instance_id: string, instance_name: string, } | { "type": "zip_extract", instance_id: string, instance_name: string, } | { "type": "config_change", new_path: string, } | { "type": "copy_instance", import_location: string, instance_name: string, } | { "type": "launcher_update", version: string, current_version: string, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { LoadingBarType } from "./LoadingBarType";
|
||||
|
||||
export type LoadingPayload = { event: LoadingBarType, loader_uuid: string, fraction: number | null, message: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Log4jEvent = { timestamp_millis: number | null, logger_name: string | null, level: string | null, thread_name: string | null, message: string | null, throwable: string | null, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Log4jEvent } from "./Log4jEvent";
|
||||
|
||||
export type LogPayload = { instance_id: string, } & ({ "type": "log4j" } & Log4jEvent | { "type": "legacy", message: string, });
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ModLoader = "vanilla" | "forge" | "fabric" | "quilt" | "neoforge";
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ProcessPayloadType } from "./ProcessPayloadType";
|
||||
|
||||
export type ProcessPayload = { instance_id: string, uuid: string, event: ProcessPayloadType, message: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ProcessPayloadType = "launched" | "finished";
|
||||
@@ -0,0 +1,8 @@
|
||||
# App event bindings
|
||||
|
||||
> [!WARNING]
|
||||
> Do not edit the generated TypeScript or Postcard binding files in this directory manually.
|
||||
|
||||
The event bus types are determined by the Rust [`AppEvent`](../../../../../packages/app-lib/src/event/mod.rs) contract.
|
||||
|
||||
They are regenerated automatically when you run `pnpm app:dev` from the workspace root. Commit any generated changes with the Rust contract change.
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SharedInstanceUnavailableReason = "deleted" | "access_revoked" | "quarantined";
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type WarningPayload = { message: string, };
|
||||
@@ -0,0 +1,78 @@
|
||||
declare type u8 = number
|
||||
declare type u16 = number
|
||||
declare type u32 = number
|
||||
declare type u64 = bigint
|
||||
declare type u128 = bigint
|
||||
declare type usize = bigint
|
||||
declare type i8 = number
|
||||
declare type i16 = number
|
||||
declare type i32 = number
|
||||
declare type i64 = bigint
|
||||
declare type i128 = bigint
|
||||
declare type isize = bigint
|
||||
declare type NonZeroU8 = number
|
||||
declare type NonZeroU16 = number
|
||||
declare type NonZeroU32 = number
|
||||
declare type NonZeroU64 = bigint
|
||||
declare type NonZeroU128 = bigint
|
||||
declare type NonZeroUsize = bigint
|
||||
declare type NonZeroI8 = number
|
||||
declare type NonZeroI16 = number
|
||||
declare type NonZeroI32 = number
|
||||
declare type NonZeroI64 = bigint
|
||||
declare type NonZeroI128 = bigint
|
||||
declare type NonZeroIsize = bigint
|
||||
declare type f32 = number
|
||||
declare type f64 = number
|
||||
|
||||
declare type ArrayLengthMutationKeys = "splice" | "push" | "pop" | "shift" | "unshift"
|
||||
declare type FixedLengthArray<T, L extends number, TObj = [T, ...Array<T>]> =
|
||||
Pick<TObj, Exclude<keyof TObj, ArrayLengthMutationKeys>>
|
||||
& {
|
||||
readonly length: L
|
||||
[ I : number ] : T
|
||||
[Symbol.iterator]: () => IterableIterator<T>
|
||||
}
|
||||
|
||||
export type AppEvent = { tag: "loading", value: LoadingPayload } | { tag: "process", value: ProcessPayload } | { tag: "instance", value: InstancePayload } | { tag: "instance_bulk_update_progress", value: InstanceBulkUpdateProgressPayload } | { tag: "install_job", value: InstallJobSnapshot } | { tag: "command", value: CommandPayload } | { tag: "warning", value: WarningPayload } | { tag: "friend", value: FriendPayload } | { tag: "notification", value: string } | { tag: "log", value: LogPayload } | { tag: "ads_consent_required", value: boolean }
|
||||
export type LoadingBarType = { tag: "legacy_data_migration" } | { tag: "directory_move", value: { old: string, new: string } } | { tag: "java_download", value: { version: u32 } } | { tag: "pack_file_download", value: { instance_id: string, pack_name: string, icon: string | undefined, pack_version: string } } | { tag: "pack_download", value: { instance_id: string, pack_name: string, icon: string | undefined, pack_id: string | undefined, pack_version: string | undefined } } | { tag: "minecraft_download", value: { instance_id: string, instance_name: string } } | { tag: "instance_update", value: { instance_id: string, instance_name: string } } | { tag: "zip_extract", value: { instance_id: string, instance_name: string } } | { tag: "config_change", value: { new_path: string } } | { tag: "copy_instance", value: { import_location: string, instance_name: string } } | { tag: "launcher_update", value: { version: string, current_version: string } }
|
||||
export type LoadingPayload = { event: LoadingBarType, loader_uuid: string, fraction: f64 | undefined, message: string }
|
||||
export type WarningPayload = { message: string }
|
||||
export type InstanceBulkUpdateProgressPayload = { instanceId: string, stage: InstanceBulkUpdateProgressStage, current: u64, total: u64 }
|
||||
export type InstanceBulkUpdateProgressStage = { tag: "resolving_versions" } | { tag: "downloading" } | { tag: "finishing" }
|
||||
export type CommandPayload = { tag: "InstallMod", value: { id: string } } | { tag: "InstallVersion", value: { id: string } } | { tag: "InstallModpack", value: { id: string } } | { tag: "InstallServer", value: { id: string } } | { tag: "LaunchInstance", value: { id: string, server: string | undefined, singleplayer_world: string | undefined } } | { tag: "InstallSharedInstanceInvite", value: { invite_id: string } } | { tag: "RunMRPack", value: { path: string } }
|
||||
export type ProcessPayload = { instance_id: string, uuid: string, event: ProcessPayloadType, message: string }
|
||||
export type ProcessPayloadType = { tag: "launched" } | { tag: "finished" }
|
||||
export type InstancePayload = { instance_id: string, event: InstancePayloadType }
|
||||
export type InstancePayloadType = { tag: "created" } | { tag: "synced" } | { tag: "servers_updated" } | { tag: "world_updated", value: { world: string } } | { tag: "server_joined", value: { host: string, port: u16, timestamp: string } } | { tag: "edited" } | { tag: "content_install_finished", value: { project_ids: string[] } } | { tag: "content_install_failed", value: { project_ids: string[], message: string } } | { tag: "removed" }
|
||||
export type FriendPayload = { tag: "friend_request", value: { from: string } } | { tag: "user_offline", value: { id: string } } | { tag: "status_update", value: { user_status: FriendStatusPayload } } | { tag: "status_sync" }
|
||||
export type FriendStatusPayload = { user_id: string, profile_name: string | undefined, last_update: string }
|
||||
export type SharedInstanceUnavailableReason = { tag: "deleted" } | { tag: "access_revoked" } | { tag: "quarantined" }
|
||||
export type LogEvent = { tag: "log4j", value: Log4jEvent } | { tag: "legacy", value: { message: string } }
|
||||
export type LogPayload = { instance_id: string, event: LogEvent }
|
||||
export type Log4jEvent = { timestamp_millis: i64 | undefined, logger_name: string | undefined, level: string | undefined, thread_name: string | undefined, message: string | undefined, throwable: string | undefined }
|
||||
export type ModLoader = { tag: "vanilla" } | { tag: "forge" } | { tag: "fabric" } | { tag: "quilt" } | { tag: "neoforge" }
|
||||
export type InstallJobSnapshot = { job_id: string, instance_id: string | undefined, kind: InstallJobKind, status: InstallJobStatus, target: InstallTarget, phase: InstallPhaseId, progress: InstallProgress | undefined, details: InstallPhaseDetails, display: InstallJobDisplay | undefined, error: InstallErrorView | undefined, rollback_error: InstallErrorView | undefined, created: string, modified: string, finished: string | undefined }
|
||||
export type InstallJobKind = { tag: "create_instance" } | { tag: "create_modpack_instance" } | { tag: "create_shared_instance" } | { tag: "import_instance" } | { tag: "duplicate_instance" } | { tag: "install_existing_instance" } | { tag: "install_pack_to_existing_instance" } | { tag: "update_shared_instance" }
|
||||
export type InstallJobStatus = { tag: "queued" } | { tag: "running" } | { tag: "succeeded" } | { tag: "failed" } | { tag: "interrupted" } | { tag: "canceled" }
|
||||
export type InstallTarget = { tag: "new_instance", value: { instance_id: string | undefined } } | { tag: "existing_instance", value: { instance_id: string } }
|
||||
export type InstallPhaseId = { tag: "preparing_instance" } | { tag: "resolving_pack" } | { tag: "downloading_pack_file" } | { tag: "reading_pack_manifest" } | { tag: "downloading_content" } | { tag: "extracting_overrides" } | { tag: "resolving_minecraft" } | { tag: "resolving_loader" } | { tag: "preparing_java" } | { tag: "downloading_minecraft" } | { tag: "running_loader_processors" } | { tag: "finalizing" } | { tag: "rolling_back" }
|
||||
export type InstallProgress = { current: u64, total: u64, secondary: InstallProgressSecondary | undefined }
|
||||
export type InstallProgressSecondary = { current: u64, total: u64 }
|
||||
export type InstallPhaseDetails = { tag: "empty" } | { tag: "instance", value: { name: string } } | { tag: "minecraft", value: { game_version: string, loader: ModLoader } } | { tag: "java", value: { major_version: u32, step: InstallJavaStep } } | { tag: "modpack", value: { project_id: string | undefined, version_id: string | undefined, title: string | undefined } } | { tag: "import", value: { launcher_type: ImportLauncherType, instance_folder: string } }
|
||||
export type InstallJavaStep = { tag: "resolving" } | { tag: "fetching_metadata" } | { tag: "downloading" } | { tag: "extracting" } | { tag: "validating" }
|
||||
export type InstallJobDisplay = { title: string, icon: string | undefined }
|
||||
export type InstallErrorView = { code: string, phase: InstallPhaseId | undefined, message: string, reason: SharedInstanceUnavailableReason | undefined, api: InstallApiErrorDetails | undefined, context: InstallErrorContext | undefined }
|
||||
export type InstallApiErrorDetails = { error: string, status: u16 | undefined, method: string | undefined, url: string | undefined, route: string | undefined }
|
||||
export type InstallErrorContext = { operation: string, source_path: string | undefined, target_path: string | undefined, file_path: string | undefined, entry_path: string | undefined, urls: string[], expected_hash: string | undefined, expected_size: u64 | undefined, project_id: string | undefined, version_id: string | undefined, minecraft_version: string | undefined, loader: string | undefined, java_version: u32 | undefined, os: string | undefined, arch: string | undefined }
|
||||
export type ImportLauncherType = { tag: "MultiMC" } | { tag: "PrismLauncher" } | { tag: "ATLauncher" } | { tag: "GDLauncher" } | { tag: "Curseforge" } | { tag: "Unknown" }
|
||||
|
||||
export type Type = "AppEvent" | "LoadingBarType" | "LoadingPayload" | "WarningPayload" | "InstanceBulkUpdateProgressPayload" | "InstanceBulkUpdateProgressStage" | "CommandPayload" | "ProcessPayload" | "ProcessPayloadType" | "InstancePayload" | "InstancePayloadType" | "FriendPayload" | "FriendStatusPayload" | "LogEvent" | "LogPayload" | "Log4jEvent" | "InstallJobSnapshot" | "InstallJobKind" | "InstallJobStatus" | "InstallTarget" | "InstallPhaseId" | "InstallProgress" | "InstallProgressSecondary" | "InstallPhaseDetails" | "InstallJavaStep" | "InstallJobDisplay" | "InstallErrorView" | "InstallApiErrorDetails" | "InstallErrorContext" | "ImportLauncherType" | "ModLoader" | "SharedInstanceUnavailableReason"
|
||||
declare type ValueType<T extends Type> = T extends "AppEvent" ? AppEvent : T extends "LoadingBarType" ? LoadingBarType : T extends "LoadingPayload" ? LoadingPayload : T extends "WarningPayload" ? WarningPayload : T extends "InstanceBulkUpdateProgressPayload" ? InstanceBulkUpdateProgressPayload : T extends "InstanceBulkUpdateProgressStage" ? InstanceBulkUpdateProgressStage : T extends "CommandPayload" ? CommandPayload : T extends "ProcessPayload" ? ProcessPayload : T extends "ProcessPayloadType" ? ProcessPayloadType : T extends "InstancePayload" ? InstancePayload : T extends "InstancePayloadType" ? InstancePayloadType : T extends "FriendPayload" ? FriendPayload : T extends "FriendStatusPayload" ? FriendStatusPayload : T extends "LogEvent" ? LogEvent : T extends "LogPayload" ? LogPayload : T extends "Log4jEvent" ? Log4jEvent : T extends "InstallJobSnapshot" ? InstallJobSnapshot : T extends "InstallJobKind" ? InstallJobKind : T extends "InstallJobStatus" ? InstallJobStatus : T extends "InstallTarget" ? InstallTarget : T extends "InstallPhaseId" ? InstallPhaseId : T extends "InstallProgress" ? InstallProgress : T extends "InstallProgressSecondary" ? InstallProgressSecondary : T extends "InstallPhaseDetails" ? InstallPhaseDetails : T extends "InstallJavaStep" ? InstallJavaStep : T extends "InstallJobDisplay" ? InstallJobDisplay : T extends "InstallErrorView" ? InstallErrorView : T extends "InstallApiErrorDetails" ? InstallApiErrorDetails : T extends "InstallErrorContext" ? InstallErrorContext : T extends "ImportLauncherType" ? ImportLauncherType : T extends "ModLoader" ? ModLoader : T extends "SharedInstanceUnavailableReason" ? SharedInstanceUnavailableReason : void
|
||||
|
||||
export interface Result<T extends Type> {
|
||||
value: ValueType<T>;
|
||||
bytes: Uint8Array;
|
||||
}
|
||||
|
||||
export function deserialize<T extends Type>(type: T, bytes: Uint8Array): Result<T>
|
||||
@@ -0,0 +1,953 @@
|
||||
const BITS_PER_BYTE = 8, BITS_PER_VARINT_BYTE = 7, U8_BYTES = 1, U16_BYTES = 2, U32_BYTES = 4, U64_BYTES = 8, U128_BYTES = 16
|
||||
|
||||
const de_zig_zag_signed = (n) => (n >> 1n) ^ (-(n & 0b1n))
|
||||
const zig_zag = (n_bytes, n) => (n << 1n) ^ (n >> BigInt(n_bytes * BITS_PER_BYTE - 1))
|
||||
const varint_max = (n_bytes) => Math.floor((n_bytes * BITS_PER_BYTE + (BITS_PER_BYTE - 1)) / BITS_PER_VARINT_BYTE)
|
||||
const max_of_last_byte = (n_bytes) => (1 << (n_bytes * BITS_PER_BYTE) % 7) - 1
|
||||
const to_number_if_safe = (n) => Number.MAX_SAFE_INTEGER < ((n < 0n) ? -n : n) ? n : Number(n)
|
||||
const varint = (n_bytes, n) => { let value = BigInt(n), out = []; for (let i = 0; i < varint_max(n_bytes); i++) { out.push(Number(value & 0xFFn)); if (value < 128n) { return out } out[i] |= 0x80; value >>= 7n } }
|
||||
|
||||
class Deserializer {
|
||||
constructor(bytes_in) { this.bytes = Array.from(bytes_in); }
|
||||
pop_next = () => { const next = this.bytes.shift(); if (next === undefined) { throw "input buffer too small" } return next }
|
||||
pop_n = (n) => { const bytes = Array(); for (let i = 0; i < n; i++) { bytes.push(this.bytes.shift()) } return bytes }
|
||||
get_int8 = (signed) => signed ? new Int8Array([this.pop_next()])[0] : this.pop_next();
|
||||
try_take = (n_bytes) => { let out = 0n, v_max = varint_max(n_bytes); for (let i = 0; i < v_max; i++) { const val = this.pop_next(), carry = BigInt(val & 0x7F); out |= carry << BigInt(7 * i); if ((val & 0x80) === 0) { if (i === v_max - 1 && val > max_of_last_byte(n_bytes)) { throw "Bad Variant" } else return out } } throw "Bad Variant"; }
|
||||
deserialize_bool = () => { const byte = this.pop_next(); return byte === undefined ? undefined : byte > 0 ? true : false }
|
||||
deserialize_number = (n_bytes, signed) => { if (n_bytes === U8_BYTES) { return this.get_int8(signed) } else if (n_bytes === U16_BYTES || n_bytes === U32_BYTES || n_bytes === U64_BYTES || n_bytes === U128_BYTES) { const val = this.try_take(n_bytes); return to_number_if_safe(signed ? de_zig_zag_signed(val) : val) } else { throw "byte count not supported" } }
|
||||
deserialize_number_float = (n_bytes) => { const b_buffer = new ArrayBuffer(n_bytes), b_view = new DataView(b_buffer); this.pop_n(n_bytes).forEach((b, i) => b_view.setUint8(i, b)); if (n_bytes === U32_BYTES) { return b_view.getFloat32(0, true) } else if (n_bytes === U64_BYTES) { return b_view.getFloat64(0, true) } else { throw "byte count not supported" } }
|
||||
deserialize_string = () => new TextDecoder().decode(new Uint8Array(this.pop_n(Number(this.try_take(U32_BYTES)))))
|
||||
deserialize_array = (des, len) => Array.from({length: len === undefined ? Number(this.try_take(U32_BYTES)) : len}, (v, i) => des(this))
|
||||
deserialize_string_key_map = (des) => { return [...Array(Number(this.try_take(U32_BYTES)))].reduce((prev) => { prev[this.deserialize_string()] = des(this); return prev }, {}) }
|
||||
deserialize_map = (des) => { return [...Array(Number(this.try_take(U32_BYTES)))].reduce((prev) => { const d = des(this); prev.set(d[0], d[1]); return prev }, new Map()) }
|
||||
release_bytes = () => { return new Uint8Array(this.bytes); }
|
||||
}
|
||||
|
||||
function deserialize_APP_EVENT(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "loading",
|
||||
value: deserialize_LOADING_PAYLOAD(d)
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "process",
|
||||
value: deserialize_PROCESS_PAYLOAD(d)
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "instance",
|
||||
value: deserialize_INSTANCE_PAYLOAD(d)
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "instance_bulk_update_progress",
|
||||
value: deserialize_INSTANCE_BULK_UPDATE_PROGRESS_PAYLOAD(d)
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "install_job",
|
||||
value: deserialize_INSTALL_JOB_SNAPSHOT(d)
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "command",
|
||||
value: deserialize_COMMAND_PAYLOAD(d)
|
||||
};
|
||||
case 6:
|
||||
return {
|
||||
tag: "warning",
|
||||
value: deserialize_WARNING_PAYLOAD(d)
|
||||
};
|
||||
case 7:
|
||||
return {
|
||||
tag: "friend",
|
||||
value: deserialize_FRIEND_PAYLOAD(d)
|
||||
};
|
||||
case 8:
|
||||
return {
|
||||
tag: "notification",
|
||||
value: d.deserialize_string()
|
||||
};
|
||||
case 9:
|
||||
return {
|
||||
tag: "log",
|
||||
value: deserialize_LOG_PAYLOAD(d)
|
||||
};
|
||||
case 10:
|
||||
return {
|
||||
tag: "ads_consent_required",
|
||||
value: d.deserialize_bool()
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_LOADING_BAR_TYPE(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "legacy_data_migration"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "directory_move",
|
||||
value: {
|
||||
old: d.deserialize_string(),
|
||||
new: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "java_download",
|
||||
value: {
|
||||
version: d.deserialize_number(U32_BYTES, false)
|
||||
}
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "pack_file_download",
|
||||
value: {
|
||||
instance_id: d.deserialize_string(),
|
||||
pack_name: d.deserialize_string(),
|
||||
icon: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
pack_version: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "pack_download",
|
||||
value: {
|
||||
instance_id: d.deserialize_string(),
|
||||
pack_name: d.deserialize_string(),
|
||||
icon: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
pack_id: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
pack_version: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "minecraft_download",
|
||||
value: {
|
||||
instance_id: d.deserialize_string(),
|
||||
instance_name: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 6:
|
||||
return {
|
||||
tag: "instance_update",
|
||||
value: {
|
||||
instance_id: d.deserialize_string(),
|
||||
instance_name: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 7:
|
||||
return {
|
||||
tag: "zip_extract",
|
||||
value: {
|
||||
instance_id: d.deserialize_string(),
|
||||
instance_name: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 8:
|
||||
return {
|
||||
tag: "config_change",
|
||||
value: {
|
||||
new_path: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 9:
|
||||
return {
|
||||
tag: "copy_instance",
|
||||
value: {
|
||||
import_location: d.deserialize_string(),
|
||||
instance_name: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 10:
|
||||
return {
|
||||
tag: "launcher_update",
|
||||
value: {
|
||||
version: d.deserialize_string(),
|
||||
current_version: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_LOADING_PAYLOAD(d) {
|
||||
return {
|
||||
event: deserialize_LOADING_BAR_TYPE(d),
|
||||
loader_uuid: d.deserialize_string(),
|
||||
fraction: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_number_float(U64_BYTES),
|
||||
message: d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_WARNING_PAYLOAD(d) {
|
||||
return {
|
||||
message: d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTANCE_BULK_UPDATE_PROGRESS_PAYLOAD(d) {
|
||||
return {
|
||||
instanceId: d.deserialize_string(),
|
||||
stage: deserialize_INSTANCE_BULK_UPDATE_PROGRESS_STAGE(d),
|
||||
current: d.deserialize_number(U64_BYTES, false),
|
||||
total: d.deserialize_number(U64_BYTES, false)
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTANCE_BULK_UPDATE_PROGRESS_STAGE(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "resolving_versions"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "downloading"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "finishing"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_COMMAND_PAYLOAD(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "InstallMod",
|
||||
value: {
|
||||
id: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "InstallVersion",
|
||||
value: {
|
||||
id: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "InstallModpack",
|
||||
value: {
|
||||
id: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "InstallServer",
|
||||
value: {
|
||||
id: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "LaunchInstance",
|
||||
value: {
|
||||
id: d.deserialize_string(),
|
||||
server: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
singleplayer_world: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "InstallSharedInstanceInvite",
|
||||
value: {
|
||||
invite_id: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 6:
|
||||
return {
|
||||
tag: "RunMRPack",
|
||||
value: {
|
||||
path: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_PROCESS_PAYLOAD(d) {
|
||||
return {
|
||||
instance_id: d.deserialize_string(),
|
||||
uuid: d.deserialize_string(),
|
||||
event: deserialize_PROCESS_PAYLOAD_TYPE(d),
|
||||
message: d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_PROCESS_PAYLOAD_TYPE(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "launched"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "finished"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_INSTANCE_PAYLOAD(d) {
|
||||
return {
|
||||
instance_id: d.deserialize_string(),
|
||||
event: deserialize_INSTANCE_PAYLOAD_TYPE(d)
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTANCE_PAYLOAD_TYPE(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "created"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "synced"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "servers_updated"
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "world_updated",
|
||||
value: {
|
||||
world: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "server_joined",
|
||||
value: {
|
||||
host: d.deserialize_string(),
|
||||
port: d.deserialize_number(U16_BYTES, false),
|
||||
timestamp: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "edited"
|
||||
};
|
||||
case 6:
|
||||
return {
|
||||
tag: "content_install_finished",
|
||||
value: {
|
||||
project_ids: d.deserialize_array(() => d.deserialize_string())
|
||||
}
|
||||
};
|
||||
case 7:
|
||||
return {
|
||||
tag: "content_install_failed",
|
||||
value: {
|
||||
project_ids: d.deserialize_array(() => d.deserialize_string()),
|
||||
message: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 8:
|
||||
return {
|
||||
tag: "removed"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_FRIEND_PAYLOAD(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "friend_request",
|
||||
value: {
|
||||
from: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "user_offline",
|
||||
value: {
|
||||
id: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "status_update",
|
||||
value: {
|
||||
user_status: deserialize_FRIEND_STATUS_PAYLOAD(d)
|
||||
}
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "status_sync"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_FRIEND_STATUS_PAYLOAD(d) {
|
||||
return {
|
||||
user_id: d.deserialize_string(),
|
||||
profile_name: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
last_update: d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_LOG_EVENT(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "log4j",
|
||||
value: deserialize_LOG4J_EVENT(d)
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "legacy",
|
||||
value: {
|
||||
message: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_LOG_PAYLOAD(d) {
|
||||
return {
|
||||
instance_id: d.deserialize_string(),
|
||||
event: deserialize_LOG_EVENT(d)
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_LOG4J_EVENT(d) {
|
||||
return {
|
||||
timestamp_millis: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_number(U64_BYTES, true),
|
||||
logger_name: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
level: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
thread_name: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
message: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
throwable: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_JOB_SNAPSHOT(d) {
|
||||
return {
|
||||
job_id: d.deserialize_string(),
|
||||
instance_id: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
kind: deserialize_INSTALL_JOB_KIND(d),
|
||||
status: deserialize_INSTALL_JOB_STATUS(d),
|
||||
target: deserialize_INSTALL_TARGET(d),
|
||||
phase: deserialize_INSTALL_PHASE_ID(d),
|
||||
progress: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_PROGRESS(d),
|
||||
details: deserialize_INSTALL_PHASE_DETAILS(d),
|
||||
display: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_JOB_DISPLAY(d),
|
||||
error: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_ERROR_VIEW(d),
|
||||
rollback_error: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_ERROR_VIEW(d),
|
||||
created: d.deserialize_string(),
|
||||
modified: d.deserialize_string(),
|
||||
finished: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_JOB_KIND(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "create_instance"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "create_modpack_instance"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "create_shared_instance"
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "import_instance"
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "duplicate_instance"
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "install_existing_instance"
|
||||
};
|
||||
case 6:
|
||||
return {
|
||||
tag: "install_pack_to_existing_instance"
|
||||
};
|
||||
case 7:
|
||||
return {
|
||||
tag: "update_shared_instance"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_JOB_STATUS(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "queued"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "running"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "succeeded"
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "failed"
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "interrupted"
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "canceled"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_TARGET(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "new_instance",
|
||||
value: {
|
||||
instance_id: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "existing_instance",
|
||||
value: {
|
||||
instance_id: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_PHASE_ID(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "preparing_instance"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "resolving_pack"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "downloading_pack_file"
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "reading_pack_manifest"
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "downloading_content"
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "extracting_overrides"
|
||||
};
|
||||
case 6:
|
||||
return {
|
||||
tag: "resolving_minecraft"
|
||||
};
|
||||
case 7:
|
||||
return {
|
||||
tag: "resolving_loader"
|
||||
};
|
||||
case 8:
|
||||
return {
|
||||
tag: "preparing_java"
|
||||
};
|
||||
case 9:
|
||||
return {
|
||||
tag: "downloading_minecraft"
|
||||
};
|
||||
case 10:
|
||||
return {
|
||||
tag: "running_loader_processors"
|
||||
};
|
||||
case 11:
|
||||
return {
|
||||
tag: "finalizing"
|
||||
};
|
||||
case 12:
|
||||
return {
|
||||
tag: "rolling_back"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_PROGRESS(d) {
|
||||
return {
|
||||
current: d.deserialize_number(U64_BYTES, false),
|
||||
total: d.deserialize_number(U64_BYTES, false),
|
||||
secondary: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_PROGRESS_SECONDARY(d)
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_PROGRESS_SECONDARY(d) {
|
||||
return {
|
||||
current: d.deserialize_number(U64_BYTES, false),
|
||||
total: d.deserialize_number(U64_BYTES, false)
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_PHASE_DETAILS(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "empty"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "instance",
|
||||
value: {
|
||||
name: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "minecraft",
|
||||
value: {
|
||||
game_version: d.deserialize_string(),
|
||||
loader: deserialize_MOD_LOADER(d)
|
||||
}
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "java",
|
||||
value: {
|
||||
major_version: d.deserialize_number(U32_BYTES, false),
|
||||
step: deserialize_INSTALL_JAVA_STEP(d)
|
||||
}
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "modpack",
|
||||
value: {
|
||||
project_id: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
version_id: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
title: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
}
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "import",
|
||||
value: {
|
||||
launcher_type: deserialize_IMPORT_LAUNCHER_TYPE(d),
|
||||
instance_folder: d.deserialize_string()
|
||||
}
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_JAVA_STEP(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "resolving"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "fetching_metadata"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "downloading"
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "extracting"
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "validating"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_JOB_DISPLAY(d) {
|
||||
return {
|
||||
title: d.deserialize_string(),
|
||||
icon: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_ERROR_VIEW(d) {
|
||||
return {
|
||||
code: d.deserialize_string(),
|
||||
phase: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_PHASE_ID(d),
|
||||
message: d.deserialize_string(),
|
||||
reason: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_SHARED_INSTANCE_UNAVAILABLE_REASON(d),
|
||||
api: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_API_ERROR_DETAILS(d),
|
||||
context: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : deserialize_INSTALL_ERROR_CONTEXT(d)
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_API_ERROR_DETAILS(d) {
|
||||
return {
|
||||
error: d.deserialize_string(),
|
||||
status: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_number(U16_BYTES, false),
|
||||
method: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
url: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
route: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_INSTALL_ERROR_CONTEXT(d) {
|
||||
return {
|
||||
operation: d.deserialize_string(),
|
||||
source_path: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
target_path: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
file_path: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
entry_path: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
urls: d.deserialize_array(() => d.deserialize_string()),
|
||||
expected_hash: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
expected_size: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_number(U64_BYTES, false),
|
||||
project_id: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
version_id: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
minecraft_version: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
loader: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
java_version: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_number(U32_BYTES, false),
|
||||
os: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string(),
|
||||
arch: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_string()
|
||||
};
|
||||
}
|
||||
|
||||
function deserialize_IMPORT_LAUNCHER_TYPE(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "MultiMC"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "PrismLauncher"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "ATLauncher"
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "GDLauncher"
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "Curseforge"
|
||||
};
|
||||
case 5:
|
||||
return {
|
||||
tag: "Unknown"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_MOD_LOADER(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "vanilla"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "forge"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "fabric"
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
tag: "quilt"
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
tag: "neoforge"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize_SHARED_INSTANCE_UNAVAILABLE_REASON(d) {
|
||||
switch (d.deserialize_number(U32_BYTES, false)) {
|
||||
case 0:
|
||||
return {
|
||||
tag: "deleted"
|
||||
};
|
||||
case 1:
|
||||
return {
|
||||
tag: "access_revoked"
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
tag: "quarantined"
|
||||
};
|
||||
default:
|
||||
throw "variant not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a value from an array of bytes.
|
||||
* @param {string} type - The type of the value to deserialize.
|
||||
* @param {Uint8Array} bytes - The byte array to deserialize from.
|
||||
* @return {Object} The deserialized value and remaining bytes.
|
||||
*/
|
||||
function deserialize(type, bytes) {
|
||||
if (!(typeof type === "string")) {
|
||||
throw "type must be a string";
|
||||
}
|
||||
const d = new Deserializer(bytes);
|
||||
var return_value = undefined;
|
||||
switch (type) {
|
||||
case "AppEvent":
|
||||
return_value = deserialize_APP_EVENT(d);
|
||||
break;
|
||||
case "LoadingBarType":
|
||||
return_value = deserialize_LOADING_BAR_TYPE(d);
|
||||
break;
|
||||
case "LoadingPayload":
|
||||
return_value = deserialize_LOADING_PAYLOAD(d);
|
||||
break;
|
||||
case "WarningPayload":
|
||||
return_value = deserialize_WARNING_PAYLOAD(d);
|
||||
break;
|
||||
case "InstanceBulkUpdateProgressPayload":
|
||||
return_value = deserialize_INSTANCE_BULK_UPDATE_PROGRESS_PAYLOAD(d);
|
||||
break;
|
||||
case "InstanceBulkUpdateProgressStage":
|
||||
return_value = deserialize_INSTANCE_BULK_UPDATE_PROGRESS_STAGE(d);
|
||||
break;
|
||||
case "CommandPayload":
|
||||
return_value = deserialize_COMMAND_PAYLOAD(d);
|
||||
break;
|
||||
case "ProcessPayload":
|
||||
return_value = deserialize_PROCESS_PAYLOAD(d);
|
||||
break;
|
||||
case "ProcessPayloadType":
|
||||
return_value = deserialize_PROCESS_PAYLOAD_TYPE(d);
|
||||
break;
|
||||
case "InstancePayload":
|
||||
return_value = deserialize_INSTANCE_PAYLOAD(d);
|
||||
break;
|
||||
case "InstancePayloadType":
|
||||
return_value = deserialize_INSTANCE_PAYLOAD_TYPE(d);
|
||||
break;
|
||||
case "FriendPayload":
|
||||
return_value = deserialize_FRIEND_PAYLOAD(d);
|
||||
break;
|
||||
case "FriendStatusPayload":
|
||||
return_value = deserialize_FRIEND_STATUS_PAYLOAD(d);
|
||||
break;
|
||||
case "LogEvent":
|
||||
return_value = deserialize_LOG_EVENT(d);
|
||||
break;
|
||||
case "LogPayload":
|
||||
return_value = deserialize_LOG_PAYLOAD(d);
|
||||
break;
|
||||
case "Log4jEvent":
|
||||
return_value = deserialize_LOG4J_EVENT(d);
|
||||
break;
|
||||
case "InstallJobSnapshot":
|
||||
return_value = deserialize_INSTALL_JOB_SNAPSHOT(d);
|
||||
break;
|
||||
case "InstallJobKind":
|
||||
return_value = deserialize_INSTALL_JOB_KIND(d);
|
||||
break;
|
||||
case "InstallJobStatus":
|
||||
return_value = deserialize_INSTALL_JOB_STATUS(d);
|
||||
break;
|
||||
case "InstallTarget":
|
||||
return_value = deserialize_INSTALL_TARGET(d);
|
||||
break;
|
||||
case "InstallPhaseId":
|
||||
return_value = deserialize_INSTALL_PHASE_ID(d);
|
||||
break;
|
||||
case "InstallProgress":
|
||||
return_value = deserialize_INSTALL_PROGRESS(d);
|
||||
break;
|
||||
case "InstallProgressSecondary":
|
||||
return_value = deserialize_INSTALL_PROGRESS_SECONDARY(d);
|
||||
break;
|
||||
case "InstallPhaseDetails":
|
||||
return_value = deserialize_INSTALL_PHASE_DETAILS(d);
|
||||
break;
|
||||
case "InstallJavaStep":
|
||||
return_value = deserialize_INSTALL_JAVA_STEP(d);
|
||||
break;
|
||||
case "InstallJobDisplay":
|
||||
return_value = deserialize_INSTALL_JOB_DISPLAY(d);
|
||||
break;
|
||||
case "InstallErrorView":
|
||||
return_value = deserialize_INSTALL_ERROR_VIEW(d);
|
||||
break;
|
||||
case "InstallApiErrorDetails":
|
||||
return_value = deserialize_INSTALL_API_ERROR_DETAILS(d);
|
||||
break;
|
||||
case "InstallErrorContext":
|
||||
return_value = deserialize_INSTALL_ERROR_CONTEXT(d);
|
||||
break;
|
||||
case "ImportLauncherType":
|
||||
return_value = deserialize_IMPORT_LAUNCHER_TYPE(d);
|
||||
break;
|
||||
case "ModLoader":
|
||||
return_value = deserialize_MOD_LOADER(d);
|
||||
break;
|
||||
case "SharedInstanceUnavailableReason":
|
||||
return_value = deserialize_SHARED_INSTANCE_UNAVAILABLE_REASON(d);
|
||||
break;
|
||||
default:
|
||||
throw "type not implemented";
|
||||
}
|
||||
return { value: return_value, bytes: d.release_bytes() };
|
||||
}
|
||||
|
||||
export {
|
||||
deserialize
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "postcard",
|
||||
"description": "Auto generated bindings for postcard format serializing and deserializing javascript to and from bytes.",
|
||||
"version": "0.0.0",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"type": "module"
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
|
||||
export async function init_ads_window(overrideShown = false) {
|
||||
return await invoke('plugin:ads|init_ads_window', {
|
||||
@@ -8,8 +7,27 @@ export async function init_ads_window(overrideShown = false) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function show_ads_window() {
|
||||
return await invoke('plugin:ads|show_ads_window', { dpr: window.devicePixelRatio })
|
||||
let adsWindowHoldUpdate = Promise.resolve()
|
||||
|
||||
async function update_ads_window_hold(acquire) {
|
||||
adsWindowHoldUpdate = adsWindowHoldUpdate
|
||||
.catch(() => {})
|
||||
.then(() =>
|
||||
invoke('plugin:ads|update_ads_window_hold', {
|
||||
acquire,
|
||||
dpr: window.devicePixelRatio,
|
||||
}),
|
||||
)
|
||||
|
||||
return await adsWindowHoldUpdate
|
||||
}
|
||||
|
||||
export async function take_ads_window_hold() {
|
||||
return await update_ads_window_hold(true)
|
||||
}
|
||||
|
||||
export async function release_ads_window_hold() {
|
||||
return await update_ads_window_hold(false)
|
||||
}
|
||||
|
||||
export async function hide_ads_window(reset) {
|
||||
@@ -28,10 +46,6 @@ export async function open_ads_consent_preferences() {
|
||||
return await invoke('plugin:ads|open_ads_consent_preferences')
|
||||
}
|
||||
|
||||
export async function ads_consent_listener(callback) {
|
||||
return await listen('ads-consent-required', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
export async function record_ads_click() {
|
||||
return await invoke('plugin:ads|record_ads_click')
|
||||
}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
Event listeners for interacting with the Rust api
|
||||
These are all async functions that return a promise that resolves to the payload object (whatever Rust is trying to deliver)
|
||||
*/
|
||||
|
||||
/*
|
||||
callback is a function that takes a single argument, which is the payload object (whatever Rust is trying to deliver)
|
||||
|
||||
You can call these to await any kind of emitted signal from Rust, and then do something with the payload object
|
||||
An example place to put this is at the start of main.js before the state is initialized- that way
|
||||
you can listen for any emitted signal from Rust and do something with it as the state is being initialized
|
||||
|
||||
Example:
|
||||
import { loading_listener } from '@/helpers/events'
|
||||
await loading_listener((event) => {
|
||||
// event.event is the event name (useful if you want to use a single callback fn for multiple event types)
|
||||
// event.payload is the payload object
|
||||
console.log(event)
|
||||
})
|
||||
|
||||
Putting that in a script will print any emitted signal from rust
|
||||
*/
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
|
||||
/// Payload for the 'loading' event
|
||||
/*
|
||||
LoadingPayload {
|
||||
event: {
|
||||
type: string, one of "StateInit", "PackDownload", etc
|
||||
(Optional fields depending on event type)
|
||||
pack_name: name of the pack
|
||||
pack_id, optional, the id of the modpack
|
||||
pack_version, optional, the version of the modpack
|
||||
instance_name: name of the instance
|
||||
instance_id: unique identification of the instance
|
||||
|
||||
}
|
||||
loader_uuid: unique identification of the loading bar
|
||||
fraction: number, (as a fraction of 1, how much we've loaded so far). If null, by convention, loading is finished
|
||||
message: message to display to the user
|
||||
}
|
||||
*/
|
||||
export async function loading_listener(callback) {
|
||||
return await listen('loading', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'process' event
|
||||
/*
|
||||
ProcessPayload {
|
||||
uuid: unique identification of the process in the state (currently identified by PID, but that will change)
|
||||
pid: process ID
|
||||
event: event type ("Launched", "Finished")
|
||||
message: message to display to the user
|
||||
}
|
||||
*/
|
||||
export async function process_listener(callback) {
|
||||
return await listen('process', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'instance' event
|
||||
/*
|
||||
InstancePayload {
|
||||
instance_id: unique identification of the instance
|
||||
event: event type ("Created", "Added", "Edited", "Removed")
|
||||
}
|
||||
*/
|
||||
export async function instance_listener(callback) {
|
||||
return await listen('instance', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'instance_bulk_update_progress' event
|
||||
/*
|
||||
InstanceBulkUpdateProgress {
|
||||
instanceId: string
|
||||
stage: "resolving_versions" | "downloading" | "finishing"
|
||||
current: number
|
||||
total: number
|
||||
}
|
||||
*/
|
||||
export async function instance_bulk_update_progress_listener(callback) {
|
||||
return await listen('instance_bulk_update_progress', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
export async function install_job_listener(callback) {
|
||||
return await listen('install_job', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'command' event
|
||||
/*
|
||||
CommandPayload {
|
||||
event: event type ("InstallMod", "InstallModpack", "InstallVersion"),
|
||||
id: string id of the mod/modpack/version to install
|
||||
}
|
||||
*/
|
||||
export async function command_listener(callback) {
|
||||
return await listen('command', (event) => {
|
||||
callback(event.payload)
|
||||
})
|
||||
}
|
||||
|
||||
/// Payload for the 'warning' event
|
||||
/*
|
||||
WarningPayload {
|
||||
message: message to display to the user
|
||||
}
|
||||
*/
|
||||
export async function warning_listener(callback) {
|
||||
return await listen('warning', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
export async function friend_listener(callback) {
|
||||
return await listen('friend', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
export async function notification_listener(callback) {
|
||||
return await listen('notification', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'log' event
|
||||
/*
|
||||
LogPayload {
|
||||
instance_id: string,
|
||||
type: "log4j" | "legacy",
|
||||
// log4j fields (when type === "log4j"):
|
||||
timestamp_millis?: number,
|
||||
logger_name?: string,
|
||||
level?: string,
|
||||
thread_name?: string,
|
||||
message?: string,
|
||||
throwable?: string,
|
||||
// legacy fields (when type === "legacy"):
|
||||
message?: string,
|
||||
}
|
||||
*/
|
||||
export async function log_listener(callback) {
|
||||
return await listen('log', (event) => callback(event.payload))
|
||||
}
|
||||
@@ -1,8 +1,28 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { install_job_listener } from './events'
|
||||
import type { InstallErrorView } from '@/generated/app-events/InstallErrorView'
|
||||
import type { InstallJavaStep } from '@/generated/app-events/InstallJavaStep'
|
||||
import type { InstallJobSnapshot } from '@/generated/app-events/InstallJobSnapshot'
|
||||
import type { InstallJobStatus } from '@/generated/app-events/InstallJobStatus'
|
||||
import type { InstallPhaseId } from '@/generated/app-events/InstallPhaseId'
|
||||
import type { InstallProgress } from '@/generated/app-events/InstallProgress'
|
||||
import type { InstallProgressSecondary } from '@/generated/app-events/InstallProgressSecondary'
|
||||
import type { SharedInstanceUnavailableReason } from '@/generated/app-events/SharedInstanceUnavailableReason'
|
||||
import type { AppEvents } from '@/providers/app-events'
|
||||
|
||||
import type { InstanceLink, InstanceLoader } from './types'
|
||||
|
||||
export type {
|
||||
InstallErrorView,
|
||||
InstallJavaStep,
|
||||
InstallJobSnapshot,
|
||||
InstallJobStatus,
|
||||
InstallPhaseId,
|
||||
InstallProgress,
|
||||
InstallProgressSecondary,
|
||||
SharedInstanceUnavailableReason,
|
||||
}
|
||||
|
||||
export interface PackLocationVersionId {
|
||||
type: 'fromVersionId'
|
||||
project_id: string
|
||||
@@ -104,8 +124,6 @@ export interface SharedInstanceUpdateDiff {
|
||||
export const SHARED_INSTANCE_UNAVAILABLE_ERROR_CODE = 'shared_instance_unavailable'
|
||||
export const SHARED_INSTANCES_API_ERROR_CODE = 'shared_instances_api_error'
|
||||
|
||||
export type SharedInstanceUnavailableReason = 'deleted' | 'access_revoked' | 'quarantined'
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null
|
||||
}
|
||||
@@ -136,116 +154,6 @@ export function getErrorMessage(error: unknown): string {
|
||||
return 'Unknown error'
|
||||
}
|
||||
|
||||
export type InstallJobStatus =
|
||||
| 'queued'
|
||||
| 'running'
|
||||
| 'succeeded'
|
||||
| 'failed'
|
||||
| 'interrupted'
|
||||
| 'canceled'
|
||||
|
||||
export type InstallPhaseId =
|
||||
| 'preparing_instance'
|
||||
| 'resolving_pack'
|
||||
| 'downloading_pack_file'
|
||||
| 'reading_pack_manifest'
|
||||
| 'downloading_content'
|
||||
| 'extracting_overrides'
|
||||
| 'resolving_minecraft'
|
||||
| 'resolving_loader'
|
||||
| 'preparing_java'
|
||||
| 'downloading_minecraft'
|
||||
| 'running_loader_processors'
|
||||
| 'finalizing'
|
||||
| 'rolling_back'
|
||||
|
||||
export interface InstallProgress {
|
||||
current: number
|
||||
total: number
|
||||
secondary?: InstallProgressSecondary | null
|
||||
}
|
||||
|
||||
export interface InstallProgressSecondary {
|
||||
current: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type InstallJavaStep =
|
||||
| 'resolving'
|
||||
| 'fetching_metadata'
|
||||
| 'downloading'
|
||||
| 'extracting'
|
||||
| 'validating'
|
||||
|
||||
export interface InstallErrorView {
|
||||
code: string
|
||||
phase?: InstallPhaseId | null
|
||||
message: string
|
||||
reason?: SharedInstanceUnavailableReason | null
|
||||
api?: {
|
||||
error: string
|
||||
status?: number | null
|
||||
method?: string | null
|
||||
url?: string | null
|
||||
route?: string | null
|
||||
} | null
|
||||
context?: {
|
||||
operation: string
|
||||
source_path?: string | null
|
||||
target_path?: string | null
|
||||
file_path?: string | null
|
||||
entry_path?: string | null
|
||||
urls?: string[]
|
||||
expected_hash?: string | null
|
||||
expected_size?: number | null
|
||||
project_id?: string | null
|
||||
version_id?: string | null
|
||||
minecraft_version?: string | null
|
||||
loader?: string | null
|
||||
java_version?: number | null
|
||||
os?: string | null
|
||||
arch?: string | null
|
||||
} | null
|
||||
}
|
||||
|
||||
export interface InstallJobSnapshot {
|
||||
job_id: string
|
||||
instance_id?: string | null
|
||||
kind:
|
||||
| 'create_instance'
|
||||
| 'create_modpack_instance'
|
||||
| 'create_shared_instance'
|
||||
| 'update_shared_instance'
|
||||
| 'import_instance'
|
||||
| 'duplicate_instance'
|
||||
| 'install_existing_instance'
|
||||
| 'install_pack_to_existing_instance'
|
||||
status: InstallJobStatus
|
||||
target:
|
||||
| { type: 'new_instance'; instance_id?: string | null }
|
||||
| { type: 'existing_instance'; instance_id: string }
|
||||
phase: InstallPhaseId
|
||||
progress?: InstallProgress | null
|
||||
details:
|
||||
| { type: 'empty' }
|
||||
| { type: 'instance'; name: string }
|
||||
| { type: 'minecraft'; game_version: string; loader: InstanceLoader }
|
||||
| { type: 'java'; major_version: number; step: InstallJavaStep }
|
||||
| {
|
||||
type: 'modpack'
|
||||
project_id?: string | null
|
||||
version_id?: string | null
|
||||
title?: string | null
|
||||
}
|
||||
| { type: 'import'; launcher_type: string; instance_folder: string }
|
||||
display?: { title: string; icon?: string | null } | null
|
||||
error?: InstallErrorView | null
|
||||
rollback_error?: InstallErrorView | null
|
||||
created: string
|
||||
modified: string
|
||||
finished?: string | null
|
||||
}
|
||||
|
||||
export async function install_get_modpack_preview(location: CreatePackLocation) {
|
||||
return await invoke<InstallModpackPreview>('plugin:install|install_get_modpack_preview', {
|
||||
location,
|
||||
@@ -399,7 +307,7 @@ function settleInstallJob(job: InstallJobSnapshot) {
|
||||
throw new Error(`Install job ${job.job_id} ${job.status}`)
|
||||
}
|
||||
|
||||
export async function wait_for_install_job(jobId: string) {
|
||||
export async function wait_for_install_job(events: AppEvents, jobId: string) {
|
||||
const current = await install_job_get(jobId)
|
||||
if (isInstallJobFinished(current.status)) return settleInstallJob(current)
|
||||
|
||||
@@ -434,16 +342,7 @@ export async function wait_for_install_job(jobId: string) {
|
||||
reject(err)
|
||||
}
|
||||
|
||||
install_job_listener(resolveJob)
|
||||
.then((listener) => {
|
||||
if (finished) {
|
||||
listener()
|
||||
return
|
||||
}
|
||||
|
||||
unlisten = listener
|
||||
install_job_get(jobId).then(resolveJob).catch(rejectWait)
|
||||
})
|
||||
.catch(rejectWait)
|
||||
unlisten = events.on('install_job', resolveJob)
|
||||
install_job_get(jobId).then(resolveJob).catch(rejectWait)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import type {
|
||||
ContentItem,
|
||||
ContentModpackCardCategory,
|
||||
ContentModpackCardProject,
|
||||
ContentModpackCardVersion,
|
||||
ContentOwner,
|
||||
} from '@modrinth/ui'
|
||||
import type { ContentItem, ManagedContentProject, ManagedContentVersion } from '@modrinth/ui'
|
||||
|
||||
import {
|
||||
get_content_items,
|
||||
get_linked_modpack_info,
|
||||
type LinkedModpackInfo,
|
||||
} from '@/helpers/instance'
|
||||
import { get_categories } from '@/helpers/tags.js'
|
||||
import type { CacheBehaviour } from '@/helpers/types'
|
||||
|
||||
export type InstanceContentData = {
|
||||
@@ -21,11 +14,8 @@ export type InstanceContentData = {
|
||||
}
|
||||
|
||||
export type InstanceContentModpackData = {
|
||||
project: ContentModpackCardProject
|
||||
version: ContentModpackCardVersion
|
||||
owner: ContentOwner | null
|
||||
categories: ContentModpackCardCategory[]
|
||||
hasUpdate: boolean
|
||||
project: ManagedContentProject
|
||||
version: ManagedContentVersion
|
||||
updateVersionId: string | null
|
||||
}
|
||||
|
||||
@@ -34,19 +24,15 @@ export async function loadInstanceContentData(
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
onError?: (error: Error) => unknown,
|
||||
): Promise<InstanceContentData> {
|
||||
const [contentItems, modpackInfo, allCategories] = await Promise.all([
|
||||
const [contentItems, modpackInfo] = await Promise.all([
|
||||
get_content_items(path, cacheBehaviour).catch((error) => handleLoadError(error, onError)),
|
||||
get_linked_modpack_info(path, cacheBehaviour).catch((error) => handleLoadError(error, onError)),
|
||||
get_categories().catch((error) => handleLoadError(error, onError)),
|
||||
])
|
||||
|
||||
return {
|
||||
path,
|
||||
contentItems: (contentItems as ContentItem[] | null | undefined) ?? null,
|
||||
modpack: normalizeLinkedModpackInfo(
|
||||
modpackInfo as LinkedModpackInfo | null | undefined,
|
||||
allCategories as ContentModpackCardCategory[] | null | undefined,
|
||||
),
|
||||
modpack: normalizeLinkedModpackInfo(modpackInfo as LinkedModpackInfo | null | undefined),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +44,6 @@ function handleLoadError(error: unknown, onError?: (error: Error) => unknown) {
|
||||
|
||||
function normalizeLinkedModpackInfo(
|
||||
modpackInfo: LinkedModpackInfo | null | undefined,
|
||||
allCategories: ContentModpackCardCategory[] | null | undefined,
|
||||
): InstanceContentModpackData | null {
|
||||
if (!modpackInfo) return null
|
||||
|
||||
@@ -72,30 +57,6 @@ function normalizeLinkedModpackInfo(
|
||||
...modpackInfo.version,
|
||||
date_published: modpackInfo.version.date_published.toString(),
|
||||
},
|
||||
owner: modpackInfo.owner
|
||||
? {
|
||||
...modpackInfo.owner,
|
||||
avatar_url: modpackInfo.owner.avatar_url ?? undefined,
|
||||
}
|
||||
: null,
|
||||
categories: resolveLinkedModpackCategories(modpackInfo, allCategories),
|
||||
hasUpdate: modpackInfo.has_update,
|
||||
updateVersionId: modpackInfo.update_version_id,
|
||||
}
|
||||
}
|
||||
|
||||
function resolveLinkedModpackCategories(
|
||||
modpackInfo: LinkedModpackInfo,
|
||||
allCategories: ContentModpackCardCategory[] | null | undefined,
|
||||
) {
|
||||
if (!allCategories || !modpackInfo.project.categories) return []
|
||||
|
||||
const seen = new Set<string>()
|
||||
return allCategories.filter((category) => {
|
||||
if (modpackInfo.project.categories.includes(category.name) && !seen.has(category.name)) {
|
||||
seen.add(category.name)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import type { ContentItem, ContentOwner } from '@modrinth/ui'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { convertFileSrc, invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import type { InstallJobSnapshot, SharedInstanceUpdateDiff } from './install'
|
||||
import type {
|
||||
@@ -74,7 +74,11 @@ export async function get_content_items(
|
||||
instanceId: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:instance|instance_get_content_items', { instanceId, cacheBehaviour })
|
||||
const items = await invoke<ContentItem[]>('plugin:instance|instance_get_content_items', {
|
||||
instanceId,
|
||||
cacheBehaviour,
|
||||
})
|
||||
return adaptContentItems(items)
|
||||
}
|
||||
|
||||
export async function refresh_content_updates(instanceId: string): Promise<void> {
|
||||
@@ -111,10 +115,11 @@ export async function get_linked_modpack_content(
|
||||
instanceId: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:instance|instance_get_linked_modpack_content', {
|
||||
const items = await invoke<ContentItem[]>('plugin:instance|instance_get_linked_modpack_content', {
|
||||
instanceId,
|
||||
cacheBehaviour,
|
||||
})
|
||||
return adaptContentItems(items)
|
||||
}
|
||||
|
||||
// Convert a list of dependencies into ContentItems with rich metadata
|
||||
@@ -122,9 +127,28 @@ export async function get_dependencies_as_content_items(
|
||||
dependencies: Labrinth.Versions.v3.Dependency[],
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:instance|instance_get_dependencies_as_content_items', {
|
||||
dependencies,
|
||||
cacheBehaviour,
|
||||
const items = await invoke<ContentItem[]>(
|
||||
'plugin:instance|instance_get_dependencies_as_content_items',
|
||||
{
|
||||
dependencies,
|
||||
cacheBehaviour,
|
||||
},
|
||||
)
|
||||
return adaptContentItems(items)
|
||||
}
|
||||
|
||||
function adaptContentItems(items: ContentItem[]): ContentItem[] {
|
||||
return items.map((item) => {
|
||||
const embeddedMetadata = item.embedded_metadata
|
||||
if (!embeddedMetadata?.icon_path) return item
|
||||
|
||||
return {
|
||||
...item,
|
||||
embedded_metadata: {
|
||||
...embeddedMetadata,
|
||||
icon_url: convertFileSrc(embeddedMetadata.icon_path),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -264,6 +288,18 @@ export async function toggle_disable_project(
|
||||
})
|
||||
}
|
||||
|
||||
export async function set_project_locked(
|
||||
instanceId: string,
|
||||
projectPath: string,
|
||||
locked: boolean,
|
||||
): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_set_project_locked', {
|
||||
instanceId,
|
||||
projectPath,
|
||||
locked,
|
||||
})
|
||||
}
|
||||
|
||||
// Remove a project
|
||||
export async function remove_project(instanceId: string, projectPath: string): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_remove_project', { instanceId, projectPath })
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { type Channel, invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import type { AppEvent } from '@/generated/app-events/AppEvent'
|
||||
|
||||
export interface LoadingBarType {
|
||||
type?: string
|
||||
@@ -24,24 +26,12 @@ export interface LoadingBar {
|
||||
bar_type?: LoadingBarType
|
||||
}
|
||||
|
||||
export type OpeningCommandEvent =
|
||||
| 'RunMRPack'
|
||||
| 'InstallServer'
|
||||
| 'InstallVersion'
|
||||
| 'InstallMod'
|
||||
| 'InstallModpack'
|
||||
| string
|
||||
|
||||
export interface OpeningCommand {
|
||||
event: OpeningCommandEvent
|
||||
id?: string
|
||||
path?: string
|
||||
}
|
||||
export type OpeningCommand = Extract<AppEvent, { type: 'command' }>['payload']
|
||||
|
||||
// Initialize the theseus API state
|
||||
// This should be called during the initializion/opening of the launcher
|
||||
export async function initialize_state() {
|
||||
return await invoke<void>('initialize_state')
|
||||
export async function initialize_state(events: Channel<ArrayBuffer>) {
|
||||
return await invoke<void>('initialize_state', { events })
|
||||
}
|
||||
|
||||
// Gets active progress bars
|
||||
|
||||
+1
@@ -128,6 +128,7 @@ export type ContentSourceKind =
|
||||
|
||||
type ContentFile = {
|
||||
enabled: boolean
|
||||
locked: boolean
|
||||
source_kind?: ContentSourceKind | null
|
||||
metadata?: {
|
||||
project_id: string
|
||||
|
||||
@@ -3,6 +3,7 @@ import { autoToHTML } from '@sfirew/minecraft-motd-parser'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import type { InstancePayload } from '@/generated/app-events/InstancePayload'
|
||||
import { get_full_path } from '@/helpers/instance'
|
||||
import { openPath } from '@/helpers/utils'
|
||||
|
||||
@@ -532,18 +533,4 @@ export function hasWorldQuickPlaySupport(gameVersions: GameVersion[], currentVer
|
||||
return versionIndex !== -1 && targetIndex !== -1 && versionIndex <= targetIndex
|
||||
}
|
||||
|
||||
export type InstanceEvent = { instance_id: string } & (
|
||||
| {
|
||||
event: 'servers_updated'
|
||||
}
|
||||
| {
|
||||
event: 'world_updated'
|
||||
world: string
|
||||
}
|
||||
| {
|
||||
event: 'server_joined'
|
||||
host: string
|
||||
port: number
|
||||
timestamp: string
|
||||
}
|
||||
)
|
||||
export type InstanceEvent = InstancePayload
|
||||
|
||||
@@ -1073,16 +1073,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "مزامنة مع النسخة"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "يقدمها الخادم"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "يمكن إضافة التعديلات **المحليه** فقط إلى نموذج الخادم"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "يتم توفير نسخة اللعبة من قبل الخادم"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "يتم توفير المحمّل من قبل الخادم"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,16 +965,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synchronizováno s instancí"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Poskytováno serverem"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Pouze módy ze strany klientu mohou být přidány na server"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Verze hry je poskytována serverem"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader zprostředkovává server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,18 +296,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Gennemså ændringer"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Gennemgå opdatering"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Gennemgår..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "En opdatering er krævet for at spille {name}. Venligst opdater til den seneste version for at køre spillet."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "En opdatering er tilgængelig"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Al' data for din instance vil blive permanent slettet, dette inkludere dine verdener, konfigurationer, og alt installeret indhold."
|
||||
},
|
||||
@@ -470,9 +461,6 @@
|
||||
"app.modal.install-to-play.report-image-too-large": {
|
||||
"message": "Filen overskrider 1MiB størrelse begrænsning"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Delt instance"
|
||||
},
|
||||
@@ -1181,16 +1169,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synkroniser med instance"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Givet af serveren"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Kun klient-sided mods kan blive tilføjet til denne server instance"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spille version er givet af serveren"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader er givet af serveren"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Änderungen überprüfen"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Update überprüfen"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Wird überprüft..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Ein Update ist erforderlich, um {name} zu spielen. Bitte aktualisiere auf die neueste Version, um das Spiel zu starten."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Ein Update ist verfügbar"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle Daten deiner Instanz werden permanent gelöscht, inlusive deiner Welten, Konfigurationen und allen installierten Inhalten."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Gegen welche Regel verstößt diese Instanz?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Unangemessen"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Bösartig"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Geteilte Instanz melden"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Mit Instanz synchronisieren"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Vom Server bereitgestellt"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Nur Clientseitige Mods können der Serverinstanz hinzugefügt werden"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spielversion wird vom Server bereitgestellt"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader wird vom Server bereitgestellt"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Konto"
|
||||
},
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Änderungen überprüfen"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Update überprüfen"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Wird überprüft..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Ein Update ist erforderlich, um {name} zu spielen. Bitte aktualisiere auf die neueste Version, um das Spiel zu starten."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Ein Update ist verfügbar"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle Daten deiner Instanz werden permanent gelöscht, einschließlich deiner Welten, Konfigurationen und allen installierten Inhalten."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Gegen welche Regel verstößt diese Instanz?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Unangemessen"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Bösartig"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Geteilte Instanz melden"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Mit Instanz synchronisieren"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Vom Server vorgegeben"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Nur clientseitige Mods können der Serverinstanz hinzugefügt werden"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spielversion vom Server vorgegeben"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader vom Server vorgegeben"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Konto"
|
||||
},
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
"app.action-bar.downloads": {
|
||||
"message": "Downloads"
|
||||
},
|
||||
"app.action-bar.hide-downloads": {
|
||||
"message": "Hide active downloads"
|
||||
},
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Hide more running instances"
|
||||
},
|
||||
@@ -110,6 +113,9 @@
|
||||
"app.action-bar.reload-to-update": {
|
||||
"message": "Reload to update"
|
||||
},
|
||||
"app.action-bar.show-downloads": {
|
||||
"message": "Show active downloads"
|
||||
},
|
||||
"app.action-bar.show-more-running-instances": {
|
||||
"message": "Show more running instances"
|
||||
},
|
||||
@@ -267,7 +273,7 @@
|
||||
"message": "Modpacks"
|
||||
},
|
||||
"app.browse.server-instance-content-warning": {
|
||||
"message": "Adding content can break compatibility when joining the server. Any added content will also be lost when you update the server instance content."
|
||||
"message": "Adding content may prevent you from joining this server. Any content you add will be removed when the managed server content is updated."
|
||||
},
|
||||
"app.browse.server.installing": {
|
||||
"message": "Installing"
|
||||
@@ -281,6 +287,12 @@
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Export"
|
||||
},
|
||||
"app.export-modal.export-complete": {
|
||||
"message": "Export complete"
|
||||
},
|
||||
"app.export-modal.export-complete-description": {
|
||||
"message": "{name} was exported successfully."
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Export modpack"
|
||||
},
|
||||
@@ -296,6 +308,18 @@
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.hosting.update-required.description": {
|
||||
"message": "You need to update to use Modrinth Hosting through the Modrinth App"
|
||||
},
|
||||
"app.hosting.update-required.download": {
|
||||
"message": "Download to update"
|
||||
},
|
||||
"app.hosting.update-required.rinthbot-alt": {
|
||||
"message": "Excited Modrinth Bot"
|
||||
},
|
||||
"app.hosting.update-required.title": {
|
||||
"message": "Modrinth App update required"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Downloading content"
|
||||
},
|
||||
@@ -377,18 +401,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Review changes"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Review update"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Reviewing..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "An update is required to play {name}. Please update to latest version to launch the game."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "An update is available"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "All data for your instance will be permanently deleted, including your worlds, configs, and all installed content."
|
||||
},
|
||||
@@ -401,6 +416,12 @@
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Delete instance"
|
||||
},
|
||||
"app.instance.content.managed-content.modpack-header": {
|
||||
"message": "Modpack content"
|
||||
},
|
||||
"app.instance.content.managed-content.shared-header": {
|
||||
"message": "Shared content"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "This modpack is already installed in the <bold>{instanceName}</bold> instance. Are you sure you want to duplicate it?"
|
||||
},
|
||||
@@ -425,6 +446,9 @@
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "project"
|
||||
},
|
||||
"app.instance.mods.freeze-content": {
|
||||
"message": "Freeze version"
|
||||
},
|
||||
"app.instance.mods.locked-content": {
|
||||
"message": "Content in locked instances cannot be changed."
|
||||
},
|
||||
@@ -443,6 +467,9 @@
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Successfully uploaded"
|
||||
},
|
||||
"app.instance.mods.unfreeze-content": {
|
||||
"message": "Unfreeze version"
|
||||
},
|
||||
"app.instance.share.empty.description": {
|
||||
"message": "You can share this instance with your friends!"
|
||||
},
|
||||
@@ -686,6 +713,9 @@
|
||||
"app.modal.install-to-play.invite-warning-with-creator": {
|
||||
"message": "This invite was created by <creator>{username}</creator>, not Modrinth. Only accept invites from people you trust."
|
||||
},
|
||||
"app.modal.install-to-play.managed-content.modpack-header": {
|
||||
"message": "Modpack content"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
@@ -704,15 +734,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Which rule does this instance violate?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Inappropriate"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Malicious"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Report shared instance"
|
||||
},
|
||||
@@ -1457,6 +1478,9 @@
|
||||
"instance.files.save-as": {
|
||||
"message": "Save as..."
|
||||
},
|
||||
"instance.last-played": {
|
||||
"message": "Last played"
|
||||
},
|
||||
"instance.locked.delete-button": {
|
||||
"message": "Delete instance"
|
||||
},
|
||||
@@ -1922,18 +1946,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sync with instance"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Provided by the server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Only client-side mods can be added to the server instance"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Game version is provided by the server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader is provided by the server"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Account"
|
||||
},
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Revisar cambios"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Actualizar"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Actualizando..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Se necesita una actualización para jugar a {name}. Por favor actualiza a la versión más reciente para iniciar el juego."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Hay una actualización disponible"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Todos los datos de tu instancia se eliminarán permanentemente, incluidos tus mundos, configuraciones y todo el contenido instalado."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "¿Qué regla rompe esta instancia?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Inapropiado"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Malicioso"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Reportar instancia compartida"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar con la instancia"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Proporcionado por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Solo se pueden añadir mods que sean del lado del cliente a la instancia del servidor"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "La versión del juego es proporcionada por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "El loader es proporcionado por el servidor"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Cuenta"
|
||||
},
|
||||
|
||||
@@ -878,16 +878,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar con la instancia"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Proporcionado por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Solo se pueden añadir a la instancia del servidor modificaciones del lado del cliente"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "La versión del juego es proporcionada por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader proporcionado por el servidor"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -959,16 +959,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synkronoi instanssin kanssa"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Palvelimen tarjoama"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Voit lisätä vain paikallisia modeja palvelin instanssiin"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Peliversio on palvelimen tarjoama"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Modialusta on palvelimen tarjoama"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,16 +659,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Maki-sync sa instansiya"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Handog ng server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Mga mod sa panig ng client lamang ang maidadaragdag sa instansiyang server"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Ang bersiyon ng laro ay handog ng server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Ang loader ay handog na ng server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Examiner les modifications"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Télécharger la mise à jour"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Examination..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Une mise à jour est nécessaire pour jouer à {name}. Veuillez mettre à jour vers la dernière version pour lancer le jeu."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Une mise à jour est disponible"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Toutes les données pour votre instance seront supprimées à jamais, y compris vos mondes, vos configurations, et le contenu installé."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Quelle règle cette instance enfreint-elle ?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Inapproprié"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Malicieux"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Signaler une instance partagée"
|
||||
},
|
||||
@@ -1919,18 +1901,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synchroniser avec l'instance"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Fournis par le serveur"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Seuls les mods client peuvent être ajoutés à l'instance du serveur"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Version du jeu est procurée par le serveur"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Le loader est procuré par le serveur"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Compte"
|
||||
},
|
||||
|
||||
@@ -533,16 +533,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "סנכרן עם התקנה"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "מסופק על ידי השרת"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "ניתן להוסיף רק מודים בצד הלקוח לשרת"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "גרסת המשחק מסופקת על ידי השרת"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "הטוען מסופק על ידי השרת"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Változtatások áttekintése"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Frissítés áttekintése"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Áttekintés..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Egy frssítés szükséges a(z) {name} példányhoz. Kérjük, frissítsd a játékot a legújabb verzióra az indításhoz."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Frissítés érhető el"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "A példányodhoz tartozó összes adat véglegesen törlődik, beleértve a világjaidat, a beállításaidat és az összes telepített tartalmat."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Melyik szabályt sérti ez az adott példány?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Nem megfelelő"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Káros"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Megosztott példány jelentése"
|
||||
},
|
||||
@@ -1907,18 +1889,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Szinkronizálás a példánnyal"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "A szerver által van megadva"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Szerverpéldányokhoz csak szerveroldali modok adhatók hozzá"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "A játékverzió a szerver által van megadva"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "A betöltőt az adott szerver biztosítja"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Fiók"
|
||||
},
|
||||
|
||||
@@ -821,16 +821,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sinkronkan dengan instans"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Disediakan oleh server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Anda hanya dapat menambahkan mod sisi klien pada instans server"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Versi permainan disediakan oleh server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Pemuat disediakan oleh server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Revisiona modifiche"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Revisiona aggiornamento"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Revisione..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "{name} richiede degli aggiornamenti. Installa l'ultima versione per poter giocare."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Aggiornamento disponibile"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Tutti i dati della tua istanza verranno eliminati permanentemente, inclusi i tuoi mondi, configurazioni e tutti i contenuti installati."
|
||||
},
|
||||
@@ -701,15 +692,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Quale regola è violata da quest'istanza?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Inappropriato"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Dannoso"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Segnala istanza condivisa"
|
||||
},
|
||||
@@ -1919,18 +1901,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizza con l'istanza"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Determinato dal server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Solo mod lato client possono essere aggiunte all'istanza del server"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "La versione del gioco è determinata dal server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Il loader è determinato dal server"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Account"
|
||||
},
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "変更点を確認"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "アップデート内容を確認"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "審査中…"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "{name}をプレイするにはアップデートが必要です。ゲームを起動するには最新バージョンにアップデートしてください。"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "アップデートが利用可能です"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "インスタンス内のすべてのデータは、ワールド、設定、インストール済みのコンテンツを含め、完全に削除されます。"
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "この起動構成はどの規則に違反していますか?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "不適切なコンテンツ"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "悪意がある"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "スパム"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "共有された起動構成を通報する"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "インスタンスと同期"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "サーバーによる条件"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "サーバーインスタンスにはクライアント側Modのみ追加可能"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "ゲームバージョンはサーバーによる条件です"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "ローダーはサーバーによる条件です"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "アカウント"
|
||||
},
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Review changes"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "업데이트 검토"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "검토중..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "{name} 플레이를 위해 업데이트가 필요합니다. 게임을 실행하려면 최신 버전 업데이트를 진행하세요."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "업데이트가 있습니다"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "인스턴스의 모든 데이터가 삭제됩니다. 세계 폴더, 설정 폴더 등 설치된 모든 컨텐츠가 포함됩니다."
|
||||
},
|
||||
@@ -701,15 +692,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "이 인스턴스가 위반한 규칙은 무엇인가요?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "부적절함"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "악성/유해함"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "스팸"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "공유 인스턴스 신고"
|
||||
},
|
||||
@@ -1895,18 +1877,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "인스턴스와 동기화"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "서버에 의해 관리됨"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "서버 인스턴스에는 클라이언트 전용 모드만 추가할 수 있습니다"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "게임 버전이 서버에 의해 제공됩니다"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "로더가 서버에 의해 제공됩니다"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "계정"
|
||||
},
|
||||
|
||||
@@ -245,9 +245,6 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, other {# mod}}"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Pemasangan yang dikongsi"
|
||||
},
|
||||
@@ -818,16 +815,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Selaraskan dengan pemasangan"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Disediakan oleh pelayan"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Hanya mod bahagian pelanggan sahaja yang boleh ditambah pada pemasangan pelayan"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Versi permainan adalah disediakan oleh pelayan"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Pemuat adalah disediakan oleh pelayan"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Wijzigingen bekijken"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Update bekijken"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Controleren..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Er is een update nodig om {name} te kunnen spelen. Werk het spel bij naar de nieuwste versie om het te kunnen starten."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Update is beschikbaar"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle gegevens van je instantie worden definitief verwijderd, inclusief je werelden, configuraties en alle geïnstalleerde inhoud."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Welke regel wordt in deze instantie overtreden?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Ongepast"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Kwaadaardig"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Gedeelde instantie melden"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synchroniseer installatie"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Aangeleverd door de server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Alleen client-side mods kunnen toegevoegd worden aan de server instantie"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spel versie is gegeven door de server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader is gegeven door de server"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Account"
|
||||
},
|
||||
|
||||
@@ -371,15 +371,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Sprawdź zmiany"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Sprawdź aktualizację"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Trwa przegląd..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Dostępna aktualizacja"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Wszystkie dane z Twojej instancji zostaną trwale usunięte, w tym Twoje światy, pliki konfiguracji i jakakolwiek dodana zawartość."
|
||||
},
|
||||
@@ -668,15 +662,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Którą zasadę narusza ta instancja?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Treści nieodpowiednie"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Zawiera Złośliwy kod"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Zgłoś przesłaną Instalacje"
|
||||
},
|
||||
@@ -1703,18 +1688,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synchronizuj z instancją"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Dostarczone przez serwer"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Tylko mody po stronie klienta mogą być dodane do instancji serwera"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Wersja gry jest dostarczona przez serwer"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader jest dostarczony przez serwer"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Konto"
|
||||
},
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Revisar alterações"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Revisar atualização"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Revisando..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Uma atualização é necessária para jogar {name}. Atualize para a versão mais recente para iniciar o jogo."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Uma atualização está disponível"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Todos os dados para sua instância serão excluídos permanentemente, incluindo seus mundos, configs e todo o conteúdo instalado."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Qual regra esta instância viola?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Inapropriado"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Malicioso"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Denunciar instância compartilhada"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar com a instância"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Fornecido pelo servidor"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Somente mods do cliente podem ser adicionados à instância do servidor"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "A versão do jogo é fornecida pelo servidor"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "O loader é fornecido pelo servidor"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Conta"
|
||||
},
|
||||
|
||||
@@ -872,16 +872,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar com a instância"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Fornecido pelo servidor"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Apenas mods no cliente podem ser adicionados à instância de servidor"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Versão do jogo é fornecida pelo servidor"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Carregador é fornecido pelo servidor"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,16 +506,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizează cu instanța"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Furnizat de server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Numai modurile de pe partea clientului pot fi adăugate la instanța serverului"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Versiunea jocului este furnizată de server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Încărcătorul este furnizat de server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Проверьте изменения"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Обзор обновления"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Проверка..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Необходимо обновление для игры в {name}. Обновитесь до последней версии и запустите игру."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Доступно обновление"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Все данные сборки будут удалены навсегда, в том числе миры, настройки и весь установленный контент."
|
||||
},
|
||||
@@ -695,15 +686,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Какое правило нарушает данная сборка?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Неприемлемое содержимое"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Вредоносное содержимое"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Спам"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Сообщить об общем экземпляре"
|
||||
},
|
||||
@@ -1910,18 +1892,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Использовать из сборки"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Управляется сервером"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "В серверной сборке доступны только клиентские моды"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Версия игры управляется сервером"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Загрузчик управляется сервером"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Аккаунт"
|
||||
},
|
||||
|
||||
@@ -1100,16 +1100,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sinhroniziraj sa instancom"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Obezbeđeno od servera"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Samo modovi za kliente mogu biti dodani na instancu servera"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Verzije igre je obezbeđena od servera"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Učitavač je obezbeđen od servera"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,18 +359,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Granskar ändringar"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Granska uppdatering"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Granskar..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "En uppdatering krävs för att spela {name}. Vänligen uppdatera till den senaste verisoner för att köra spelet."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "En uppdatering finns tillgänglig"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "All data från din instans kommer permanent raderas, däribland dina världar, konfigurationer samt allt installerat innehåll."
|
||||
},
|
||||
@@ -683,15 +674,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Vilken regel bryter instansen mot?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Olämplig"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Skadlig"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Rapportera delad instans"
|
||||
},
|
||||
@@ -1718,18 +1700,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synkronisera med instansen"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Tillhandahållet av servern"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Endast klient-sido moddar kan läggas till i serverinstansen"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spelversion tillhandahålls av servern"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader tillhandahålls av servern"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Konto"
|
||||
},
|
||||
|
||||
@@ -785,16 +785,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "เชื่อมต่อกับโปรแกรม"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "เซิร์ฟเวอร์เป็นผู้กำหนด"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "มีเพียงม็อดสำหรับฝั่งเครื่องของผู้เล่นเท่านั้นที่สามารถเพิ่มลงในโปรแกรมเซิร์ฟเวอร์ดังกล่าวได้"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "เวอร์ชันเกมถูกกำหนดโดยเซิร์ฟเวอร์แล้ว"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "ตัวรันถูกกำหนดโดยเซิร์ฟเวอร์แล้ว"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Değişimleri inceleniyor"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Güncellemeyi gözden geçir"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "İnceleniyor..."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "{name}'i oynamak için bir güncelleme gerekli. Oyunu açabilmek için lütfen son sürüme güncelleyin."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Bir güncelleme mevcut"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Dünyalarınız, yapılandırmalarınız ve yüklü tüm içerikler ve tüm veriler kalıcı olarak silinecek."
|
||||
},
|
||||
@@ -665,15 +656,6 @@
|
||||
"app.modal.install-to-play.report-image-too-large": {
|
||||
"message": "Dosya 1 MiB boyut sınırını aşıyor"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Uygunsuz"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Kötü niyetli"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Spam"
|
||||
},
|
||||
"app.modal.install-to-play.report-submitted": {
|
||||
"message": "Rapor sunuldu"
|
||||
},
|
||||
@@ -1508,18 +1490,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Kurulum ile eşitle"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Sunucu tarafından sağlanmıştır"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Sunucu örneğine yalnızca istemci tarafında çalışan modlar eklenebilir"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Oyun sürümü sunucu tarafından sağlanıyor"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Yükleyici sunucu tarafından sağlanıyor"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Hesap"
|
||||
},
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "Огляд змін"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "Переглянути оновлення"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "Оглядаємо…"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "Для гри в {name} потрібне оновлення. Будь ласка, оновіть до найновішої версії, щоб запустити гру."
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "Доступне оновлення"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Усі дані вашого профілю будуть видалені назавжди, включно з вашими світами, налаштуваннями та всім установленим умістом."
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "Яке правило порушує цей профіль?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "Неприпустимий уміст"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "Шкідливий уміст"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "Спам"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "Скарга на спільний профіль"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Синхронізувати з профілем"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Надано сервером"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "До профілю сервера можна додавати лише клієнтські моди"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Версія гри надана сервером"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Завантажувач наданий сервером"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "Обліковий запис"
|
||||
},
|
||||
|
||||
@@ -998,16 +998,7 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Đồng bộ với phiên bản"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Do máy chủ cung cấp"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Chỉ các mod chạy phía client mới có thể thêm hồ sơ máy chủ"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Phiên bản trò chơi được cung cấp bởi máy chủ"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader được cung cấp bởi máy chủ"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +377,9 @@
|
||||
"app.instance.admonitions.shared-instance.review-header": {
|
||||
"message": "查看变更"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.review-update-button": {
|
||||
"message": "查看更新"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.reviewing-button": {
|
||||
"message": "正在审查……"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-body": {
|
||||
"message": "{name}需要更新。请更新到最新版本以启动游戏。"
|
||||
},
|
||||
"app.instance.admonitions.shared-instance.update-available-header": {
|
||||
"message": "有更新可用"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "你实例的所有数据将被永久删除,包括你的世界、配置和所有已安装的内容。"
|
||||
},
|
||||
@@ -704,15 +695,6 @@
|
||||
"app.modal.install-to-play.report-reason": {
|
||||
"message": "该实例违反了哪项规则?"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.inappropriate": {
|
||||
"message": "不当内容"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.malicious": {
|
||||
"message": "恶意内容"
|
||||
},
|
||||
"app.modal.install-to-play.report-reason.spam": {
|
||||
"message": "垃圾内容"
|
||||
},
|
||||
"app.modal.install-to-play.report-shared-instance-header": {
|
||||
"message": "举报共享实例"
|
||||
},
|
||||
@@ -1922,18 +1904,9 @@
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "与实例同步"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "由该服务器提供"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "只能将客户端模组添加到服务器实例中"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "游戏版本由服务器提供"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "加载器由服务器提供"
|
||||
},
|
||||
"settings.sidebar.label.account": {
|
||||
"message": "账户"
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user