diff --git a/project.godot b/project.godot index ea43c42..c07f30d 100644 --- a/project.godot +++ b/project.godot @@ -30,6 +30,7 @@ channel_disable_time=5.0 Note="*res://scripts/Note.gd" Rules="*res://scripts/Rules.gd" FileLoader="*res://scripts/FileLoader.gd" +Library="*res://scripts/Library.gd" GameTheme="*res://scripts/GameTheme.gd" SFXPlayer="*res://scripts/SFXPlayer.gd" diff --git a/scripts/FileLoader.gd b/scripts/FileLoader.gd index ef8cb7e..29b99c6 100644 --- a/scripts/FileLoader.gd +++ b/scripts/FileLoader.gd @@ -54,6 +54,7 @@ func find_by_extensions(array, extensions=null) -> Dictionary: output[ext] = [filename] return output +const default_difficulty_keys = ['Z', 'B', 'A', 'E', 'M', 'R'] func scan_library(): print('Scanning library') var rootdir = userroot + 'songs' @@ -83,6 +84,12 @@ func scan_library(): genres[song_defs[key]['genre']].append(key) else: genres[song_defs[key]['genre']] = [key] + if typeof(song_defs[key]['chart_difficulties']) == TYPE_ARRAY: + var diffs = song_defs[key]['chart_difficulties'] + var chart_difficulties = {} + for i in min(len(diffs), len(default_difficulty_keys)): + chart_difficulties[default_difficulty_keys[i]] = diffs[i] + song_defs[key]['chart_difficulties'] = chart_difficulties elif dir.file_exists(key + '/collection.json'): var collection = FileLoader.load_folder('%s/%s' % [rootdir, key], 'collection') collections[key] = collection @@ -90,11 +97,17 @@ func scan_library(): for key in collection.keys(): if key != 'songs': base_dict[key] = collection[key] - for song in collection['songs']: + for song_key in collection['songs'].keys(): + var song_dict = collection['songs'][song_key] var song_def = base_dict.duplicate() - song_defs[key] = song_def - for key in song.keys(): - song_def[key] = song[key] + song_defs[song_key] = song_def + for key in song_dict.keys(): + song_def[key] = song_dict[key] + song_images[song_key] = FileLoader.load_image('%s/%s/%s.png' % [rootdir, key, song_key]) + if song_defs[song_key]['genre'] in genres: + genres[song_defs[song_key]['genre']].append(song_key) + else: + genres[song_defs[song_key]['genre']] = [song_key] else: var files_by_ext = find_by_extensions(directory_list(rootdir + '/' + key, false).files) if 'sm' in files_by_ext: @@ -244,10 +257,10 @@ class RGT: return notes Format.RGTM: lines.pop_front() # Anything before the first [header] is meaningless - var charts = [] - for c in lines: - charts.append(parse_rgts(c)) - return [chart_ids, charts] + var charts = {} + for i in len(lines): + charts[chart_ids[i]] = parse_rgts(lines[i]) + return charts return format static func parse_rgtx(lines): @@ -532,6 +545,30 @@ func load_folder(folder, filename='song'): result.directory = folder return result +func load_filelist(filelist: Array): + var charts = {} + var key := 1 + for filename in filelist: + var extension: String = filename.rsplit('.', true, 1)[-1] + match extension: + 'rgtm': # multiple charts + var res = RGT.load_file(filename) + for key in res: + charts[key] = res[key] + 'rgts', 'rgtx': # single chart + charts[key] = RGT.load_file(filename) + key += 1 + 'srt': # maimai, single chart + charts[key] = SRT.load_file(filename) + key += 1 + 'sm': # Stepmania, multiple charts + var res = SM.load_file(filename) + for key in res: + charts[key] = res[key] + _: + pass + return charts + func load_ogg(filename) -> AudioStreamOGGVorbis: var audiostream = AudioStreamOGGVorbis.new() diff --git a/scripts/Library.gd b/scripts/Library.gd new file mode 100644 index 0000000..a5fdf0e --- /dev/null +++ b/scripts/Library.gd @@ -0,0 +1,121 @@ +extends Node + +class MultilangStr: + # Automatically propogate higher langs to lower ones if lower ones are missing. + # e.g. if we don't have a proper english title, return the transliterated one instead + # If I could alias properties, these would have their full names as well, but no point duplicating variables for the longform. + var n := '' setget set_native + var tl := '' setget set_translit + var en := '' setget set_english + func _init(native='', translit='', english=''): + self.n = native + if not translit.empty(): + self.tl = translit + if not english.empty: + self.en = english +# func get_native() -> String: +# return n +# func get_translit() -> String: +# return tl if tl else n +# func get_english() -> String: +# return en if en else self.tl + func set_native(native) -> void: + n = native + if tl.empty(): + tl = native + func set_translit(translit) -> void: + tl = translit + if en.empty(): + en = translit + func set_english(english) -> void: + en = english + +class Song: + var title: MultilangStr + var subtitle: MultilangStr + var artist: MultilangStr + var BPM: float + var bpm_beats: Array + var bpm_values: Array + var dynamic_bpm: bool + var genre: String + var tile_filename: String + var audio_filelist: Array + var video_filelist: Array + var chart_filelist: Array + var audio_offsets: Array + var video_offsets: Array + var audio_preview_times: Array + var video_dimensions: Array + var chart_difficulties: Dictionary + const default_difficulty_keys = ['Z', 'B', 'A', 'E', 'M', 'R'] + + func _init(values: Dictionary): + title = MultilangStr.new(values.get('title', ''), values.get('title_transliteration', ''), values.get('title_english', '')) + subtitle = MultilangStr.new(values.get('subtitle', ''), values.get('subtitle_transliteration', ''), values.get('subtitle_english', '')) + artist = MultilangStr.new(values.get('artist', ''), values.get('artist_transliteration', ''), values.get('artist_english', '')) + + dynamic_bpm = false + if 'bpm_values' in values: + bpm_values = values['bpm_values'] + BPM = bpm_values[0] + bpm_beats = values.get('bpm_beats', [0.0]) + dynamic_bpm = true if len(bpm_beats) > 1 and len(bpm_beats)==len(bpm_values) else false + if 'bpm' in values: + BPM = values['bpm'] + + tile_filename = values.get('tile_filename', '%s.png'%values.get('index', 'tile')) + audio_filelist = values.get('audio_filelist', ['%s.ogg'%values.get('index', 'audio')]) + video_filelist = values.get('video_filelist', ['%s.webm'%values.get('index', 'video')]) + video_dimensions = values.get('video_dimensions', [1.0, 1.0]) + audio_preview_times = values.get('video_dimensions', [1.0, 1.0]) + genre = values.get('genre', 'None') + + chart_filelist = values.get('chart_filelist', ['%s.rtgm'%values.get('index', 'charts')]) + + var diffs = values['chart_difficulties'] + match typeof(diffs): + TYPE_DICTIONARY: + chart_difficulties = diffs + TYPE_ARRAY: + chart_difficulties = {} + for i in min(len(diffs), len(default_difficulty_keys)): + chart_difficulties[default_difficulty_keys[i]] = diffs[i] + _: + print_debug('Invalid chart_difficulties!', title.en) + chart_difficulties = {} + + func get_BPM(realtime:=0.0): + if not dynamic_bpm: + return BPM + # TODO: some dynamic behaviour when all that jazz is implemented + + +var all_songs = {} +var genre_ids = {} +var genre_titles = [] +var genre_songs = [] + +var tile_tex_cache = {} # We'll need some way of managing this later since holding all the tiles in memory might be expensive +var charts_cache = {} + +func get_song_tile_texture(song_key): + if song_key in tile_tex_cache: + return tile_tex_cache[song_key] + elif song_key in all_songs: + tile_tex_cache[song_key] = load(all_songs[song_key].tile_filename) + return tile_tex_cache[song_key] + else: + print_debug('Invalid song_key: ', song_key) + +func get_song_charts(song_key): + if song_key in charts_cache: + return charts_cache[song_key] + elif song_key in all_songs: + charts_cache[song_key] = FileLoader.load_filelist(all_songs[song_key].chart_filelist) + return charts_cache[song_key] + else: + print_debug('Invalid song_key: ', song_key) + +func initialize(): + pass diff --git a/scripts/Menu.gd b/scripts/Menu.gd index e293d65..355c8ab 100644 --- a/scripts/Menu.gd +++ b/scripts/Menu.gd @@ -111,8 +111,8 @@ func _ready(): # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): var diff = selected_song - (selected_song_vis + selected_song_delta) - selected_song_speed = sign(diff)*ease(abs(diff), 2)*10 - selected_song_delta += selected_song_speed * delta + selected_song_speed = ease(abs(diff), 1)*10 + selected_song_delta += sign(diff) * selected_song_speed * delta if selected_song_delta > 0.5: selected_song_delta -= 1.0 selected_song_vis += 1 @@ -139,9 +139,9 @@ func draw_songtile(song_key, position, size, title_text:=false, difficulty=selec draw_rect(Rect2(position.x - outline_px, position.y - outline_px, size + outline_px*2, size + outline_px*2), diff_color) draw_texture_rect(song_images[song_key], rect, false) # Draw track difficulty rating - draw_string_centered(GenreFont, Vector2(position.x+size-24, position.y+size-56), diffstr(song_defs[song_key]["chart_difficulties"][difficulty]), diff_color) + draw_string_centered(GenreFont, Vector2(position.x+size-24, position.y+size-56), song_defs[song_key]['chart_difficulties'].get(Library.Song.default_difficulty_keys[difficulty], 0), diff_color) if title_text: - draw_string_centered(TitleFont, Vector2(position.x+size/2.0, position.y+size), song_defs[song_key]["title"], Color(0.95, 0.95, 1.0)) + draw_string_centered(TitleFont, Vector2(position.x+size/2.0, position.y+size), song_defs[song_key]['title'], Color(0.95, 0.95, 1.0)) return rect func diffstr(difficulty: float): @@ -155,7 +155,7 @@ func _draw_song_select(center: Vector2) -> Array: var spacer_y = 64 var sel_scales := [1.0, 0.8, 0.64, 0.512, 0.4096] var bg_scales := [0.64, 0.64, 0.64, 0.512, 0.4096] - var gy := center.y + var gy := center.y -250 var touchrects := [] for g in len(genres):