1
0
mirror of synced 2025-02-03 05:07:17 +01:00

Add support for multiplayer charts (STYLE:{Single,Double}, # START {P1,P2}) (#23)

This PR adds support for multiplayer charts, and adds a new multiplayer
TJA/fumen combo for testing.

This PR is quite small, because the only work that needed to be done is
parsing the course metadata. Once the TJA lines are split into courses,
the actual course-by-course parsing logic is identical to the songs that
came before.

Fixes #6.
This commit is contained in:
Viv 2023-07-05 16:03:41 -04:00 committed by GitHub
parent d9b1476f4d
commit ce633253ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 719 additions and 11 deletions

View File

@ -33,12 +33,17 @@ def main(argv=None):
# Generate output filenames # Generate output filenames
baseName = os.path.splitext(fnameTJA)[0] baseName = os.path.splitext(fnameTJA)[0]
outputFilenames = [baseName + f"_{COURSE_IDS[course]}.bin" if len(parsedSongsTJA) > 1 outputFilenames = []
else baseName + ".bin" for courseName, fumenData in parsedSongsFumen.items():
for course in parsedSongsFumen.keys()] if len(parsedSongsTJA) == 1:
outputName = f"{baseName}.bin"
# Write fumen data to files else:
for fumenData, outputName in zip(parsedSongsFumen.values(), outputFilenames): splitName = courseName.split("P") # e.g. 'OniP2' -> ['Oni', '2'], 'Oni' -> ['Oni']
outputName = f"{baseName}_{COURSE_IDS[splitName[0]]}"
if len(splitName) == 2:
outputName += f"_{splitName[1]}" # Add "_1" or "_2" if P1/P2 chart
outputName += ".bin"
outputFilenames.append(outputName)
writeFumen(outputName, fumenData) writeFumen(outputName, fumenData)
if return_vars: if return_vars:

View File

@ -28,6 +28,7 @@ def parseTJA(fnameTJA):
def getCourseData(lines): def getCourseData(lines):
courses = {} courses = {}
currentCourse = '' currentCourse = ''
currentCourseCached = ''
songBPM = 0 songBPM = 0
songOffset = 0 songOffset = 0
@ -47,6 +48,7 @@ def getCourseData(lines):
# Course-specific header fields # Course-specific header fields
elif nameUpper == 'COURSE': elif nameUpper == 'COURSE':
currentCourse = NORMALIZE_COURSE[value] currentCourse = NORMALIZE_COURSE[value]
currentCourseCached = currentCourse
if currentCourse not in courses.keys(): if currentCourse not in courses.keys():
courses[currentCourse] = { courses[currentCourse] = {
'metadata': {'course': currentCourse, 'bpm': songBPM, 'offset': songOffset, 'level': 0, 'metadata': {'course': currentCourse, 'bpm': songBPM, 'offset': songOffset, 'level': 0,
@ -63,12 +65,10 @@ def getCourseData(lines):
if value: if value:
balloons = [int(v) for v in value.split(",") if v] balloons = [int(v) for v in value.split(",") if v]
courses[currentCourse]['metadata']['balloon'] = balloons courses[currentCourse]['metadata']['balloon'] = balloons
# STYLE is a P1/P2 command, which we don't support yet, so normally this would be a
# NotImplemetedError. However, TakoTako outputs `STYLE:SINGLE` when converting Ura
# charts, so throwing an error here would prevent Ura charts from being converted.
# See: https://github.com/vivaria/tja2fumen/issues/15#issuecomment-1575341088
elif nameUpper == 'STYLE': elif nameUpper == 'STYLE':
pass # Reset the course name to remove "P1/P2" that may have been added by a previous STYLE:DOUBLE chart
if value == 'Single':
currentCourse = currentCourseCached
else: else:
pass # Ignore other header fields such as 'TITLE', 'SUBTITLE', 'WAVE', etc. pass # Ignore other header fields such as 'TITLE', 'SUBTITLE', 'WAVE', etc.
@ -79,11 +79,25 @@ def getCourseData(lines):
if match_command: if match_command:
nameUpper = match_command.group(1).upper() nameUpper = match_command.group(1).upper()
value = match_command.group(2).strip() if match_command.group(2) else '' value = match_command.group(2).strip() if match_command.group(2) else ''
# For STYLE:Double, #START P1/P2 indicates the start of a new chart
# But, we want multiplayer charts to inherit the metadata from the course as a whole, so we deepcopy
if nameUpper == "START" and value in ["P1", "P2"]:
currentCourse = currentCourseCached + value
courses[currentCourse] = deepcopy(courses[currentCourseCached])
courses[currentCourse]['data'] = list() # Keep the metadata, but reset the note data
value = '' # Once we've made the new course, we can reset this to a normal #START command
elif match_notes: elif match_notes:
nameUpper = 'NOTES' nameUpper = 'NOTES'
value = match_notes.group(1) value = match_notes.group(1)
courses[currentCourse]['data'].append({"name": nameUpper, "value": value}) courses[currentCourse]['data'].append({"name": nameUpper, "value": value})
# If a course has no song data, then this is likely because the course has "STYLE: Double" but no "STYLE: Single".
# To fix this, we copy over the P1 chart from "STYLE: Double" to fill the "STYLE: Single" role.
for courseName, course in courses.items():
if not course['data']:
if courseName+"P1" in courses.keys():
courses[courseName] = deepcopy(courses[courseName+"P1"])
return courses return courses

688
testing/data/senpac.tja Normal file
View File

@ -0,0 +1,688 @@
BPM:160
OFFSET:-1.705
COURSE:Edit
LEVEL:10
STYLE:Double
BALLOON:12
SCOREINIT:430
SCOREDIFF:112
#START P1
10000201,
10100220,
1000002220002010,
1000100000111020,
10000201,
10100220,
1000222000200020,
#MEASURE 2/4
1010,
#MEASURE 4/4
300000000000000111200000,
1112121211121222,
1112121211211212,
1112111212211212,
1112111212121000,
1112121211121222,
1212111212121112,
1112111212221222,
1112111212121110,
3003003000303030,
#MEASURE 2/4
,
#MEASURE 4/4
1010221010102210,
1010221020111020,
1010221010102210,
1010221010222220,
1010221010102210,
1010221020111020,
1010221010102210,
1000000010212121,
20011020,
1000001110100010,
10011020,
1000001110201000,
1020102210201011,
1020102210201011,
1020102210201011,
1022102121212111,
1000000030000022,
#GOGOSTART
1010001010221020,
1022101110102000,
1110201010221020,
1000700000000800,
1020112010222000,
1020112010222000,
1122002011220020,
1022102210221110,
1020112011111020,
1022102011111000,
1020112011111020,
1022121010221210,
1000201000102220,
1000201010101111,
1000202000002220,
3000202000002220,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
1112121211121212,
1121121211211212,
1112111211121112,
1122112212121212,
1212111212121112,
1212112112121121,
2211221122112221,
1112111212121222,
1221221022121210,
3,
#END
#START P2
10000201,
10100220,
1000002220002010,
1000100000111020,
10000201,
10100220,
1000222000200020,
#MEASURE 2/4
1010,
#MEASURE 4/4
300000000000000111200000,
1112121211121222,
1112121211211212,
1112111212211212,
1112111212103000,
1212111212121112,
1112121211211212,
1112111212221222,
1112111212121110,
3003003000303030,
#MEASURE 2/4
,
#MEASURE 4/4
1010102210101022,
1010102210201220,
1010102210101022,
1010102210112220,
1010102210101022,
1010102210202220,
1010102210101022,
1000000010212121,
20011020,
1000001110100010,
10011020,
1000001110001020,
1011202010102010,
1011201020101020,
1011201010112000,
1112111212121000,
3000000030000022,
#GOGOSTART
1022102010100010,
1110102011201000,
1022102010102210,
1020101011103000,
3011201020112010,
1011201020112010,
1000112210001122,
1000111011102020,
1022102010100010,
1110102011201020,
1022102011102020,
1122102011221020,
1000102210201110,
1020102210201110,
3000202000002220,
3000202000002220,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
1212111212121112,
1212112112121121,
2211221122112221,
1112111212121212,
1112121211121212,
1121121211211212,
1112111211121112,
1122112212121222,
1221221022121210,
3,
#END
COURSE:Oni
LEVEL:10
STYLE:Double
BALLOON:12
SCOREINIT:430
SCOREDIFF:112
#START P1
10000201,
10100220,
1000002220002010,
1000100000111020,
10000201,
10100220,
1000222000200020,
#MEASURE 2/4
1010,
#MEASURE 4/4
300000000000000111200000,
1112121211121222,
1112121211211212,
1112111212211212,
1112111212121000,
1112121211121222,
1212111212121112,
1112111212221222,
1112111212121110,
3003003000303030,
#MEASURE 2/4
,
#MEASURE 4/4
1010221010102210,
1010221020111020,
1010221010102210,
1010221010222220,
1010221010102210,
1010221020111020,
1010221010102210,
1000000010212121,
20011020,
1000001110100010,
10011020,
1000001110201000,
1020102210201011,
1020102210201011,
1020102210201011,
1022102121212111,
1000000030000022,
#GOGOSTART
1010001010221020,
1022101110102000,
1110201010221020,
1000700000000800,
1020112010222000,
1020112010222000,
1122002011220020,
1022102210221110,
1020112011111020,
1022102011111000,
1020112011111020,
1022121010221210,
1000201000102220,
1000201010101111,
1000202000002220,
3000202000002220,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
1112121211121212,
1121121211211212,
1112111211121112,
1122112212121212,
1212111212121112,
1212112112121121,
2211221122112221,
1112111212121222,
1221221022121210,
3,
#END
#START P2
10000201,
10100220,
1000002220002010,
1000100000111020,
10000201,
10100220,
1000222000200020,
#MEASURE 2/4
1010,
#MEASURE 4/4
300000000000000111200000,
1112121211121222,
1112121211211212,
1112111212211212,
1112111212103000,
1212111212121112,
1112121211211212,
1112111212221222,
1112111212121110,
3003003000303030,
#MEASURE 2/4
,
#MEASURE 4/4
1010102210101022,
1010102210201220,
1010102210101022,
1010102210112220,
1010102210101022,
1010102210202220,
1010102210101022,
1000000010212121,
20011020,
1000001110100010,
10011020,
1000001110001020,
1011202010102010,
1011201020101020,
1011201010112000,
1112111212121000,
3000000030000022,
#GOGOSTART
1022102010100010,
1110102011201000,
1022102010102210,
1020101011103000,
3011201020112010,
1011201020112010,
1000112210001122,
1000111011102020,
1022102010100010,
1110102011201020,
1022102011102020,
1122102011221020,
1000102210201110,
1020102210201110,
3000202000002220,
3000202000002220,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
1212111212121112,
1212112112121121,
2211221122112221,
1112111212121212,
1112121211121212,
1121121211211212,
1112111211121112,
1122112212121222,
1221221022121210,
3,
#END
STYLE:Single
BALLOON:
SCOREINIT:590
SCOREDIFF:157
#START
10000201,
10100220,
1000002220002010,
1000100000111020,
10000201,
10100220,
1000222000200020,
#MEASURE 2/4
1010,
#MEASURE 4/4
300000000000000111200000,
1112121211121222,
1112121211211212,
1112111212211212,
1112111212121000,
1112121211121222,
1112121211121212,
1112111212221222,
1112111212121110,
3003003000303030,
#MEASURE 2/4
,
#MEASURE 4/4
1010221010102210,
1010221020111020,
1010221010102210,
1010221010221120,
1010221010102210,
1010221020111020,
1010221010102211,
1000000010212121,
20011020,
1000001110200020,
10011020,
1000001110222020,
1020102210201011,
1020102210201011,
1020102210201011,
1022102121212111,
1000000030000022,
#GOGOSTART
1022102010112010,
1110102011201020,
1022101020102210,
1020101011103000,
3011201020112010,
1011201020112010,
1000112210001122,
1020112011122020,
1022102010112010,
1110102011201020,
1022102011102020,
1122102011221020,
1020102210201110,
1020102210221110,
3000202000002220,
3000202000002220,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
1112121211121212,
1121121211211212,
1112111211121112,
1122112212121212,
1112121211121212,
1112112112121121,
2211221122112212,
1112111212121222,
1221221022121210,
3,
#END
COURSE:Hard
LEVEL:8
BALLOON:8
SCOREINIT:610
SCOREDIFF:165
#START
30000201,
10100220,
10022021,
10100111,
10011201,
10100220,
10220202,
#MEASURE 2/4
10,
#MEASURE 4/4
3004,
1110111011011020,
1110111011101000,
1110111022202220,
1110111011103000,
1110111011011020,
1110111011101000,
1110111022202220,
1101101011101000,
3003003000303030,
#MEASURE 2/4
,
#MEASURE 4/4
1010201000111010,
1010201000111000,
1010201000111010,
1010201000222000,
1010201000111010,
1010201000111010,
11211121,
1000000011111000,
10011020,
1000001110000000,
10011020,
1000001110002000,
12121110,
12121010,
12101210,
500000000000000000000000000000000000000000000008,
03,
#GOGOSTART
1022202010111000,
1110202011102000,
1022202010111000,
1000700000000800,
3011101000200020,
1011101000222000,
1110200011102000,
1110111011102000,
1022202010111010,
1110202011102000,
1022202011101000,
3333,
3022202011101000,
1110202011102000,
30200220,
30200220,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
1110111011011020,
1110111011101000,
1110111022202220,
1110111011103000,
1110111011011020,
1110111011111000,
1110111022202220,
1101101101102000,
3003003000303030,
3,
,
,
,
,
,
,
#END
COURSE:Normal
LEVEL:5
BALLOON:8
SCOREINIT:710
SCOREDIFF:217
#START
11,
10100220,
11,
10100220,
11,
10100220,
11,
#MEASURE 2/4
11,
#MEASURE 4/4
3004,
11101110,
11101010,
11101110,
11111030,
11101110,
22202020,
11101110,
11111000,
3003003000303030,
#MEASURE 2/4
,
#MEASURE 4/4
11010110,
1011,
11010110,
12,
11010110,
1011,
11010110,
3,
10011000,
22,
10011000,
22,
10111010,
10111000,
10111010,
500000000000000000000000000000000000000000000008,
03,
#GOGOSTART
10222020,
1222,
10222020,
7000000000000800,
10100220,
10100220,
11,
1111,
10222020,
1222,
10222020,
3333,
30100220,
10100220,
30000220,
30000220,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
11101110,
11101010,
11101110,
11111030,
11101110,
22202020,
11101110,
11111030,
3003003000303030,
3,
,
,
,
,
,
,
#END
COURSE:Easy
LEVEL:4
BALLOON:
SCOREINIT:700
SCOREDIFF:280
#START
11,
1110,
11,
1,
11,
1110,
11,
#MEASURE 2/4
1,
#MEASURE 4/4
30,
1110,
11,
1110,
11,
2220,
22,
2220,
22,
3033,
#MEASURE 2/4
,
#MEASURE 4/4
1101,
12,
1101,
12,
1101,
12,
1101,
1,
11,
22,
11,
22,
1011,
1011,
11,
500000000000000000000000000000000000000000000008,
03,
#GOGOSTART
1202,
1202,
1202,
500000000000000000000008000000000000000000000000,
1120,
1120,
11,
1120,
1202,
1202,
1202,
3330,
1120,
1120,
34,
34,
5,
000000000000000000000000000000000008000000000000,
#GOGOEND
1111,
11,
1111,
11,
2222,
22,
2222,
22,
3330,
3,
,
,
,
,
,
,
#END

BIN
testing/data/senpac.zip Normal file

Binary file not shown.

View File

@ -12,6 +12,7 @@ from tja2fumen.constants import COURSE_IDS, NORMALIZE_COURSE, simpleHeaders, byt
@pytest.mark.parametrize('id_song', [ @pytest.mark.parametrize('id_song', [
pytest.param('senpac'),
pytest.param('butou5'), pytest.param('butou5'),
pytest.param('hol6po'), pytest.param('hol6po'),
pytest.param('mikdp'), pytest.param('mikdp'),