RGTS parser mostly done, pre-scripts refactor
This commit is contained in:
parent
16b1470a0e
commit
7665929ed9
123
FileLoader.gd
123
FileLoader.gd
|
@ -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
10
Note.gd
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue