diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index f6333d2a56..13737b1aa5 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -108,7 +108,12 @@ import { debugAnalytics, initAnalytics, trackEvent } from '@/helpers/analytics' import { check_reachable } from '@/helpers/auth.js' import { get_user, get_version } from '@/helpers/cache.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 { + can_current_user_use_shared_instances, + get as getInstance, + get_global_synced_options, + run, +} from '@/helpers/instance' import { get as getCreds, login, logout } from '@/helpers/mr_auth.ts' import { mergeUrlQuery, parseModrinthLink } from '@/helpers/project-links.ts' import { get as getSettings, set as setSettings } from '@/helpers/settings.ts' @@ -419,6 +424,11 @@ const os = ref('') const isDevEnvironment = ref(false) const stateInitialized = ref(false) +const globalSyncedOptionsQuery = useQuery({ + queryKey: ['global-synced-options'], + queryFn: get_global_synced_options, + enabled: computed(() => stateInitialized.value), +}) const criticalErrorMessage = ref() @@ -1717,7 +1727,11 @@ provideAppUpdateDownloadProgress(appUpdateDownload) - + -import { - defineMessages, - injectNotificationManager, - Slider, - StyledInput, - Toggle, - useVIntl, -} from '@modrinth/ui' -import { ref, watch } from 'vue' - -import useMemorySlider from '@/composables/useMemorySlider' -import { get, parseEnvVars, serializeEnvVars, set } from '@/helpers/settings.ts' - -const { handleError } = injectNotificationManager() -const { formatMessage } = useVIntl() - -const messages = defineMessages({ - fullscreenTitle: { - id: 'app.settings.default-instance-options.fullscreen.title', - defaultMessage: 'Fullscreen', - }, - fullscreenDescription: { - id: 'app.settings.default-instance-options.fullscreen.description', - defaultMessage: 'Start instances in fullscreen by updating their options.txt file.', - }, - widthTitle: { - id: 'app.settings.default-instance-options.width.title', - defaultMessage: 'Width', - }, - widthDescription: { - id: 'app.settings.default-instance-options.width.description', - defaultMessage: 'The width of the game window when launched.', - }, - widthPlaceholder: { - id: 'app.settings.default-instance-options.width.placeholder', - defaultMessage: 'Enter width...', - }, - heightTitle: { - id: 'app.settings.default-instance-options.height.title', - defaultMessage: 'Height', - }, - heightDescription: { - id: 'app.settings.default-instance-options.height.description', - defaultMessage: 'The height of the game window when launched.', - }, - heightPlaceholder: { - id: 'app.settings.default-instance-options.height.placeholder', - defaultMessage: 'Enter height...', - }, - memoryAllocationTitle: { - id: 'app.settings.default-instance-options.memory-allocation.title', - defaultMessage: 'Memory allocation', - }, - memoryAllocationDescription: { - id: 'app.settings.default-instance-options.memory-allocation.description', - defaultMessage: 'Maximum memory available to each instance.', - }, - javaArgumentsTitle: { - id: 'app.settings.default-instance-options.java-arguments.title', - defaultMessage: 'Java arguments', - }, - javaArgumentsPlaceholder: { - id: 'app.settings.default-instance-options.java-arguments.placeholder', - defaultMessage: 'Enter Java arguments...', - }, - javaArgumentsDescription: { - id: 'app.settings.default-instance-options.java-arguments.description', - defaultMessage: 'Arguments passed to Java when launching an instance.', - }, - environmentVariablesTitle: { - id: 'app.settings.default-instance-options.environment-variables.title', - defaultMessage: 'Environment variables', - }, - environmentVariablesPlaceholder: { - id: 'app.settings.default-instance-options.environment-variables.placeholder', - defaultMessage: 'Enter environment variables...', - }, - environmentVariablesDescription: { - id: 'app.settings.default-instance-options.environment-variables.description', - defaultMessage: 'Environment variables set when launching an instance.', - }, - preLaunchHookTitle: { - id: 'app.settings.default-instance-options.pre-launch-hook.title', - defaultMessage: 'Pre-launch hook', - }, - preLaunchHookPlaceholder: { - id: 'app.settings.default-instance-options.pre-launch-hook.placeholder', - defaultMessage: 'Enter pre-launch command...', - }, - preLaunchHookDescription: { - id: 'app.settings.default-instance-options.pre-launch-hook.description', - defaultMessage: 'Runs before the instance starts.', - }, - wrapperHookTitle: { - id: 'app.settings.default-instance-options.wrapper-hook.title', - defaultMessage: 'Wrapper hook', - }, - wrapperHookPlaceholder: { - id: 'app.settings.default-instance-options.wrapper-hook.placeholder', - defaultMessage: 'Enter wrapper command...', - }, - wrapperHookDescription: { - id: 'app.settings.default-instance-options.wrapper-hook.description', - defaultMessage: 'Command used to wrap the Minecraft launch process.', - }, - postExitHookTitle: { - id: 'app.settings.default-instance-options.post-exit-hook.title', - defaultMessage: 'Post-exit hook', - }, - postExitHookPlaceholder: { - id: 'app.settings.default-instance-options.post-exit-hook.placeholder', - defaultMessage: 'Enter post-exit command...', - }, - postExitHookDescription: { - id: 'app.settings.default-instance-options.post-exit-hook.description', - defaultMessage: 'Runs after the game closes.', - }, - hookVariablesDescription: { - id: 'instance.settings.tabs.hooks.variables.description', - defaultMessage: - 'Hooks run in the working directory of the instance, with the following variables:', - }, - instanceNameDescription: { - id: 'instance.settings.tabs.hooks.variables.inst-name.description', - defaultMessage: '$INST_NAME: The name of the instance', - }, - instanceIdDescription: { - id: 'instance.settings.tabs.hooks.variables.inst-id.description', - defaultMessage: "$INST_ID: The name of the instance's folder", - }, - instanceDirDescription: { - id: 'instance.settings.tabs.hooks.variables.inst-dir.description', - defaultMessage: "$INST_DIR: The absolute path to the instance's folder", - }, - instanceMcDirDescription: { - id: 'instance.settings.tabs.hooks.variables.inst-mc-dir.description', - defaultMessage: '$INST_MC_DIR: An alias for $INST_DIR', - }, - instanceJavaDescription: { - id: 'instance.settings.tabs.hooks.variables.inst-java.description', - defaultMessage: '$INST_JAVA: The absolute path to the java binary', - }, - instanceJavaArgsDescription: { - id: 'instance.settings.tabs.hooks.variables.inst-java-args.description', - defaultMessage: '$INST_JAVA_ARGS: The JVM Arguments provided to the game', - }, -}) - -const fetchSettings = await get() -fetchSettings.launchArgs = fetchSettings.extra_launch_args.join(' ') -fetchSettings.envVars = serializeEnvVars(fetchSettings.custom_env_vars) - -const settings = ref(fetchSettings) - -const { maxMemory, snapPoints } = (await useMemorySlider().catch(handleError)) as unknown as { - maxMemory: number - snapPoints: number[] -} - -watch( - settings, - async () => { - const setSettings = JSON.parse(JSON.stringify(settings.value)) - - setSettings.extra_launch_args = setSettings.launchArgs.trim().split(/\s+/).filter(Boolean) - setSettings.custom_env_vars = parseEnvVars(setSettings.envVars) - delete setSettings.launchArgs - delete setSettings.envVars - - if (!setSettings.custom_dir) { - setSettings.custom_dir = null - } - - await set(setSettings).catch(handleError) - }, - { deep: true }, -) - - - diff --git a/apps/app-frontend/src/components/ui/settings/instances/InstancesSyncedSettings.vue b/apps/app-frontend/src/components/ui/settings/instances/InstancesSyncedSettings.vue new file mode 100644 index 0000000000..3a5169b146 --- /dev/null +++ b/apps/app-frontend/src/components/ui/settings/instances/InstancesSyncedSettings.vue @@ -0,0 +1,797 @@ + + + + + diff --git a/apps/app-frontend/src/components/ui/world/WorldItem.vue b/apps/app-frontend/src/components/ui/world/WorldItem.vue index 8147d0bce0..b1e1ebac41 100644 --- a/apps/app-frontend/src/components/ui/world/WorldItem.vue +++ b/apps/app-frontend/src/components/ui/world/WorldItem.vue @@ -66,7 +66,7 @@ const router = useRouter() const { addNotification } = injectNotificationManager() const emit = defineEmits<{ - (e: 'play' | 'play-instance' | 'update' | 'stop' | 'refresh' | 'edit' | 'delete'): void + (e: 'play' | 'play-instance' | 'update' | 'stop' | 'refresh' | 'edit' | 'delete' | 'desync'): void (e: 'open-folder', world: SingleplayerWorld): void }>() @@ -217,6 +217,10 @@ const messages = defineMessages({ id: 'instance.worlds.copy_address', defaultMessage: 'Copy address', }, + desync: { + id: 'instance.worlds.desync_server', + defaultMessage: 'Desync', + }, viewInstance: { id: 'instance.worlds.view_instance', defaultMessage: 'View instance', @@ -500,6 +504,16 @@ const messages = defineMessages({ shown: world.type === 'server', action: () => copyToClipboard((world as ServerWorld).address), }, + { + id: 'desync', + label: formatMessage(messages.desync), + action: () => emit('desync'), + shown: + !instanceId && + world.type === 'server' && + (world as ServerWorld).source === 'user_synced' && + !!(world as ServerWorld).server_id, + }, { id: 'edit', label: formatMessage(commonMessages.editButton), @@ -577,6 +591,10 @@ const messages = defineMessages({