fix: preserve analysis results and flag stale user data
Publish GitHub Pages output / publish (push) Successful in 51s
Publish GitHub Pages output / publish (push) Successful in 51s
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import cardSummary from '$lib/data/cards-summary.json';
|
||||
import { leaderOutfitCards } from '$lib/engine/leader-outfits.ts';
|
||||
@@ -168,6 +168,43 @@
|
||||
let screeningProgress = 0;
|
||||
let errorMessage = '';
|
||||
let ready = false;
|
||||
let loadedUserData: string | null | undefined;
|
||||
let userDataChanged = false;
|
||||
|
||||
function loadUserData(): void {
|
||||
const raw = localStorage.getItem(USER_DATA_STORAGE_KEY);
|
||||
const stored = JSON.parse(raw ?? 'null');
|
||||
collection = stored?.collection && typeof stored.collection === 'object' ? stored.collection : {};
|
||||
memberBoards = stored?.memberBoards && typeof stored.memberBoards === 'object' ? stored.memberBoards : {};
|
||||
boardCards = stored?.boardCards && typeof stored.boardCards === 'object' ? stored.boardCards : {};
|
||||
memoryCount = Number.isFinite(stored?.memoryCount) ? stored.memoryCount : 0;
|
||||
memberPowerUpPercent = Number.isFinite(stored?.memberPowerUpPercent) ? stored.memberPowerUpPercent : 0;
|
||||
loadedUserData = raw;
|
||||
userDataChanged = false;
|
||||
}
|
||||
|
||||
function resetBaseline(): void {
|
||||
baselineWorker?.terminate();
|
||||
const nextWorker = createScoreOptimizerWorker();
|
||||
baselineWorker = nextWorker;
|
||||
baselineResult = null;
|
||||
baselineAchievementProbabilities = undefined;
|
||||
baselineRunning = false;
|
||||
baselineError = '';
|
||||
nextWorker.onmessage = (event) => {
|
||||
if (baselineWorker !== nextWorker) return;
|
||||
if (event.data.type === 'progress') baselineProgress = event.data.progress;
|
||||
if (event.data.type === 'result') {
|
||||
baselineResult = event.data.result;
|
||||
baselineAchievementProbabilities = event.data.achievementProbabilities;
|
||||
baselineRunning = false;
|
||||
}
|
||||
if (event.data.type === 'error') {
|
||||
baselineError = event.data.message;
|
||||
baselineRunning = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$: charts = releasedSongCharts(allCharts, releaseNow);
|
||||
$: currentEvent = eventMode
|
||||
@@ -259,12 +296,7 @@
|
||||
releaseNow = currentReleaseClock.now();
|
||||
}, 1_000);
|
||||
try {
|
||||
const stored = JSON.parse(localStorage.getItem(USER_DATA_STORAGE_KEY) ?? 'null');
|
||||
collection = stored?.collection && typeof stored.collection === 'object' ? stored.collection : {};
|
||||
memberBoards = stored?.memberBoards && typeof stored.memberBoards === 'object' ? stored.memberBoards : {};
|
||||
boardCards = stored?.boardCards && typeof stored.boardCards === 'object' ? stored.boardCards : {};
|
||||
memoryCount = Number.isFinite(stored?.memoryCount) ? stored.memoryCount : 0;
|
||||
memberPowerUpPercent = Number.isFinite(stored?.memberPowerUpPercent) ? stored.memberPowerUpPercent : 0;
|
||||
loadUserData();
|
||||
} catch {
|
||||
collection = {};
|
||||
}
|
||||
@@ -296,19 +328,7 @@
|
||||
searchPhase = 'idle';
|
||||
}
|
||||
};
|
||||
baselineWorker = createScoreOptimizerWorker();
|
||||
baselineWorker.onmessage = (event) => {
|
||||
if (event.data.type === 'progress') baselineProgress = event.data.progress;
|
||||
if (event.data.type === 'result') {
|
||||
baselineResult = event.data.result;
|
||||
baselineAchievementProbabilities = event.data.achievementProbabilities;
|
||||
baselineRunning = false;
|
||||
}
|
||||
if (event.data.type === 'error') {
|
||||
baselineError = event.data.message;
|
||||
baselineRunning = false;
|
||||
}
|
||||
};
|
||||
resetBaseline();
|
||||
try {
|
||||
baselineState = readAnalysisState(localStorage.getItem(ANALYSIS_STORAGE_KEY));
|
||||
} catch {
|
||||
@@ -316,8 +336,16 @@
|
||||
baselineError = '배치 분석의 저장 데이터를 읽지 못했습니다.';
|
||||
}
|
||||
ready = true;
|
||||
const syncStorage = (event: StorageEvent) => {
|
||||
if (event.storageArea !== localStorage || (event.key !== USER_DATA_STORAGE_KEY && event.key !== null)) return;
|
||||
// Keep the calculation's growth snapshot and all existing results intact.
|
||||
// Read the current value because queued storage events may already be outdated.
|
||||
userDataChanged = localStorage.getItem(USER_DATA_STORAGE_KEY) !== loadedUserData;
|
||||
};
|
||||
window.addEventListener('storage', syncStorage);
|
||||
return () => {
|
||||
mounted = false;
|
||||
window.removeEventListener('storage', syncStorage);
|
||||
window.clearInterval(releaseClock);
|
||||
worker?.terminate();
|
||||
terminateParallelWorkers();
|
||||
@@ -821,6 +849,7 @@
|
||||
}
|
||||
|
||||
async function analyzeBaseline(): Promise<void> {
|
||||
const targetWorker = baselineWorker;
|
||||
const state = baselineState;
|
||||
const chartMetadata = baselineChartMetadata;
|
||||
if (!state || !chartMetadata || !baselineWorker || !baselineMatchesConditions) return;
|
||||
@@ -872,6 +901,7 @@
|
||||
};
|
||||
});
|
||||
const chart = await loadExactSongChart(chartMetadata.path);
|
||||
if (baselineWorker !== targetWorker) return;
|
||||
baselineOverallPower = power.overallPower;
|
||||
baselineProgress = { evaluatedCandidates: 0, totalCandidates: countOptimizationCandidates(optimizerCards) };
|
||||
baselineWorker.postMessage({
|
||||
@@ -883,6 +913,7 @@
|
||||
includeAchievementProbabilities: true
|
||||
});
|
||||
} catch (error) {
|
||||
if (baselineWorker !== targetWorker) return;
|
||||
baselineError = error instanceof Error ? error.message : '기준 조합을 분석하지 못했습니다.';
|
||||
baselineRunning = false;
|
||||
}
|
||||
@@ -1007,7 +1038,18 @@
|
||||
}
|
||||
|
||||
async function search(): Promise<void> {
|
||||
if (running) return;
|
||||
errorMessage = '';
|
||||
try {
|
||||
const previousUserData = loadedUserData;
|
||||
loadUserData();
|
||||
if (previousUserData !== loadedUserData) resetBaseline();
|
||||
// Rebuild reactive connection cards and candidate ownership before searching.
|
||||
await tick();
|
||||
} catch {
|
||||
errorMessage = '사용자 데이터를 읽지 못했습니다. 사용자 데이터 페이지에서 저장 상태를 확인해 주세요.';
|
||||
return;
|
||||
}
|
||||
result = null;
|
||||
if (!worker || !selectedChart) return;
|
||||
if (ownedCardsOnly && new Set(candidateCards.map((card) => card.characterId)).size < 5) {
|
||||
@@ -1259,6 +1301,7 @@
|
||||
|
||||
<section class="panel" aria-labelledby="result-title">
|
||||
<div class="section-title"><div><span>02</span><h2 id="result-title">탐색 결과</h2></div>{#if result}<strong>{screenedCombinationCount.toLocaleString('ko-KR')}개 선별 · {exactCombinationCount}개 정밀 분석 · {comparableToBaseline ? '기준 조합 포함 ' : ''}상위 {displayedRankings.length}개</strong>{/if}</div>
|
||||
{#if userDataChanged}<p class="baseline-guide" role="status">사용자 데이터가 변경되었습니다. 진행 중인 탐색과 아래 결과는 이전 데이터 기준이며, 다시 탐색하면 최신 데이터를 적용합니다.</p>{/if}
|
||||
{#if displayedRankings.length > 0}
|
||||
<div class="ranking-list">
|
||||
{#each displayedRankings as ranking, rank}
|
||||
|
||||
Reference in New Issue
Block a user