Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
StarLight 实例一键安装此前固定落到启动器默认目录,无法选择游戏数据位置。 现复用创建流程的外部游戏目录能力:点击一键安装后弹出目录选择框, 只允许修改游戏目录,其余参数仍由服务器整合包决定。 - hosted::create 接受 game_dir_root,拼为 <root>/<包名> 作为 game_dir_override (刻意避开 versions/ 布局,该结构被外部直链实例检测占用) - 新增顶层命令 get_launcher_root_dir,作为弹窗默认值(可执行文件所在目录) - 新增 HostedGameDirModal 弹窗:只读路径框 + 浏览 + 默认位置 + 安装预览 - 补齐 en-US / zh-CN / zh-TW 三语文案 hosted_create 增加 game_dir_root 参数,前端 hostedCreate/install 同步透传。
224 lines
6.6 KiB
Vue
224 lines
6.6 KiB
Vue
<script setup lang="ts">
|
|
import { FolderOpenIcon, LeftArrowIcon, SparklesIcon } from '@modrinth/assets'
|
|
import { BigOptionButton, Button, defineMessages, useVIntl } from '@modrinth/ui'
|
|
import { inject, ref, watch } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import InstanceModeOptions from '@/components/instance/InstanceModeOptions.vue'
|
|
import HostedGameDirModal from '@/components/instance/HostedGameDirModal.vue'
|
|
import HostedPackProgress from '@/components/instance/HostedPackProgress.vue'
|
|
import type { InstanceMode } from '@/helpers/hosted-packs'
|
|
import { useHostedCreation } from '@/composables/useHostedCreation'
|
|
|
|
const { formatMessage } = useVIntl()
|
|
const router = useRouter()
|
|
const { installing, installError, createdInstance, completed, acknowledge, install } =
|
|
useHostedCreation()
|
|
const instanceMode = ref<InstanceMode>(
|
|
installing.value || createdInstance.value ? 'starlight' : 'local',
|
|
)
|
|
|
|
const hostedGameDirModal = ref<InstanceType<typeof HostedGameDirModal>>()
|
|
|
|
// One-click StarLight installs reuse the same external game-directory choice
|
|
// as the custom creation flow: the pack gets its own folder under `<root>`.
|
|
function promptHostedGameDir() {
|
|
hostedGameDirModal.value?.show()
|
|
}
|
|
|
|
async function installHostedWithGameDir(gameDirRoot: string) {
|
|
await install(gameDirRoot)
|
|
}
|
|
async function openCompleted(instanceId: string) {
|
|
try {
|
|
const failure = await router.push(`/instance/${encodeURIComponent(instanceId)}/`)
|
|
if (!failure) acknowledge(instanceId)
|
|
else installError.value = failure.message
|
|
} catch (cause) {
|
|
installError.value = String(cause)
|
|
}
|
|
}
|
|
watch(
|
|
() => (completed.value ? createdInstance.value : undefined),
|
|
(instanceId) => {
|
|
if (instanceId) void openCompleted(instanceId)
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
const showModal = inject<
|
|
(options?: {
|
|
skipSetupType?: boolean
|
|
initialMode?: 'custom' | 'import'
|
|
onBack?: () => void
|
|
}) => void
|
|
>('showCreationModalWithOptions')
|
|
|
|
const messages = defineMessages({
|
|
openInstance: { id: 'app.hosted-packs.open-instance', defaultMessage: 'Open installed instance' },
|
|
autoInstall: {
|
|
id: 'app.hosted-packs.auto-install',
|
|
defaultMessage: 'Install the StarLight modpack',
|
|
},
|
|
autoDescription: {
|
|
id: 'app.hosted-packs.auto-description',
|
|
defaultMessage:
|
|
'Download and automatically install the modpack from StarLight to play on the StarLight server with one click.',
|
|
},
|
|
autoInstalling: {
|
|
id: 'app.hosted-packs.auto-installing',
|
|
defaultMessage: 'Downloading and installing the server modpack…',
|
|
},
|
|
retryInstall: { id: 'app.hosted-packs.retry-install', defaultMessage: 'Retry installation' },
|
|
title: {
|
|
id: 'create.title',
|
|
defaultMessage: 'Create Instance',
|
|
},
|
|
subtitle: {
|
|
id: 'create.subtitle',
|
|
defaultMessage: 'Start a new adventure or bring your existing worlds',
|
|
},
|
|
newTitle: {
|
|
id: 'create.new.title',
|
|
defaultMessage: 'Start Fresh',
|
|
},
|
|
newDescription: {
|
|
id: 'create.new.description',
|
|
defaultMessage: 'Create a new Minecraft instance from scratch.',
|
|
},
|
|
importTitle: {
|
|
id: 'create.import.title',
|
|
defaultMessage: 'Import Existing',
|
|
},
|
|
importDescription: {
|
|
id: 'create.import.description',
|
|
defaultMessage: 'Import instances from other launchers or install a modpack.',
|
|
},
|
|
back: {
|
|
id: 'create.back',
|
|
defaultMessage: 'Back to Library',
|
|
},
|
|
pclHmclHint: {
|
|
id: 'create.pcl-hmcl-hint',
|
|
defaultMessage: 'Using PCL / HMCL?',
|
|
},
|
|
addMinecraftFolder: {
|
|
id: 'create.add-minecraft-folder',
|
|
defaultMessage: 'Add .minecraft folder',
|
|
},
|
|
})
|
|
|
|
const navigateBack = () => router.push('/library')
|
|
|
|
async function handleStartFresh() {
|
|
if (installing.value) return
|
|
if (instanceMode.value === 'starlight') {
|
|
if (completed.value && createdInstance.value) {
|
|
await openCompleted(createdInstance.value)
|
|
return
|
|
}
|
|
if (createdInstance.value) {
|
|
// A previous attempt already created the instance; retry in place.
|
|
await install()
|
|
return
|
|
}
|
|
promptHostedGameDir()
|
|
return
|
|
}
|
|
showModal?.({
|
|
skipSetupType: true,
|
|
initialMode: 'custom',
|
|
onBack: () => router.push('/create'),
|
|
})
|
|
}
|
|
|
|
function handleImportExisting() {
|
|
showModal?.({
|
|
skipSetupType: true,
|
|
initialMode: 'import',
|
|
onBack: () => router.push('/create'),
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex h-full w-full flex-col items-center overflow-y-auto p-6">
|
|
<div class="my-auto flex w-full max-w-2xl shrink-0 flex-col gap-6">
|
|
<div class="flex flex-col gap-2">
|
|
<h1 class="m-0 text-2xl font-bold text-contrast">
|
|
{{ formatMessage(messages.title) }}
|
|
</h1>
|
|
<p class="m-0 text-sm text-secondary">
|
|
{{ formatMessage(messages.subtitle) }}
|
|
</p>
|
|
</div>
|
|
|
|
<InstanceModeOptions
|
|
v-model="instanceMode"
|
|
:disabled="installing"
|
|
data-onboarding-id="creation-instance-mode"
|
|
/>
|
|
<div data-onboarding-id="creation-methods" class="flex flex-col gap-4 sm:flex-row">
|
|
<BigOptionButton
|
|
:data-onboarding-id="
|
|
instanceMode === 'starlight' ? 'creation-method-starlight' : 'creation-method-custom'
|
|
"
|
|
:disabled="installing"
|
|
:icon="SparklesIcon"
|
|
:title="
|
|
formatMessage(
|
|
instanceMode === 'starlight'
|
|
? installing
|
|
? messages.autoInstalling
|
|
: completed
|
|
? messages.openInstance
|
|
: createdInstance
|
|
? messages.retryInstall
|
|
: messages.autoInstall
|
|
: messages.newTitle,
|
|
)
|
|
"
|
|
:description="
|
|
formatMessage(
|
|
instanceMode === 'starlight' ? messages.autoDescription : messages.newDescription,
|
|
)
|
|
"
|
|
no-icon-box
|
|
@click="handleStartFresh"
|
|
/>
|
|
|
|
<BigOptionButton
|
|
data-onboarding-id="creation-method-import"
|
|
v-if="instanceMode === 'local'"
|
|
:icon="FolderOpenIcon"
|
|
:title="formatMessage(messages.importTitle)"
|
|
:description="formatMessage(messages.importDescription)"
|
|
no-icon-box
|
|
@click="handleImportExisting"
|
|
/>
|
|
</div>
|
|
|
|
<HostedGameDirModal
|
|
ref="hostedGameDirModal"
|
|
@confirm="installHostedWithGameDir"
|
|
/>
|
|
<HostedPackProgress :instance-id="createdInstance" :active="installing" />
|
|
<p v-if="installError" class="m-0 text-red" role="alert">{{ installError }}</p>
|
|
<p v-if="instanceMode === 'local'" class="m-0 text-sm text-secondary">
|
|
{{ formatMessage(messages.pclHmclHint) }}
|
|
{{ ' ' }}
|
|
<RouterLink
|
|
to="/settings#storage-backups"
|
|
class="text-brand underline decoration-transparent underline-offset-2 transition-colors hover:decoration-current"
|
|
>
|
|
{{ formatMessage(messages.addMinecraftFolder) }}
|
|
</RouterLink>
|
|
</p>
|
|
|
|
<Button transparent class="self-start" @click="navigateBack">
|
|
<LeftArrowIcon class="size-4" stroke-width="2" />
|
|
{{ formatMessage(messages.back) }}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</template>
|