RGTS parser mostly done, pre-scripts refactor

This commit is contained in:
Luke Hubmayer-Werner 2020-05-01 15:45:28 +09:30
parent 16b1470a0e
commit 7665929ed9
4 changed files with 92 additions and 45 deletions

View File

@ -1,10 +1,10 @@
#extends Object #extends Object
extends Node extends Node
var userroot := "user://" if OS.get_name() != "Android" else "/storage/emulated/0/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") # 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/" # '/storage/emulated/0/Android/data/au.ufeff.rhythmgame/'
# "/sdcard/Android/data/au.ufeff.rhythmgame/" # '/sdcard/Android/data/au.ufeff.rhythmgame/'
func directory_list(directory: String, hidden: bool, sort:=true) -> Dictionary: func directory_list(directory: String, hidden: bool, sort:=true) -> Dictionary:
# Sadly there's no filelist sugar so we make our own # 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? # Maybe convert the Arrays to PoolStringArrays?
return output return output
func find_by_extensions(array, extensions) -> Dictionary: func find_by_extensions(array, extensions=null) -> Dictionary:
# Both args can be Array or PoolStringArray # Both args can be Array or PoolStringArray
# If extensions omitted, do all extensions
var output = {} var output = {}
for ext in extensions: if extensions:
output[ext] = []
for string in array:
for ext in extensions: for ext in extensions:
if string.ends_with(ext): output[ext] = []
output[ext].append(string) 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 return output
func scan_library(): func scan_library():
print("Scanning library") print('Scanning library')
var rootdir = userroot + "songs" var rootdir = userroot + 'songs'
var dir = Directory.new() var dir = Directory.new()
var err = dir.make_dir_recursive(rootdir) var err = dir.make_dir_recursive(rootdir)
if err != OK: 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 return err
var songslist = directory_list(rootdir, false) var songslist = directory_list(rootdir, false)
if songslist.err != OK: 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 return songslist.err
var song_defs = {} var song_defs = {}
var collections = {}
var song_images = {} var song_images = {}
var genres = {} var genres = {}
dir.open(rootdir) dir.open(rootdir)
for key in songslist.folders: for key in songslist.folders:
if dir.file_exists(key + "/song.json"): if dir.file_exists(key + '/song.json'):
# Our format # Our format
song_defs[key] = FileLoader.load_folder("%s/%s" % [rootdir, key]) song_defs[key] = FileLoader.load_folder('%s/%s' % [rootdir, key])
print("Loaded song directory: %s" % key) print('Loaded song directory: %s' % key)
song_images[key] = FileLoader.load_image("%s/%s/%s" % [rootdir, key, song_defs[key]["tile_filename"]]) song_images[key] = FileLoader.load_image('%s/%s/%s' % [rootdir, key, song_defs[key]['tile_filename']])
if song_defs[key]["genre"] in genres: if song_defs[key]['genre'] in genres:
genres[song_defs[key]["genre"]].append(key) genres[song_defs[key]['genre']].append(key)
else: 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: else:
var step_files = find_by_extensions(directory_list(rootdir + '/' + key, false).files, ['.sm']) var files_by_ext = find_by_extensions(directory_list(rootdir + '/' + key, false).files)
if len(step_files['.sm']) > 0: if 'sm' in files_by_ext:
var sm_filename = step_files['.sm'][0] var sm_filename = files_by_ext['sm'][0]
print(sm_filename) print(sm_filename)
var thing = SM.load_file(rootdir + '/' + key + '/' + sm_filename) var thing = SM.load_file(rootdir + '/' + key + '/' + sm_filename)
print(thing) print(thing)
pass pass
else: else:
print("Found non-song directory: " + key) print('Found non-song directory: ' + key)
for file in songslist.files: for file in songslist.files:
print("Found file: " + file) print('Found file: ' + file)
return {song_defs=song_defs, song_images=song_images, genres=genres} return {song_defs=song_defs, song_images=song_images, genres=genres}
@ -143,7 +165,7 @@ class SRT:
ID3_SLIDE_ARC_ACW: ID3_SLIDE_ARC_ACW:
slide_type = Note.SlideType.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) var note = Note.NoteStar.new(time_hit, column)
note.duration = duration note.duration = duration
notes.push_back(note) notes.push_back(note)
@ -167,7 +189,7 @@ class RGT:
const NOTE_TYPES = { const NOTE_TYPES = {
't': Note.NOTE_TAP, 't': Note.NOTE_TAP,
'h': Note.NOTE_HOLD, 'h': Note.NOTE_HOLD,
's': Note.NOTE_SLIDE, 's': Note.NOTE_STAR,
'e': Note.NOTE_SLIDE, 'e': Note.NOTE_SLIDE,
'b': Note.NOTE_TAP # Break 'b': Note.NOTE_TAP # Break
} }
@ -178,7 +200,18 @@ class RGT:
'3': Note.SlideType.ARC_CW, # From Cirno master '3': Note.SlideType.ARC_CW, # From Cirno master
'4': Note.SlideType.CHORD, # Probably some weird loop etc. '4': Note.SlideType.CHORD, # Probably some weird loop etc.
'5': 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): static func load_file(filename: String):
var extension = filename.rsplit('.', false, 1)[1] var extension = filename.rsplit('.', false, 1)[1]
if not EXTENSIONS.has(extension): if not EXTENSIONS.has(extension):
@ -190,23 +223,36 @@ class RGT:
print(err) print(err)
return err return err
var length = file.get_len() var length = file.get_len()
var chart_ids = []
var lines = [[]] 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() while (file.get_position() < (length-1)): # Could probably replace this with file.eof_reached()
var line : String = file.get_line() var line : String = file.get_line()
if line.begins_with('['): # Split to a new list for each chart definition if line.begins_with('['): # Split to a new list for each chart definition
chart_ids.append(line.lstrip('[').rstrip(']'))
lines.append([]) lines.append([])
lines[-1].append(line) elif !line.empty():
lines[-1].append(line)
file.close() file.close()
match format: match format:
Format.RGTS: Format.RGTS:
pass var notes = parse_rgts(lines[0])
return notes
Format.RGTX: Format.RGTX:
pass var notes = parse_rgtx(lines[0])
return notes
Format.RGTM: 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 return format
static func parse_rgtx(lines):
return [] # To be implemented later
static func parse_rgts(lines): static func parse_rgts(lines):
var notes = [] var notes = []
var slide_ids = {} var slide_ids = {}
@ -240,7 +286,7 @@ class RGT:
var star = Note.NoteStar.new(time, column) var star = Note.NoteStar.new(time, column)
note_hits.append(star) note_hits.append(star)
last_star[column] = 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)) var slide_id = int(n.substr(1))
if slide_id > 0: if slide_id > 0:
slide_stars[slide_id] = star 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)) notes.push_back(Note.NoteTap.new(bar*4 + (i/8.0), (bar + i + 3)%8))
return notes return notes
func load_folder(folder):
func load_folder(folder, filename='song'):
var file = File.new() 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: if err != OK:
print(err) print(err)
return err return err
var result_json = JSON.parse(file.get_as_text()) var result_json = JSON.parse(file.get_as_text())
file.close() file.close()
if result_json.error != OK: if result_json.error != OK:
print("Error: ", result_json.error) print('Error: ', result_json.error)
print("Error Line: ", result_json.error_line) print('Error Line: ', result_json.error_line)
print("Error String: ", result_json.error_string) print('Error String: ', result_json.error_string)
return result_json.error return result_json.error
var result = result_json.result var result = result_json.result
result.directory = folder result.directory = folder

