Character pictures are kept in characters/ next to the settings, with an index.json of when the server last changed each one and when it was downloaded. Only new or changed pictures are downloaded, using the server's new /character/details. Older servers fall back to the name list, and pictures are downloaded again after 7 days. Downloaded songs are written to songs/ and only their paths are kept in memory. The folder is emptied when the game starts and when the playlist resets.
99 lines
3.7 KiB
GDScript
99 lines
3.7 KiB
GDScript
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)
|