11import { ref , onUnmounted } from 'vue'
22import axios from 'axios'
33import { getAssetUrl , getBackgroundUrl , getBgmUrl , getSeUrl } from '@/utils/asset'
4+ import { resourceManager } from '@/utils/resourceManager'
5+ import { getSvtScript , Region } from '@/api/atlas'
46
57export interface ScriptState {
68 background : string | null
@@ -87,11 +89,12 @@ export function useScriptPlayer() {
8789 }
8890
8991 const playBgm = ( id : string , volume : number = 1.0 , fadeDuration : number = 0 ) => {
90- const url = getBgmUrl ( id , currentRegion . value )
92+ const rawUrl = getBgmUrl ( id , currentRegion . value )
93+ const url = resourceManager . getResolvedUrl ( rawUrl )
9194 // Boost volume because script values (e.g. 0.1) are often too quiet for web playback
9295 const adjustedVolume = Math . min ( volume * 5.0 , 1.0 )
9396
94- if ( bgmAudio && ! bgmAudio . paused && bgmAudio . src === url ) {
97+ if ( bgmAudio && ! bgmAudio . paused && ( bgmAudio . src === url || bgmAudio . src === rawUrl ) ) {
9598 // Same BGM, just update volume
9699 fadeAudio ( bgmAudio , fadeDuration , adjustedVolume )
97100 return
@@ -129,7 +132,8 @@ export function useScriptPlayer() {
129132 }
130133
131134 const playSe = ( id : string ) => {
132- const url = getSeUrl ( id , currentRegion . value )
135+ const rawUrl = getSeUrl ( id , currentRegion . value )
136+ const url = resourceManager . getResolvedUrl ( rawUrl )
133137 const audio = new Audio ( url )
134138 audio . volume = 1.0 // Default volume for SE
135139
@@ -330,6 +334,87 @@ export function useScriptPlayer() {
330334 }
331335 }
332336
337+ const preloadUpcomingAssets = ( startIndex : number , region : string , limitBlocks : number = 3 ) => {
338+ let blocksFound = 0
339+ let index = startIndex
340+ let isPreloading = true
341+ let hasEncounteredChoice = false
342+
343+ while ( index < scriptLines . value . length ) {
344+ const line = scriptLines . value [ index ]
345+ if ( ! line ) {
346+ index ++
347+ continue
348+ }
349+ const cmd = parseLine ( line )
350+
351+ if ( cmd . type === 'choice' ) {
352+ hasEncounteredChoice = true
353+ // Reset for new branch so we scan into it
354+ blocksFound = 0
355+ isPreloading = true
356+ } else if ( cmd . type === 'choiceEnd' ) {
357+ // End of choice block, stop scanning
358+ break
359+ }
360+
361+ if ( isPreloading ) {
362+ if ( cmd . type === 'command' ) {
363+ switch ( cmd . commandName ) {
364+ case 'bgm' :
365+ if ( cmd . args && cmd . args . length > 0 ) {
366+ const url = getBgmUrl ( cmd . args [ 0 ] ! , region )
367+ resourceManager . preloadAudio ( url )
368+ }
369+ break
370+ case 'se' :
371+ if ( cmd . args && cmd . args . length > 0 ) {
372+ const url = getSeUrl ( cmd . args [ 0 ] ! , region )
373+ resourceManager . preloadAudio ( url )
374+ }
375+ break
376+ case 'scene' :
377+ if ( cmd . args && cmd . args . length > 0 ) {
378+ const url = getBackgroundUrl ( cmd . args [ 0 ] ! , region )
379+ resourceManager . preloadImage ( url )
380+ }
381+ break
382+ case 'charaSet' :
383+ // [charaSet CODE ID ASCENSION NAME...]
384+ if ( cmd . args && cmd . args . length >= 3 ) {
385+ const id = cmd . args [ 1 ] !
386+ const url = getAssetUrl ( `CharaFigure/${ id } /${ id } _merged.png` , region )
387+ resourceManager . preloadImage ( url )
388+
389+ // Preload svtScript data
390+ getSvtScript ( parseInt ( id ) , region as Region )
391+ }
392+ break
393+ case 'waitClick' :
394+ blocksFound ++
395+ break
396+ case 'end' :
397+ blocksFound = limitBlocks // Stop scanning
398+ break
399+ }
400+ } else if ( cmd . type === 'choice' ) {
401+ // Handled above
402+ }
403+
404+ if ( blocksFound >= limitBlocks ) {
405+ isPreloading = false
406+ // If we haven't seen a choice, we can stop now.
407+ // Because we are just in linear text and reached the limit.
408+ if ( ! hasEncounteredChoice ) {
409+ break
410+ }
411+ }
412+ }
413+
414+ index ++
415+ }
416+ }
417+
333418 const fetchScriptContent = async ( url : string ) => {
334419 try {
335420 const response = await axios . get ( url )
@@ -393,8 +478,12 @@ export function useScriptPlayer() {
393478
394479 const content = await fetchScriptContent ( scriptUrl )
395480 scriptLines . value = content . split ( '\n' ) . filter ( ( l : string ) => l . trim ( ) !== '' )
481+
396482 currentLineIndex . value = 0
397483
484+ // Preload initial batch (next 3 blocks)
485+ preloadUpcomingAssets ( 0 , region , 3 )
486+
398487 // Start processing until first stop
399488 await processNextBlock ( )
400489 isLoading . value = false
@@ -533,7 +622,8 @@ export function useScriptPlayer() {
533622 // TODO: Handle transitions and visual effects for scene changes
534623 if ( cmd . args && cmd . args . length > 0 ) {
535624 const bgId = cmd . args [ 0 ] as string
536- state . value . background = getBackgroundUrl ( bgId , currentRegion . value )
625+ const rawUrl = getBackgroundUrl ( bgId , currentRegion . value )
626+ state . value . background = resourceManager . getResolvedUrl ( rawUrl )
537627 }
538628 break
539629 case 'bgm' :
@@ -669,7 +759,7 @@ export function useScriptPlayer() {
669759 }
670760 }
671761
672- const next = ( ) => {
762+ const next = async ( ) => {
673763 if ( state . value . isFinished ) return
674764
675765 // Clear text for next block?
@@ -682,16 +772,22 @@ export function useScriptPlayer() {
682772 // We need to pass region again. Ideally store it in closure or ref.
683773 // For now, let's just default to JP or we need to refactor to store region in state.
684774 // Refactor: store region
685- processNextBlock ( )
775+ await processNextBlock ( )
776+
777+ // Preload next batch
778+ preloadUpcomingAssets ( currentLineIndex . value , currentRegion . value , 3 )
686779 }
687780
688- const selectChoice = ( choiceId : number ) => {
781+ const selectChoice = async ( choiceId : number ) => {
689782 const startIndex = choiceMap . value [ choiceId ]
690783 if ( startIndex !== undefined ) {
691784 currentLineIndex . value = startIndex
692785 state . value . choices = [ ]
693786 state . value . text = '' // Clear text before showing response
694- processNextBlock ( )
787+ await processNextBlock ( )
788+
789+ // Preload next batch
790+ preloadUpcomingAssets ( currentLineIndex . value , currentRegion . value , 3 )
695791 }
696792 }
697793
0 commit comments