10
Note.gd
View File

@ -4,7 +4,7 @@ extends Node
#class_name Note #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 {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 DEATH_DELAY := 1.0 # This is touchy with the judgement windows and variable bpm.
const RELEASE_SCORE_TYPES := { const RELEASE_SCORE_TYPES := {
NOTE_HOLD: -NOTE_HOLD, NOTE_HOLD: -NOTE_HOLD,
@ -122,7 +122,7 @@ class NoteSlide extends NoteBase: # Fancy charts have naked slides which necess
func update_slide_variables(): func update_slide_variables():
match slide_type: 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.start = GameTheme.RADIAL_UNIT_VECTORS[column] * GameTheme.receptor_ring_radius
values.end = GameTheme.RADIAL_UNIT_VECTORS[column_release] * GameTheme.receptor_ring_radius values.end = GameTheme.RADIAL_UNIT_VECTORS[column_release] * GameTheme.receptor_ring_radius
values.angle = (values.end - values.start).angle() 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: func get_position(progress: float) -> Vector2:
match slide_type: match slide_type:
Note.SlideType.CHORD: Note.SlideType.CHORD, Note.SlideType.CHORD_TRIPLE:
return lerp(values.start, values.end, progress) return lerp(values.start, values.end, progress)
Note.SlideType.ARC_CW: Note.SlideType.ARC_CW:
var circle_angle : float = lerp(values.start_a, values.end_a, progress) 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: func get_angle(progress: float) -> float:
match slide_type: match slide_type:
Note.SlideType.CHORD: Note.SlideType.CHORD, Note.SlideType.CHORD_TRIPLE:
return values.angle return values.angle
Note.SlideType.ARC_CW: Note.SlideType.ARC_CW:
var circle_angle : float = lerp(values.start_a, values.end_a, progress) 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: func get_slide_length() -> float:
# Return unit-circle (r=1) length of slide trail # Return unit-circle (r=1) length of slide trail
match slide_type: 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)) return 2*abs(sin((GameTheme.RADIAL_COL_ANGLES[column_release] - GameTheme.RADIAL_COL_ANGLES[column])/2))
Note.SlideType.ARC_CW: Note.SlideType.ARC_CW:
return fposmod(GameTheme.RADIAL_COL_ANGLES[column_release] - GameTheme.RADIAL_COL_ANGLES[column], TAU) return fposmod(GameTheme.RADIAL_COL_ANGLES[column_release] - GameTheme.RADIAL_COL_ANGLES[column], TAU)

View File

@ -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)) colors[i*3+j] = Color(color.r, color.g, color.b, (1.0+float(i))/float(trail_length))
match note.slide_type: 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 angle : float = note.get_angle(0)
var uv1o : Vector2 = polar2cartesian(size, angle) var uv1o : Vector2 = polar2cartesian(size, angle)
var uv2o : Vector2 = polar2cartesian(size, angle+PI/2.0) var uv2o : Vector2 = polar2cartesian(size, angle+PI/2.0)

View File

@ -28,8 +28,8 @@ channel_disable_time=5.0
[autoload] [autoload]
Note="*res://Note.gd" Note="*res://Note.gd"
FileLoader="*res://FileLoader.gd"
Rules="*res://Rules.gd" Rules="*res://Rules.gd"
FileLoader="*res://FileLoader.gd"
GameTheme="*res://GameTheme.gd" GameTheme="*res://GameTheme.gd"
SFXPlayer="*res://SFXPlayer.gd" SFXPlayer="*res://SFXPlayer.gd"