diff --git a/installer/renderer.js b/installer/renderer.js index 55c5129..a7b712b 100644 --- a/installer/renderer.js +++ b/installer/renderer.js @@ -24,6 +24,11 @@ const state = { packs: [], selectedPackKey: null, mode: null, // 'single' | 'multi' + // mode==='multi' 일 때만 의미가 있다. + // 'host' → 서버를 직접 연다. 기존 멀티 흐름 (step3 + step4) 그대로. + // 'participant' → 친구 서버에 접속만 한다. step3 (서버 설치) 를 건너뛰고 + // client 측에서도 맵은 받지 않는다 (참가자라 서버에 이미 있음). + role: null, // 'host' | 'participant' | null serverInstall: { path: '', jdk: '', @@ -154,33 +159,71 @@ function renderStep2() { '' + '' + '' + + '
' + tt('step3.eulaModal.fromFile') + '
' + - '' + escapeHtml(read.content) + '' + var fetched = await installerApi.fetchMinecraftEula() + if (fetched.html) { + bodyHtml = '
' + tt('step3.eulaModal.fromMojang', { url: fetched.url }) + '
' + + '' } else { - var fetched = await installerApi.fetchMinecraftEula() - if (fetched.html) { - bodyHtml = '' + tt('step3.eulaModal.fromMojang', { url: fetched.url }) + '
' + - '' - } else { - bodyHtml = '' + tt('step3.eulaModal.loadFailed') + '
' - } + bodyHtml = '' + tt('step3.eulaModal.loadFailed') + '
' } return new Promise(function (resolve) { var overlay = document.createElement('div') @@ -491,12 +530,6 @@ async function openEulaPopup(installPath) { }) } -function escapeHtml(text) { - return String(text).replace(/[&<>"']/g, function (ch) { - return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[ch] - }) -} - function escapeAttr(text) { return String(text).replace(/&/g, '&').replace(/"/g, '"') } @@ -535,6 +568,14 @@ function renderSubStep35(host, back, done) { var runBtn = host.querySelector('#run') host.querySelector('#back').addEventListener('click', back) + // 25565 는 마인크래프트 자바판 기본 포트라 클라이언트에서 생략 가능 → + // 사용자에게도 ip 만 보여주는 게 깔끔하다. + function formatServerAddress(ip, port) { + var safeIp = ip || tt('step3.sub35.ipUnknown') + if (Number(port) === 25565) return safeIp + return safeIp + ':' + port + } + async function runCheck() { runBtn.disabled = true resultMsg.classList.remove('success', 'warn', 'error') @@ -543,16 +584,16 @@ function renderSubStep35(host, back, done) { try { var result = await installerApi.checkPortForward(port) state.serverInstall.portStatus = result + var address = formatServerAddress(result.externalIp, result.port) if (result.status === 'preForwarded') { - resultMsg.innerHTML = tt('step3.sub35.preForwarded', { ip: result.externalIp, port: result.port }) + resultMsg.innerHTML = tt('step3.sub35.preForwarded', { address: address }) resultMsg.classList.add('success') } else if (result.status === 'upnpOk') { - resultMsg.innerHTML = tt('step3.sub35.upnpOk', { ip: result.externalIp, port: result.port }) + resultMsg.innerHTML = tt('step3.sub35.upnpOk', { address: address }) resultMsg.classList.add('success') } else { - var ip = result.externalIp || tt('step3.sub35.ipUnknown') resultMsg.innerHTML = (result.message || tt('step3.sub35.manualHint')) + - tt('step3.sub35.manualDetail', { ip: ip, port: result.port }) + tt('step3.sub35.manualDetail', { address: address }) resultMsg.classList.add('warn') } nextBtn.disabled = false @@ -581,64 +622,25 @@ function renderStep4() { '' pageHost.appendChild(section) var subHost = section.querySelector('#subHost') - function backToPrevStep() { if (state.mode === 'multi') renderStep3(); else renderStep2() } - function show41() { subHost.innerHTML = ''; renderSubStep41(subHost, pack, backToPrevStep, show42) } - function show42() { subHost.innerHTML = ''; renderSubStep42(subHost, show41, goStep5) } + // 플랫폼 선택 UI 는 더 이상 보여주지 않는다. 음악퀴즈에 지정된 플랫폼이 + // 바닐라가 아니면 자동으로 설치하고, 바닐라면 건너뛴다 — 사용자가 고를 일이 없다. + var platformType = pack ? pack.pack.platform.type : 'vanilla' + state.client.installPlatform = platformType !== 'vanilla' + + // 멀티+호스트 만 step3 (서버 설치) 를 거쳤으므로 거기로 돌아간다. + // 싱글 / 멀티+참가자 는 step2 로 되돌아간다. + function backToPrevStep() { + if (state.mode === 'multi' && state.role === 'host') renderStep3() + else renderStep2() + } + + function show42() { subHost.innerHTML = ''; renderSubStep42(subHost, backToPrevStep, goStep5) } function goStep5() { state.stepDone[4] = true renderStep5() } - show41() -} - -function renderSubStep41(host, pack, back, done) { - var platformType = pack ? pack.pack.platform.type : 'vanilla' - if (platformType === 'vanilla') { - state.client.installPlatform = false - host.innerHTML = - '' + tt('step4.sub41.vanillaInfo') + '
' + - '' + tt('step4.sub41.vanillaNoInstall') + '
' + - '' - host.querySelector('#back').addEventListener('click', back) - host.querySelector('#next').addEventListener('click', done) - return - } - - host.innerHTML = - '' + tt('step4.sub41.info', { platform: platformType }) + '
' + - '' + tt('step5.summary') + '
' + - (multi ? '