extends Node ## The songs of the current quiz, in the order they were added, and which of them are ## played, answered and playing. ## ## Registered as the [code]Playlist[/code] autoload. ## ## Downloaded songs are kept on disk in the [code]songs[/code] folder next to the ## settings, not in memory. The folder only holds the current playlist: when the game ## starts, songs the saved quiz does not use are deleted (see [QuizSave]), and the folder ## is emptied when the playlist is reset. const SONGS_FOLDER_NAME: String = "songs" var song_object_array: Array[SongObject] = [] var latest_played_song: int = 0 var currently_playing_song: int = -1 var first_song_downloaded: bool = false var first_song_played: bool = false var number_of_tracks_to_preload: int = 1 var is_song_downloading: bool = false ## The first song of the current game. Songs before it belong to earlier games, which ## ended with Reset points. var game_start_song: int = 0 # How many song files have been written, so each gets a name of its own var _song_files_written: int = 0 ## The folder downloaded songs are kept in. static func songs_folder() -> String: return Settings.config_dir().path_join(SONGS_FOLDER_NAME) func get_next_song() -> SongObject: return song_object_array[latest_played_song] func set_latest_played_song() -> void: latest_played_song += 1 if latest_played_song > song_object_array.size() - 1: latest_played_song = song_object_array.size() - 1 func update_last_played_song() -> void: latest_played_song = song_object_array.size() func get_preloaded_songs() -> int: var number_of_tracks_preloaded: int = 0 for song: SongObject in song_object_array: if !song.has_played: number_of_tracks_preloaded += 1 return number_of_tracks_preloaded func should_preload_more_songs() -> bool: return number_of_tracks_to_preload > get_preloaded_songs() func song_is_answered(song_no: int = currently_playing_song) -> void: # Nothing is playing yet (-1); a negative index would answer the last, unplayed song if song_no < 0 || song_no >= song_object_array.size(): return GameLog.debug("show_answer_pressed song_object: ", song_object_array[song_no]._to_string()) song_object_array[song_no].is_answered = true if Settings.add_to_stats && !Settings.is_offline(): GameLog.debug("add to stats: ", song_no) MusicServerClient.mark_song_played(song_no) func add_to_playlist(new_song_object: SongObject) -> void: song_object_array.append(new_song_object) func get_playlist() -> Array[SongObject]: if Settings.is_debug: return song_object_array else: var temp_list: Array[SongObject] = [] for s: SongObject in song_object_array: if s.has_played: temp_list.append(s) return temp_list func reset_playlist() -> void: currently_playing_song = -1 latest_played_song = 0 game_start_song = 0 clear_song_list() clear_song_files() func clear_song_list() -> void: song_object_array.clear() func unset_is_playing() -> void: for song_object: SongObject in song_object_array: song_object.is_playing = false func set_currently_playing_song(value: int) -> void: currently_playing_song = value func get_current_soundtrack_title() -> String: return song_object_array[currently_playing_song].get_soundtrack_title() func get_current_soundtrack_uuid() -> String: return song_object_array[currently_playing_song].get_soundtrack_uuid() func get_current_song_title() -> String: return song_object_array[currently_playing_song].get_song_title() func add_point(player_id: String) -> void: song_object_array[currently_playing_song].add_point(player_id) func remove_point(player_id: String) -> void: song_object_array[currently_playing_song].remove_point(player_id) ## Removes every player's points from every song, for a new game. func clear_points() -> void: for song_object: SongObject in song_object_array: song_object.players_given_point.clear() ## Removes a player's points from every song. func remove_player_from_list(player_id: String) -> void: for song_object: SongObject in song_object_array: song_object.remove_point(player_id) ## The song of [param song_no], read from its file. Returns null if the file is gone, so ## the song can be downloaded again. func get_song(song_no: int) -> AudioStream: var song_object: SongObject = song_object_array[song_no] if song_object.song_path.is_empty(): return song_object.song return AudioFile.load(song_object.song_path) func add_song_to_song_object(song_no: int, mp3: PackedByteArray) -> void: store_song(song_object_array[song_no], mp3) ## Keeps a downloaded song in a file in [method songs_folder]. If the file can't be ## written, the song is kept in memory instead. func store_song(song_object: SongObject, mp3: PackedByteArray) -> void: DirAccess.make_dir_recursive_absolute(songs_folder()) # Songs kept from a saved quiz already have files, which must not be written over var path: String = songs_folder().path_join("song_%d.mp3" % _song_files_written) while FileAccess.file_exists(path): _song_files_written += 1 path = songs_folder().path_join("song_%d.mp3" % _song_files_written) _song_files_written += 1 var file: FileAccess = FileAccess.open(path, FileAccess.WRITE) if file == null: GameLog.warning("Could not save a song to ", path, ", keeping it in memory: ", error_string(FileAccess.get_open_error())) var sound: AudioStreamMP3 = AudioStreamMP3.new() sound.data = mp3 song_object.song = sound song_object.song_path = "" return file.store_buffer(mp3) file.close() song_object.song = null song_object.song_path = path ## Deletes the files of the songs downloaded so far, except those in [param keep]. func clear_song_files(keep: PackedStringArray = []) -> void: if !DirAccess.dir_exists_absolute(songs_folder()): return for file_name: String in DirAccess.get_files_at(songs_folder()): var path: String = songs_folder().path_join(file_name) if !keep.has(path): DirAccess.remove_absolute(path) func song_has_played(song_no: int = latest_played_song) -> void: song_object_array[song_no].has_played = true func song_is_playing(song_no: int = latest_played_song) -> void: song_object_array[song_no].is_playing = true