fix: prevent FightViewer random resets from concurrent kaplay init
- Guard initScene() with initializingScene flag to prevent concurrent calls - Don't auto-reinit scene on WebGL context restore during active replay - Block initScene() after component is destroyed - Static audio files now play even before Kokoro worker loads - kokoroSpeak/kokoroSpeakAsync check cache before requiring worker ready Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
52769ab43a
commit
1a7ad74859
@@ -28,6 +28,7 @@ let scene: FightSceneController | null = null
|
|||||||
const sceneReady = ref(false)
|
const sceneReady = ref(false)
|
||||||
let cleanupTimerHandle: ReturnType<typeof setTimeout> | null = null
|
let cleanupTimerHandle: ReturnType<typeof setTimeout> | null = null
|
||||||
let destroyed = false
|
let destroyed = false
|
||||||
|
let initializingScene = false
|
||||||
const contextLost = ref(false)
|
const contextLost = ref(false)
|
||||||
|
|
||||||
const isReplaying = ref(false)
|
const isReplaying = ref(false)
|
||||||
@@ -174,6 +175,8 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
async function initScene() {
|
async function initScene() {
|
||||||
if (!props.fight.botA || !props.fight.botB) return
|
if (!props.fight.botA || !props.fight.botB) return
|
||||||
|
if (initializingScene || destroyed) return // prevent concurrent init or post-destroy init
|
||||||
|
initializingScene = true
|
||||||
// Destroy previous scene fully
|
// Destroy previous scene fully
|
||||||
sceneReady.value = false
|
sceneReady.value = false
|
||||||
if (scene) { scene.destroy(); scene = null }
|
if (scene) { scene.destroy(); scene = null }
|
||||||
@@ -207,8 +210,10 @@ async function initScene() {
|
|||||||
sceneReady.value = false
|
sceneReady.value = false
|
||||||
})
|
})
|
||||||
newCanvas.addEventListener('webglcontextrestored', () => {
|
newCanvas.addEventListener('webglcontextrestored', () => {
|
||||||
|
// Don't auto-reinit during replay — just mark context as restored
|
||||||
|
// The contextLost overlay will let users tap to reload if needed
|
||||||
contextLost.value = false
|
contextLost.value = false
|
||||||
initScene() // Re-create the scene with fresh context
|
if (!isReplaying.value) initScene()
|
||||||
})
|
})
|
||||||
|
|
||||||
// Wrap scene creation in try/catch + timeout so a mobile sprite loading failure
|
// Wrap scene creation in try/catch + timeout so a mobile sprite loading failure
|
||||||
@@ -230,6 +235,8 @@ async function initScene() {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[FightViewer] Scene creation failed — continuing without canvas:', err)
|
console.error('[FightViewer] Scene creation failed — continuing without canvas:', err)
|
||||||
|
} finally {
|
||||||
|
initializingScene = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user