From 7665929ed95d024533cb26e809b48d24a86b0aab Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Fri, 1 May 2020 15:45:28 +0930 Subject: [PATCH] RGTS parser mostly done, pre-scripts refactor --- FileLoader.gd | 123 ++++++++++++++++++++++++++++++++++--------------- Note.gd | 10 ++-- NoteHandler.gd | 2 +- project.godot | 2 +- 4 files changed, 92 insertions(+), 45 deletions(-) diff --git a/FileLoader.gd b/FileLoader.gd index f07a637..ef8cb7e 100644 --- a/FileLoader.gd +++ b/FileLoader.gd @@ -1,10 +1,10 @@ #extends Object extends Node -var userroot := "user://" if OS.get_name() != "Android" else "/storage/emulated/0/RhythmGame/" -# The following would probably work. One huge caveat is that permission needs to be manually granted by the user in app settings as we can't use OS.request_permission("WRITE_EXTERNAL_STORAGE") -# "/storage/emulated/0/Android/data/au.ufeff.rhythmgame/" -# "/sdcard/Android/data/au.ufeff.rhythmgame/" +var userroot := 'user://' if OS.get_name() != 'Android' else '/storage/emulated/0/RhythmGame/' +# The following would probably work. One huge caveat is that permission needs to be manually granted by the user in app settings as we can't use OS.request_permission('WRITE_EXTERNAL_STORAGE') +# '/storage/emulated/0/Android/data/au.ufeff.rhythmgame/' +# '/sdcard/Android/data/au.ufeff.rhythmgame/' func directory_list(directory: String, hidden: bool, sort:=true) -> Dictionary: # Sadly there's no filelist sugar so we make our own @@ -34,57 +34,79 @@ func directory_list(directory: String, hidden: bool, sort:=true) -> Dictionary: # Maybe convert the Arrays to PoolStringArrays? return output -func find_by_extensions(array, extensions) -> Dictionary: +func find_by_extensions(array, extensions=null) -> Dictionary: # Both args can be Array or PoolStringArray + # If extensions omitted, do all extensions var output = {} - for ext in extensions: - output[ext] = [] - for string in array: + if extensions: for ext in extensions: - if string.ends_with(ext): - output[ext].append(string) + output[ext] = [] + for filename in array: + for ext in extensions: + if filename.ends_with(ext): + output[ext].append(filename) + else: + for filename in array: + var ext = filename.rsplit('.', false, 1)[1] + if ext in output: + output[ext].append(filename) + else: + output[ext] = [filename] return output func scan_library(): - print("Scanning library") - var rootdir = userroot + "songs" + print('Scanning library') + var rootdir = userroot + 'songs' var dir = Directory.new() var err = dir.make_dir_recursive(rootdir) if err != OK: - print_debug("An error occurred while trying to create the songs directory: ", err) + print_debug('An error occurred while trying to create the songs directory: ', err) return err var songslist = directory_list(rootdir, false) if songslist.err != OK: - print("An error occurred when trying to access the songs directory: ", songslist.err) + print('An error occurred when trying to access the songs directory: ', songslist.err) return songslist.err var song_defs = {} + var collections = {} var song_images = {} var genres = {} dir.open(rootdir) for key in songslist.folders: - if dir.file_exists(key + "/song.json"): + if dir.file_exists(key + '/song.json'): # Our format - song_defs[key] = FileLoader.load_folder("%s/%s" % [rootdir, key]) - print("Loaded song directory: %s" % key) - song_images[key] = FileLoader.load_image("%s/%s/%s" % [rootdir, key, song_defs[key]["tile_filename"]]) - if song_defs[key]["genre"] in genres: - genres[song_defs[key]["genre"]].append(key) + song_defs[key] = FileLoader.load_folder('%s/%s' % [rootdir, key]) + print('Loaded song directory: %s' % key) + song_images[key] = FileLoader.load_image('%s/%s/%s' % [rootdir, key, song_defs[key]['tile_filename']]) + if song_defs[key]['genre'] in genres: + genres[song_defs[key]['genre']].append(key) else: - genres[song_defs[key]["genre"]] = [key] + genres[song_defs[key]['genre']] = [key] + elif dir.file_exists(key + '/collection.json'): + var collection = FileLoader.load_folder('%s/%s' % [rootdir, key], 'collection') + collections[key] = collection + var base_dict = {} # Top level of the collection dict contains defaults for every song in it + for key in collection.keys(): + if key != 'songs': + base_dict[key] = collection[key] + for song in collection['songs']: + var song_def = base_dict.duplicate() + song_defs[key] = song_def + for key in song.keys(): + song_def[key] = song[key] else: - var step_files = find_by_extensions(directory_list(rootdir + '/' + key, false).files, ['.sm']) - if len(step_files['.sm']) > 0: - var sm_filename = step_files['.sm'][0] + var files_by_ext = find_by_extensions(directory_list(rootdir + '/' + key, false).files) + if 'sm' in files_by_ext: + var sm_filename = files_by_ext['sm'][0] print(sm_filename) var thing = SM.load_file(rootdir + '/' + key + '/' + sm_filename) print(thing) pass else: - print("Found non-song directory: " + key) + print('Found non-song directory: ' + key) for file in songslist.files: - print("Found file: " + file) + print('Found file: ' + file) return {song_defs=song_defs, song_images=song_images, genres=genres} @@ -143,7 +165,7 @@ class SRT: ID3_SLIDE_ARC_ACW: slide_type = Note.SlideType.ARC_ACW _: - print("Unknown slide type: ", id3) + print('Unknown slide type: ', id3) var note = Note.NoteStar.new(time_hit, column) note.duration = duration notes.push_back(note) @@ -167,7 +189,7 @@ class RGT: const NOTE_TYPES = { 't': Note.NOTE_TAP, 'h': Note.NOTE_HOLD, - 's': Note.NOTE_SLIDE, + 's': Note.NOTE_STAR, 'e': Note.NOTE_SLIDE, 'b': Note.NOTE_TAP # Break } @@ -178,7 +200,18 @@ class RGT: '3': Note.SlideType.ARC_CW, # From Cirno master '4': Note.SlideType.CHORD, # Probably some weird loop etc. '5': Note.SlideType.CHORD, # Probably some weird loop etc. + '6': Note.SlideType.CHORD, # Probably some weird loop etc. + '7': Note.SlideType.CHORD, # Probably some weird loop etc. + '8': Note.SlideType.CHORD, # Probably some weird loop etc. + '9': Note.SlideType.CHORD, # Probably some weird loop etc. + 'a': Note.SlideType.CHORD, # Probably some weird loop etc. + 'b': Note.SlideType.CHORD, # Probably some weird loop etc. + 'c': Note.SlideType.CHORD, # Probably some weird loop etc. + 'd': Note.SlideType.CHORD_TRIPLE, # Triple cone. Spreads out to the adjacent receptors of the target. + 'e': Note.SlideType.CHORD, # Probably some weird loop etc. + 'f': Note.SlideType.CHORD, # Probably some weird loop etc. } + static func load_file(filename: String): var extension = filename.rsplit('.', false, 1)[1] if not EXTENSIONS.has(extension): @@ -190,23 +223,36 @@ class RGT: print(err) return err var length = file.get_len() + var chart_ids = [] var lines = [[]] + # This loop will segment the lines as if the file were RGTM while (file.get_position() < (length-1)): # Could probably replace this with file.eof_reached() var line : String = file.get_line() if line.begins_with('['): # Split to a new list for each chart definition + chart_ids.append(line.lstrip('[').rstrip(']')) lines.append([]) - lines[-1].append(line) + elif !line.empty(): + lines[-1].append(line) file.close() match format: Format.RGTS: - pass + var notes = parse_rgts(lines[0]) + return notes Format.RGTX: - pass + var notes = parse_rgtx(lines[0]) + return notes Format.RGTM: - pass + 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] return format + static func parse_rgtx(lines): + return [] # To be implemented later + static func parse_rgts(lines): var notes = [] var slide_ids = {} @@ -240,7 +286,7 @@ class RGT: var star = Note.NoteStar.new(time, column) note_hits.append(star) last_star[column] = star - var slide_type = n[0] # numeric digit, left as str just in case + var slide_type = n[0] # hex digit var slide_id = int(n.substr(1)) if slide_id > 0: slide_stars[slide_id] = star @@ -468,18 +514,19 @@ class Test: notes.push_back(Note.NoteTap.new(bar*4 + (i/8.0), (bar + i + 3)%8)) return notes -func load_folder(folder): + +func load_folder(folder, filename='song'): var file = File.new() - var err = file.open("%s/song.json" % folder, File.READ) + var err = file.open('%s/%s.json' % [folder, filename], File.READ) if err != OK: print(err) return err var result_json = JSON.parse(file.get_as_text()) file.close() if result_json.error != OK: - print("Error: ", result_json.error) - print("Error Line: ", result_json.error_line) - print("Error String: ", result_json.error_string) + print('Error: ', result_json.error) + print('Error Line: ', result_json.error_line) + print('Error String: ', result_json.error_string) return result_json.error var result = result_json.result result.directory = folder diff --git a/Note.gd b/Note.gd index 4bdf225..44aa42c 100644 --- a/Note.gd +++ b/Note.gd @@ -4,7 +4,7 @@ extends Node #class_name Note enum {NOTE_TAP, NOTE_HOLD, NOTE_STAR=2, NOTE_SLIDE=-2, NOTE_TOUCH=3, NOTE_TOUCH_HOLD=4, NOTE_ARROW, NOTE_ROLL} -enum SlideType {CHORD, ARC_CW, ARC_ACW} +enum SlideType {CHORD, ARC_CW, ARC_ACW, CHORD_TRIPLE} const DEATH_DELAY := 1.0 # This is touchy with the judgement windows and variable bpm. const RELEASE_SCORE_TYPES := { NOTE_HOLD: -NOTE_HOLD, @@ -122,7 +122,7 @@ class NoteSlide extends NoteBase: # Fancy charts have naked slides which necess func update_slide_variables(): match slide_type: - Note.SlideType.CHORD: + Note.SlideType.CHORD, Note.SlideType.CHORD_TRIPLE: values.start = GameTheme.RADIAL_UNIT_VECTORS[column] * GameTheme.receptor_ring_radius values.end = GameTheme.RADIAL_UNIT_VECTORS[column_release] * GameTheme.receptor_ring_radius values.angle = (values.end - values.start).angle() @@ -139,7 +139,7 @@ class NoteSlide extends NoteBase: # Fancy charts have naked slides which necess func get_position(progress: float) -> Vector2: match slide_type: - Note.SlideType.CHORD: + Note.SlideType.CHORD, Note.SlideType.CHORD_TRIPLE: return lerp(values.start, values.end, progress) Note.SlideType.ARC_CW: var circle_angle : float = lerp(values.start_a, values.end_a, progress) @@ -151,7 +151,7 @@ class NoteSlide extends NoteBase: # Fancy charts have naked slides which necess func get_angle(progress: float) -> float: match slide_type: - Note.SlideType.CHORD: + Note.SlideType.CHORD, Note.SlideType.CHORD_TRIPLE: return values.angle Note.SlideType.ARC_CW: var circle_angle : float = lerp(values.start_a, values.end_a, progress) @@ -164,7 +164,7 @@ class NoteSlide extends NoteBase: # Fancy charts have naked slides which necess func get_slide_length() -> float: # Return unit-circle (r=1) length of slide trail match slide_type: - Note.SlideType.CHORD: + Note.SlideType.CHORD, Note.SlideType.CHORD_TRIPLE: return 2*abs(sin((GameTheme.RADIAL_COL_ANGLES[column_release] - GameTheme.RADIAL_COL_ANGLES[column])/2)) Note.SlideType.ARC_CW: return fposmod(GameTheme.RADIAL_COL_ANGLES[column_release] - GameTheme.RADIAL_COL_ANGLES[column], TAU) diff --git a/NoteHandler.gd b/NoteHandler.gd index a2d353e..342ecb4 100644 --- a/NoteHandler.gd +++ b/NoteHandler.gd @@ -238,7 +238,7 @@ func make_slide_trail_mesh(note) -> ArrayMesh: colors[i*3+j] = Color(color.r, color.g, color.b, (1.0+float(i))/float(trail_length)) match note.slide_type: - Note.SlideType.CHORD: + Note.SlideType.CHORD, Note.SlideType.CHORD_TRIPLE: # Will need to split off triple at some point var angle : float = note.get_angle(0) var uv1o : Vector2 = polar2cartesian(size, angle) var uv2o : Vector2 = polar2cartesian(size, angle+PI/2.0) diff --git a/project.godot b/project.godot index ad87709..77a32b5 100644 --- a/project.godot +++ b/project.godot @@ -28,8 +28,8 @@ channel_disable_time=5.0 [autoload] Note="*res://Note.gd" -FileLoader="*res://FileLoader.gd" Rules="*res://Rules.gd" +FileLoader="*res://FileLoader.gd" GameTheme="*res://GameTheme.gd" SFXPlayer="*res://SFXPlayer.gd"