class_name SongLoader extends Node ## Downloads songs from the server into the Playlist ahead of time, so the next song ## can start at once. ## ## How many songs it keeps ready is the cache size in the settings ## ([code]Playlist.number_of_tracks_to_preload[/code]). ## Emitted when the songs already in the server playlist have been loaded into the ## Playlist. signal song_list_loaded ## Emitted when a new song has been downloaded and added to the Playlist. signal song_added ## Seconds to wait before retrying a download step that failed. var retry_seconds: float = 5.0 ## Loads the songs already in the server playlist, then starts preloading new ones. ## Preloading waits for the list, because loading the list clears the playlist. func load_song_list() -> void: GameLog.debug("load_song_list") var song_list_fetched: Callable = func song_list_fetched(songs: Array[SongInfo]) -> void: Playlist.clear_song_list() for info: SongInfo in songs: var new_song_object: SongObject = SongObject.new() new_song_object.song_number = info.song_no new_song_object.soundtrack_title = info.soundtrack new_song_object.song_title = info.song new_song_object.is_answered = true new_song_object.has_played = true Playlist.add_to_playlist(new_song_object) Playlist.update_last_played_song() # Songs already on the server were played before, so the game starts after them Playlist.game_start_song = Playlist.song_object_array.size() song_list_loaded.emit() fetch_song_if_idle() MusicServerClient.fetch_song_list(song_list_fetched, _retry_later.bind(load_song_list)) ## Starts downloading one more song, which keeps downloading until the cache is full. func fetch_song() -> void: GameLog.debug("fetch_song") Playlist.is_song_downloading = true _download_random_song(SongObject.new()) ## Starts downloading a song unless one is already downloading. func fetch_song_if_idle() -> void: if !Playlist.is_song_downloading: fetch_song() ## Starts downloading if nothing is downloading and the cache is not full, e.g. after ## the cache size was raised. func fill_cache() -> void: if !Playlist.is_song_downloading && Playlist.should_preload_more_songs(): fetch_song() # Fetching a song takes three requests. If one fails, only that step is retried, so # the server and the game keep the same songs in their playlists. func _download_random_song(new_song_object: SongObject) -> void: var song_downloaded: Callable = func song_downloaded(body: PackedByteArray) -> void: GameLog.debug("song_downloaded") Playlist.store_song(new_song_object, body) _add_song_to_queue(new_song_object) MusicServerClient.fetch_random_song(Settings.use_low_played_mode, song_downloaded, _retry_later.bind(_download_random_song.bind(new_song_object))) func _add_song_to_queue(new_song_object: SongObject) -> void: MusicServerClient.add_to_queue(_fetch_song_info.bind(new_song_object), _retry_later.bind(_add_song_to_queue.bind(new_song_object))) func _fetch_song_info(new_song_object: SongObject) -> void: var song_info_fetched: Callable = func song_info_fetched(info: SongInfo) -> void: GameLog.debug("song_info_fetched") new_song_object.song_number = info.song_no new_song_object.soundtrack_title = info.soundtrack new_song_object.song_title = info.song GameLog.debug("new_song_object: ", new_song_object.to_string()) Playlist.add_to_playlist(new_song_object) if Playlist.should_preload_more_songs(): fetch_song() else: Playlist.is_song_downloading = false song_added.emit() MusicServerClient.fetch_song_info(song_info_fetched, _retry_later.bind(_fetch_song_info.bind(new_song_object))) func _retry_later(step: Callable) -> void: GameLog.warning("Song download failed, retrying in %s seconds" % retry_seconds) get_tree().create_timer(retry_seconds).timeout.connect(step)