mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-03-01 07:20:42 +01:00
Fix errors, add gamedb builder and PCMCIA card info
This commit is contained in:
parent
813f939bde
commit
4b57169e64
@ -49,9 +49,7 @@
|
||||
"series": "Fisherman's Bait",
|
||||
"year": 1998,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GE765-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -63,9 +61,7 @@
|
||||
"series": "Fisherman's Bait",
|
||||
"year": 1998,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GE765-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GX" ],
|
||||
@ -121,9 +117,8 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1998,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -137,9 +132,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -151,9 +144,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1998,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GN" ],
|
||||
@ -165,9 +156,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GN" ],
|
||||
@ -179,9 +168,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -193,9 +180,7 @@
|
||||
"series": "Fisherman's Bait",
|
||||
"year": 1998,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GE765-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -207,9 +192,7 @@
|
||||
"series": "Fisherman's Bait",
|
||||
"year": 1998,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GE765-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GK" ],
|
||||
@ -221,9 +204,8 @@
|
||||
"series": "Dance Maniax",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -237,9 +219,8 @@
|
||||
"series": "Dance Maniax",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -277,9 +258,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -291,9 +270,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -305,9 +282,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -319,9 +294,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -333,9 +306,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -347,9 +318,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -361,9 +330,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -375,9 +342,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -389,9 +354,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE", "GN" ],
|
||||
@ -403,9 +366,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE", "GN" ],
|
||||
@ -417,9 +378,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GN" ],
|
||||
@ -431,9 +390,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -445,9 +402,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE", "GN" ],
|
||||
@ -459,9 +414,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GX" ],
|
||||
@ -473,9 +426,7 @@
|
||||
"series": "Fisherman's Bait",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GE765-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -487,9 +438,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -501,9 +450,7 @@
|
||||
"series": "Dance Dance Revolution Solo",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GN" ],
|
||||
@ -515,9 +462,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -529,9 +474,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -543,9 +486,7 @@
|
||||
"series": "Dance Dance Revolution Solo",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GL" ],
|
||||
@ -556,9 +497,7 @@
|
||||
"name": "GunMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "PWB0000073070"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC", "GX" ],
|
||||
@ -581,9 +520,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -595,9 +532,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -609,9 +544,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -623,9 +556,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -637,9 +568,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -651,9 +580,7 @@
|
||||
"series": "PunchMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -665,9 +592,7 @@
|
||||
"series": "PunchMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -678,9 +603,7 @@
|
||||
"name": "Dance Dance Revolution Karaoke MIX",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX921-PWB(B)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -692,9 +615,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -706,9 +627,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -731,9 +650,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -744,9 +661,7 @@
|
||||
"name": "Dance Dance Revolution Karaoke MIX 2",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX921-PWB(B)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -758,9 +673,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -772,9 +685,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -786,9 +697,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 1999,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -811,9 +720,7 @@
|
||||
"series": "PunchMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -825,9 +732,7 @@
|
||||
"series": "PunchMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(F)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -838,9 +743,7 @@
|
||||
"name": "GunMania Zone Plus",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "PWB0000073070"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -863,9 +766,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -877,9 +778,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -891,9 +790,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -905,9 +802,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE" ],
|
||||
@ -919,9 +814,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC", "GE", "GK" ],
|
||||
@ -933,9 +826,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC", "GE" ],
|
||||
@ -947,9 +838,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -961,9 +850,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC", "GU" ],
|
||||
@ -975,9 +862,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC", "GU" ],
|
||||
@ -989,9 +874,7 @@
|
||||
"series": "Dance Dance Revolution Solo",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1003,9 +886,8 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"installRequiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -1019,9 +901,8 @@
|
||||
"series": "Dance Dance Revolution Solo",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"installRequiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -1034,9 +915,7 @@
|
||||
"name": "Kick & Kick",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX700-PWB(K)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1048,9 +927,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1062,9 +939,8 @@
|
||||
"series": "Dance Maniax",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -1078,9 +954,8 @@
|
||||
"series": "Dance Maniax",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -1094,9 +969,8 @@
|
||||
"series": "Dance Maniax",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -1110,9 +984,8 @@
|
||||
"series": "Dance Maniax",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -1126,9 +999,8 @@
|
||||
"series": "Dance Maniax",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A",
|
||||
|
||||
"flags": {
|
||||
"requiresRTCHeader": true
|
||||
}
|
||||
},
|
||||
@ -1142,9 +1014,7 @@
|
||||
"series": "Mambo A Go-Go",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GQ" ],
|
||||
@ -1156,9 +1026,7 @@
|
||||
"series": "Mambo A Go-Go",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE", "GK" ],
|
||||
@ -1170,9 +1038,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2000,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GB" ],
|
||||
@ -1195,9 +1061,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1209,9 +1073,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC", "GK" ],
|
||||
@ -1223,9 +1085,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1237,9 +1097,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1251,9 +1109,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1265,9 +1121,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1279,9 +1133,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1293,9 +1145,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2001,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1307,9 +1157,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GE", "GN" ],
|
||||
@ -1321,9 +1169,7 @@
|
||||
"series": "Martial Beat",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1335,9 +1181,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1349,9 +1193,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1363,9 +1205,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1377,9 +1217,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1391,9 +1229,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC", "GK" ],
|
||||
@ -1405,9 +1241,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1419,9 +1253,7 @@
|
||||
"series": "Dance Dance Revolution",
|
||||
"year": 2002,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1433,9 +1265,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1447,9 +1277,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1461,9 +1289,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1475,9 +1301,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1489,9 +1313,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1503,9 +1325,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1517,9 +1337,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1531,9 +1349,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2003,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1545,9 +1361,7 @@
|
||||
"series": "GuitarFreaks",
|
||||
"year": 2004,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1559,9 +1373,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2004,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specifications": [ "GC" ],
|
||||
@ -1573,9 +1385,7 @@
|
||||
"series": "DrumMania",
|
||||
"year": 2004,
|
||||
|
||||
"flags": {
|
||||
"ioBoard": "GX894-PWB(B)A"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
713
data/games.json
713
data/games.json
File diff suppressed because it is too large
Load Diff
@ -128,7 +128,7 @@
|
||||
"source": "${PROJECT_SOURCE_DIR}/data/fpga.bit"
|
||||
},
|
||||
{
|
||||
"type": "db",
|
||||
"type": "gamedb",
|
||||
"name": "data/games.db",
|
||||
"source": "${PROJECT_SOURCE_DIR}/data/games.json"
|
||||
},
|
||||
|
@ -116,7 +116,7 @@
|
||||
"source": "${PROJECT_SOURCE_DIR}/data/fpga.bit"
|
||||
},
|
||||
{
|
||||
"type": "db",
|
||||
"type": "gamedb",
|
||||
"name": "data/games.db",
|
||||
"source": "${PROJECT_SOURCE_DIR}/data/games.json"
|
||||
},
|
||||
|
@ -23,7 +23,7 @@
|
||||
"properties": {
|
||||
"type": {
|
||||
"title": "Entry type",
|
||||
"description": "Must be 'empty', 'text', 'binary', 'tim', 'metrics', 'palette', 'strings' or 'db'.",
|
||||
"description": "Must be 'empty', 'text', 'binary', 'tim', 'metrics', 'palette', 'strings' or 'gamedb'.",
|
||||
"type": "string",
|
||||
|
||||
"enum": [
|
||||
@ -34,7 +34,7 @@
|
||||
"metrics",
|
||||
"palette",
|
||||
"strings",
|
||||
"db"
|
||||
"gamedb"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
@ -172,7 +172,7 @@
|
||||
"additionalProperties": false,
|
||||
|
||||
"properties": {
|
||||
"type": { "pattern": "^metrics|palette|strings|db$" },
|
||||
"type": { "pattern": "^metrics|palette|strings|gamedb$" },
|
||||
"name": { "type": "string" },
|
||||
"compLevel": {},
|
||||
|
||||
@ -234,18 +234,18 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"required": [ "db" ],
|
||||
"required": [ "gamedb" ],
|
||||
"additionalProperties": false,
|
||||
|
||||
"properties": {
|
||||
"type": { "const": "db" },
|
||||
"type": { "const": "gamedb" },
|
||||
"name": { "type": "string" },
|
||||
"compLevel": {},
|
||||
|
||||
"strings": {
|
||||
"title": "Game database",
|
||||
"description": "Game database root object. If not specified, the source attribute must be a path to a JSON file containing this object.",
|
||||
"type": "object"
|
||||
"$ref": "gamedb.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ size_t PackageProvider::loadData(util::Data &output, const char *path) {
|
||||
if (!output.allocate(uncompLength + margin))
|
||||
return 0;
|
||||
|
||||
auto compPtr = &output.as<uint8_t>() + margin;
|
||||
auto compPtr = output.as<uint8_t>() + margin;
|
||||
|
||||
if (
|
||||
(_file->seek(offset) != offset) ||
|
||||
|
@ -268,7 +268,7 @@ PortError Port::memoryCardWrite(const void *data, uint16_t lba) const {
|
||||
|
||||
if (exchangeBytes(
|
||||
&checksum,
|
||||
response,
|
||||
ackResponse,
|
||||
sizeof(checksum),
|
||||
sizeof(ackResponse)
|
||||
) < sizeof(ackResponse))
|
||||
|
@ -91,8 +91,8 @@ const char *const IDE_MOUNT_POINTS[]{ "ide0:", "ide1:" };
|
||||
|
||||
FileIOManager::FileIOManager(void)
|
||||
: _resourceFile(nullptr), resourcePtr(nullptr), resourceLength(0) {
|
||||
__builtin_memset(ideDevices, 0, sizeof(ideDevices));
|
||||
__builtin_memset(ideProviders, 0, sizeof(ideProviders));
|
||||
util::clear(ideDevices);
|
||||
util::clear(ideProviders);
|
||||
|
||||
vfs.mount("resource:", &resource);
|
||||
#ifdef ENABLE_PCDRV
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "main/cart/cart.hpp"
|
||||
#include "main/cart/cartdata.hpp"
|
||||
#include "main/cart/cartio.hpp"
|
||||
#include "main/formats.hpp"
|
||||
#include "main/uibase.hpp"
|
||||
#include "ps1/system.h"
|
||||
|
||||
@ -225,10 +226,12 @@ private:
|
||||
ui::ScreenshotOverlay _screenshotOverlay;
|
||||
|
||||
ui::Context &_ctx;
|
||||
fs::StringTable _stringTable;
|
||||
FileIOManager _fileIO;
|
||||
AudioStreamManager _audioStream;
|
||||
|
||||
formats::GameDB _gameDB;
|
||||
formats::StringTable _stringTable;
|
||||
|
||||
Thread _workerThread;
|
||||
util::Data _workerStack;
|
||||
WorkerStatus _workerStatus;
|
||||
|
@ -91,17 +91,28 @@ enum SignatureFlag : uint8_t {
|
||||
SIGNATURE_PAD_WITH_FF = 1 << 2
|
||||
};
|
||||
|
||||
enum IOBoardType : uint8_t {
|
||||
IO_BOARD_NONE = 0,
|
||||
IO_BOARD_ANALOG = 1,
|
||||
IO_BOARD_KICK = 2,
|
||||
IO_BOARD_FISHING_REEL = 3,
|
||||
IO_BOARD_DIGITAL = 4,
|
||||
IO_BOARD_DDR_KARAOKE = 5,
|
||||
IO_BOARD_GUNMANIA = 6
|
||||
};
|
||||
|
||||
enum PCMCIADeviceType : uint8_t {
|
||||
PCMCIA_NONE = 0,
|
||||
PCMCIA_NETWORK_PCB = 1,
|
||||
PCMCIA_FLASH_CARD_8 = 2,
|
||||
PCMCIA_FLASH_CARD_16 = 3,
|
||||
PCMCIA_FLASH_CARD_32 = 4,
|
||||
PCMCIA_FLASH_CARD_64 = 5
|
||||
};
|
||||
|
||||
enum GameFlag : uint8_t {
|
||||
GAME_IO_BOARD_BITMASK = 7 << 0,
|
||||
GAME_IO_BOARD_NONE = 0 << 0,
|
||||
GAME_IO_BOARD_ANALOG = 1 << 0,
|
||||
GAME_IO_BOARD_KICK = 2 << 0,
|
||||
GAME_IO_BOARD_FISHING_REEL = 3 << 0,
|
||||
GAME_IO_BOARD_DIGITAL = 4 << 0,
|
||||
GAME_IO_BOARD_DDR_KARAOKE = 5 << 0,
|
||||
GAME_IO_BOARD_GUNMANIA = 6 << 0,
|
||||
GAME_INSTALL_RTC_HEADER_REQUIRED = 1 << 3,
|
||||
GAME_RTC_HEADER_REQUIRED = 1 << 4
|
||||
GAME_INSTALL_RTC_HEADER_REQUIRED = 1 << 0,
|
||||
GAME_RTC_HEADER_REQUIRED = 1 << 1
|
||||
};
|
||||
|
||||
/* Game database structures */
|
||||
@ -130,12 +141,15 @@ struct GameInfo {
|
||||
public:
|
||||
char specifications[MAX_SPECIFICATIONS];
|
||||
char regions[MAX_REGIONS][3];
|
||||
char code[3];
|
||||
char code[4];
|
||||
|
||||
uint8_t flags;
|
||||
uint16_t nameOffset;
|
||||
uint16_t year;
|
||||
|
||||
IOBoardType ioBoard;
|
||||
PCMCIADeviceType pcmcia[2];
|
||||
uint8_t flags;
|
||||
|
||||
ROMHeaderInfo rtcHeader, flashHeader;
|
||||
CartInfo installCart, gameCart;
|
||||
};
|
||||
@ -147,13 +161,14 @@ static constexpr size_t NUM_SORT_TABLES = 4;
|
||||
enum SortOrder : uint8_t {
|
||||
SORT_CODE = 0,
|
||||
SORT_NAME = 1,
|
||||
SORT_YEAR = 2
|
||||
SORT_SERIES = 2,
|
||||
SORT_YEAR = 3
|
||||
};
|
||||
|
||||
class GameDBHeader {
|
||||
public:
|
||||
uint32_t magic[2];
|
||||
uint16_t sortTableOffsets[NUM_SORT_TABLES];
|
||||
uint16_t numEntries, numSortOrders;
|
||||
|
||||
inline bool validateMagic(void) const {
|
||||
return (magic[0] == "573g"_c) && (magic[1] == "medb"_c);
|
||||
|
@ -26,30 +26,49 @@ from typing import Any
|
||||
from common.analysis import MAMENVRAMDump, getBootloaderVersion
|
||||
from common.cartparser import parseCartHeader, parseROMHeader
|
||||
from common.decompile import AnalysisError
|
||||
from common.gamedb import GameInfo
|
||||
from common.gamedb import GameInfo, PCMCIADeviceType
|
||||
from common.util import \
|
||||
JSONFormatter, JSONGroupedArray, JSONGroupedObject, setupLogger
|
||||
|
||||
## Game analysis
|
||||
|
||||
def analyzeGame(game: GameInfo, nvramDir: Path, reanalyze: bool = False):
|
||||
dump: MAMENVRAMDump = MAMENVRAMDump(nvramDir)
|
||||
_PCMCIA_CARD_TYPES: dict[int | None, PCMCIADeviceType] = {
|
||||
None: PCMCIADeviceType.PCMCIA_NONE,
|
||||
8: PCMCIADeviceType.PCMCIA_FLASH_CARD_8,
|
||||
16: PCMCIADeviceType.PCMCIA_FLASH_CARD_16,
|
||||
32: PCMCIADeviceType.PCMCIA_FLASH_CARD_32,
|
||||
64: PCMCIADeviceType.PCMCIA_FLASH_CARD_64
|
||||
}
|
||||
|
||||
if (reanalyze or game.bootloaderVersion is None) and dump.bootloader:
|
||||
def analyzeGame(game: GameInfo, nvramDir: Path, reanalyze: bool = False):
|
||||
dump: MAMENVRAMDump = MAMENVRAMDump.fromDirectory(nvramDir)
|
||||
|
||||
if reanalyze or not game.pcmcia1:
|
||||
game.pcmcia1 = _PCMCIA_CARD_TYPES[dump.pcmcia1Size]
|
||||
if reanalyze or not game.pcmcia2:
|
||||
game.pcmcia2 = _PCMCIA_CARD_TYPES[dump.pcmcia2Size]
|
||||
|
||||
if reanalyze or game.bootloaderVersion is None:
|
||||
game.bootloaderVersion = None
|
||||
|
||||
if dump.bootloader:
|
||||
try:
|
||||
game.bootloaderVersion = getBootloaderVersion(dump.bootloader)
|
||||
except AnalysisError:
|
||||
pass
|
||||
|
||||
if (reanalyze or game.rtcHeader is None) and dump.rtcHeader:
|
||||
game.rtcHeader = parseROMHeader(dump.rtcHeader, True)
|
||||
if (reanalyze or game.flashHeader is None) and dump.flashHeader:
|
||||
game.flashHeader = parseROMHeader(dump.flashHeader)
|
||||
|
||||
if (reanalyze or game.installCart is None) and dump.installCart:
|
||||
game.installCart = parseCartHeader(dump.installCart)
|
||||
if (reanalyze or game.gameCart is None) and dump.gameCart:
|
||||
game.gameCart = parseCartHeader(dump.gameCart)
|
||||
if reanalyze or game.rtcHeader is None:
|
||||
game.rtcHeader = \
|
||||
parseROMHeader(dump.rtcHeader, True) if dump.rtcHeader else None
|
||||
if reanalyze or game.flashHeader is None:
|
||||
game.flashHeader = \
|
||||
parseROMHeader(dump.flashHeader) if dump.flashHeader else None
|
||||
if reanalyze or game.installCart is None:
|
||||
game.installCart = \
|
||||
parseCartHeader(dump.installCart) if dump.installCart else None
|
||||
if reanalyze or game.gameCart is None:
|
||||
game.gameCart = \
|
||||
parseCartHeader(dump.gameCart) if dump.gameCart else None
|
||||
|
||||
## Main
|
||||
|
||||
|
@ -26,20 +26,34 @@ from typing import Any
|
||||
|
||||
import lz4.block
|
||||
from common.assets import *
|
||||
from common.util import normalizeFileName
|
||||
from PIL import Image
|
||||
|
||||
## Asset conversion
|
||||
|
||||
def getJSONObject(asset: Mapping[str, Any], sourceDir: Path, key: str) -> dict:
|
||||
if key in asset:
|
||||
return asset[key]
|
||||
|
||||
with open(sourceDir / asset["source"], "rt", encoding = "utf-8") as file:
|
||||
return json.load(file)
|
||||
|
||||
def processAsset(asset: Mapping[str, Any], sourceDir: Path) -> ByteString:
|
||||
match asset.get("type", "file").strip():
|
||||
case "empty":
|
||||
return bytes(int(asset.get("size", 0)))
|
||||
|
||||
case "text" | "binary":
|
||||
with open(sourceDir / asset["source"], "rb") as file:
|
||||
data: ByteString = file.read()
|
||||
case "text":
|
||||
# The file is read in text mode and then encoded back to binary
|
||||
# manually in order to translate any CRLF line endings to LF only.
|
||||
with open(
|
||||
sourceDir / asset["source"], "rt", encoding = "utf-8"
|
||||
) as file:
|
||||
return file.read().encode("utf-8")
|
||||
|
||||
return data
|
||||
case "binary":
|
||||
with open(sourceDir / asset["source"], "rb") as file:
|
||||
return file.read()
|
||||
|
||||
case "tim":
|
||||
ix: int = int(asset["imagePos"]["x"])
|
||||
@ -58,49 +72,22 @@ def processAsset(asset: Mapping[str, Any], sourceDir: Path) -> ByteString:
|
||||
return generateIndexedTIM(image, ix, iy, cx, cy)
|
||||
|
||||
case "metrics":
|
||||
if "metrics" in asset:
|
||||
metrics: dict = asset["metrics"]
|
||||
else:
|
||||
with open(
|
||||
sourceDir / asset["source"], "rt", encoding = "utf-8"
|
||||
) as file:
|
||||
metrics: dict = json.load(file)
|
||||
|
||||
return generateFontMetrics(metrics)
|
||||
return generateFontMetrics(
|
||||
getJSONObject(asset, sourceDir, "metrics")
|
||||
)
|
||||
|
||||
case "palette":
|
||||
if "palette" in asset:
|
||||
palette: dict = asset["palette"]
|
||||
else:
|
||||
with open(
|
||||
sourceDir / asset["source"], "rt", encoding = "utf-8"
|
||||
) as file:
|
||||
palette: dict = json.load(file)
|
||||
|
||||
return generateColorPalette(palette)
|
||||
return generateColorPalette(
|
||||
getJSONObject(asset, sourceDir, "palette")
|
||||
)
|
||||
|
||||
case "strings":
|
||||
if "strings" in asset:
|
||||
strings: dict = asset["strings"]
|
||||
else:
|
||||
with open(
|
||||
sourceDir / asset["source"], "rt", encoding = "utf-8"
|
||||
) as file:
|
||||
strings: dict = json.load(file)
|
||||
return generateStringTable(
|
||||
getJSONObject(asset, sourceDir, "strings")
|
||||
)
|
||||
|
||||
return generateStringTable(strings)
|
||||
|
||||
case "db":
|
||||
if "db" in asset:
|
||||
db: dict = asset["db"]
|
||||
else:
|
||||
with open(
|
||||
sourceDir / asset["source"], "rt", encoding = "utf-8"
|
||||
) as file:
|
||||
db: dict = json.load(file)
|
||||
|
||||
# TODO: implement
|
||||
return b""
|
||||
case "gamedb":
|
||||
return generateGameDB(getJSONObject(asset, sourceDir, "gamedb"))
|
||||
|
||||
case _type:
|
||||
raise KeyError(f"unsupported asset type '{_type}'")
|
||||
@ -153,6 +140,13 @@ def createParser() -> ArgumentParser:
|
||||
"resource list by default)",
|
||||
metavar = "dir"
|
||||
)
|
||||
group.add_argument(
|
||||
"-e", "--export",
|
||||
type = Path,
|
||||
help = \
|
||||
"Dump generated files (before compression) to specified path",
|
||||
metavar = "dir"
|
||||
)
|
||||
group.add_argument(
|
||||
"configFile",
|
||||
type = FileType("rt", encoding = "utf-8"),
|
||||
@ -179,11 +173,19 @@ def main():
|
||||
fileData: bytearray = bytearray()
|
||||
|
||||
for asset in configFile["resources"]:
|
||||
name: str = asset["name"]
|
||||
data: ByteString = processAsset(asset, sourceDir)
|
||||
|
||||
if data and args.export:
|
||||
args.export.mkdir(parents = True, exist_ok = True)
|
||||
|
||||
with open(args.export / normalizeFileName(name), "wb") as file:
|
||||
file.write(data)
|
||||
|
||||
entry: PackageIndexEntry = \
|
||||
PackageIndexEntry(len(fileData), 0, len(data))
|
||||
|
||||
compLevel: int | None = asset.get("compLevel", args.compress_level)
|
||||
compLevel: int | None = \
|
||||
asset.get("compLevel", args.compress_level)
|
||||
|
||||
if data and compLevel:
|
||||
data = lz4.block.compress(
|
||||
@ -194,7 +196,7 @@ def main():
|
||||
)
|
||||
entry.compLength = len(data)
|
||||
|
||||
entries[asset["name"]] = entry
|
||||
entries[name] = entry
|
||||
fileData += data
|
||||
|
||||
while len(fileData) % args.align:
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
import logging, re
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from .cart import *
|
||||
@ -25,16 +26,61 @@ from .util import InterleavedFile
|
||||
|
||||
## MAME NVRAM directory reader
|
||||
|
||||
_PCMCIA_CARD_SIZES: Sequence[int] = 8, 16, 32, 64
|
||||
|
||||
def _getPCMCIACardSize(path: Path, card: int) -> int | None:
|
||||
for size in _PCMCIA_CARD_SIZES:
|
||||
if (
|
||||
(path / f"pccard{card}_konami_dual_slot3_{size}mb_1l").is_file() and
|
||||
(path / f"pccard{card}_konami_dual_slot4_{size}mb_1l").is_file()
|
||||
):
|
||||
return size * 2
|
||||
if (path / f"pccard{card}_{size}mb_1l").is_file():
|
||||
return size
|
||||
|
||||
return None
|
||||
|
||||
def _loadCartDump(path: Path) -> CartDump | None:
|
||||
try:
|
||||
with open(path, "rb") as file:
|
||||
return parseMAMECartDump(file.read())
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
@dataclass
|
||||
class MAMENVRAMDump:
|
||||
def __init__(self, nvramDir: Path):
|
||||
pcmcia1Size: int | None = None
|
||||
pcmcia2Size: int | None = None
|
||||
|
||||
rtcHeader: ROMHeaderDump | None = None
|
||||
flashHeader: ROMHeaderDump | None = None
|
||||
bootloader: PSEXEAnalyzer | None = None
|
||||
|
||||
installCart: CartDump | None = None
|
||||
gameCart: CartDump | None = None
|
||||
|
||||
@staticmethod
|
||||
def fromDirectory(path: Path):
|
||||
try:
|
||||
with open(path / "m48t58", "rb") as file:
|
||||
file.seek(RTC_HEADER_OFFSET)
|
||||
|
||||
rtcHeader: ROMHeaderDump | None = ROMHeaderDump(
|
||||
DumpFlag.DUMP_PUBLIC_DATA_OK,
|
||||
b"",
|
||||
file.read(RTC_HEADER_LENGTH)
|
||||
)
|
||||
except FileNotFoundError:
|
||||
rtcHeader: ROMHeaderDump | None = None
|
||||
|
||||
try:
|
||||
with InterleavedFile(
|
||||
open(nvramDir / "29f016a.31m", "rb"),
|
||||
open(nvramDir / "29f016a.27m", "rb")
|
||||
open(path / "29f016a.31m", "rb"),
|
||||
open(path / "29f016a.27m", "rb")
|
||||
) as file:
|
||||
file.seek(FLASH_HEADER_OFFSET)
|
||||
|
||||
self.flashHeader: ROMHeaderDump | None = ROMHeaderDump(
|
||||
flashHeader: ROMHeaderDump | None = ROMHeaderDump(
|
||||
DumpFlag.DUMP_PUBLIC_DATA_OK,
|
||||
b"",
|
||||
file.read(FLASH_HEADER_LENGTH)
|
||||
@ -44,41 +90,27 @@ class MAMENVRAMDump:
|
||||
file.seek(FLASH_EXECUTABLE_OFFSET)
|
||||
|
||||
try:
|
||||
self.bootloader: PSEXEAnalyzer | None = PSEXEAnalyzer(file)
|
||||
bootloader: PSEXEAnalyzer | None = PSEXEAnalyzer(file)
|
||||
except AnalysisError:
|
||||
self.bootloader: PSEXEAnalyzer | None = None
|
||||
bootloader: PSEXEAnalyzer | None = None
|
||||
except FileNotFoundError:
|
||||
self.flashHeader: ROMHeaderDump | None = None
|
||||
self.bootloader: PSEXEAnalyzer | None = None
|
||||
flashHeader: ROMHeaderDump | None = None
|
||||
bootloader: PSEXEAnalyzer | None = None
|
||||
|
||||
try:
|
||||
with open(nvramDir / "m48t58", "rb") as file:
|
||||
file.seek(RTC_HEADER_OFFSET)
|
||||
|
||||
self.rtcHeader: ROMHeaderDump | None = ROMHeaderDump(
|
||||
DumpFlag.DUMP_PUBLIC_DATA_OK,
|
||||
b"",
|
||||
file.read(RTC_HEADER_LENGTH)
|
||||
return MAMENVRAMDump(
|
||||
_getPCMCIACardSize(path, 1),
|
||||
_getPCMCIACardSize(path, 2),
|
||||
rtcHeader,
|
||||
flashHeader,
|
||||
bootloader,
|
||||
_loadCartDump(path / "cassette_install_eeprom"),
|
||||
_loadCartDump(path / "cassette_game_eeprom")
|
||||
)
|
||||
except FileNotFoundError:
|
||||
self.rtcHeader: ROMHeaderDump | None = None
|
||||
|
||||
self.installCart: CartDump | None = \
|
||||
self._loadCartDump(nvramDir / "cassette_install_eeprom")
|
||||
self.gameCart: CartDump | None = \
|
||||
self._loadCartDump(nvramDir / "cassette_game_eeprom")
|
||||
|
||||
def _loadCartDump(self, path: Path) -> CartDump | None:
|
||||
try:
|
||||
with open(path, "rb") as file:
|
||||
return parseMAMECartDump(file.read())
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
## Bootloader executable analysis
|
||||
|
||||
_BOOT_VERSION_REGEX: re.Pattern = \
|
||||
re.compile(rb"\0BOOT VER[. ]*(1\.[0-9A-Z]+)\0")
|
||||
re.compile(rb"\0BOOT VER\.? *(1\.[0-9A-Z]+)\0")
|
||||
|
||||
def getBootloaderVersion(exe: PSEXEAnalyzer) -> str:
|
||||
for matched in _BOOT_VERSION_REGEX.finditer(exe.body):
|
||||
|
@ -17,11 +17,12 @@
|
||||
from collections.abc import Generator, Mapping, Sequence
|
||||
from dataclasses import dataclass
|
||||
from struct import Struct
|
||||
from typing import Any
|
||||
from typing import Any, Callable
|
||||
|
||||
import numpy
|
||||
from numpy import ndarray
|
||||
from PIL import Image
|
||||
from .gamedb import GAME_INFO_STRUCT, GameInfo
|
||||
from .util import \
|
||||
HashTableBuilder, StringBlobBuilder, colorFromString, hashData, \
|
||||
roundUpToMultiple
|
||||
@ -263,7 +264,7 @@ def generateStringTable(
|
||||
for keyHash, string in _walkStringTree(strings):
|
||||
hashTable.addEntry(keyHash, blob.addString(string))
|
||||
|
||||
tableLength: int = 0 \
|
||||
blobOffset: int = 0 \
|
||||
+ _STRING_TABLE_HEADER_STRUCT.size \
|
||||
+ _STRING_TABLE_ENTRY_STRUCT.size * len(hashTable.entries)
|
||||
|
||||
@ -280,12 +281,62 @@ def generateStringTable(
|
||||
else:
|
||||
tableData += _STRING_TABLE_ENTRY_STRUCT.pack(
|
||||
entry.fullHash,
|
||||
tableLength + entry.data,
|
||||
blobOffset + entry.data,
|
||||
entry.chainIndex
|
||||
)
|
||||
|
||||
return tableData + blob.data
|
||||
|
||||
## Game database generator
|
||||
|
||||
_GAMEDB_HEADER_STRUCT: Struct = Struct("< 8s 2H")
|
||||
_GAMEDB_HEADER_MAGIC: bytes = b"573gmedb"
|
||||
_GAMEDB_STRING_ALIGNMENT: int = 4
|
||||
|
||||
_GAMEDB_SORT_ORDERS: Sequence[Callable[[ GameInfo ], tuple]] = (
|
||||
lambda game: ( game.code, game.name ), # SORT_CODE
|
||||
lambda game: ( game.name, game.code ), # SORT_NAME
|
||||
lambda game: ( game.series or "", game.code, game.name ), # SORT_SERIES
|
||||
lambda game: ( game.year, game.code, game.name ) # SORT_YEAR
|
||||
)
|
||||
|
||||
def generateGameDB(gamedb: Mapping[str, Any]) -> bytearray:
|
||||
numEntries: int = len(gamedb["games"])
|
||||
gameListOffset: int = 0 \
|
||||
+ _GAMEDB_HEADER_STRUCT.size \
|
||||
+ len(_GAMEDB_SORT_ORDERS) * 2 * numEntries
|
||||
blobOffset: int = 0 \
|
||||
+ gameListOffset \
|
||||
+ GAME_INFO_STRUCT.size * numEntries
|
||||
|
||||
games: list[GameInfo] = []
|
||||
blob: StringBlobBuilder = StringBlobBuilder(_GAMEDB_STRING_ALIGNMENT)
|
||||
|
||||
gameListData: bytearray = bytearray()
|
||||
sortTableData: bytearray = bytearray()
|
||||
sortTableData += _GAMEDB_HEADER_STRUCT.pack(
|
||||
_GAMEDB_HEADER_MAGIC,
|
||||
numEntries,
|
||||
len(_GAMEDB_SORT_ORDERS)
|
||||
)
|
||||
|
||||
for info in gamedb["games"]:
|
||||
game: GameInfo = GameInfo.fromJSONObject(info)
|
||||
name: bytes = game.name.encode("utf-8") + b"\0"
|
||||
|
||||
games.append(game)
|
||||
gameListData += game.toBinary(blobOffset + blob.addString(name))
|
||||
|
||||
for sortOrder in _GAMEDB_SORT_ORDERS:
|
||||
indices: list[int] = \
|
||||
sorted(range(numEntries), key = lambda i: sortOrder(games[i]))
|
||||
|
||||
for index in indices:
|
||||
offset: int = gameListOffset + GAME_INFO_STRUCT.size * index
|
||||
sortTableData += offset.to_bytes(2, "little")
|
||||
|
||||
return sortTableData + gameListData + blob.data
|
||||
|
||||
## Package header generator
|
||||
|
||||
_PACKAGE_INDEX_HEADER_STRUCT: Struct = Struct("< 8s I 2H")
|
||||
|
@ -24,7 +24,7 @@ from .util import JSONGroupedObject
|
||||
|
||||
## Utilities
|
||||
|
||||
def _makeJSONObject(*groups: Mapping[str, Any]) -> JSONGroupedObject:
|
||||
def _makeJSONObject(*groups: Mapping[str, Any]) -> JSONGroupedObject | None:
|
||||
jsonObj: JSONGroupedObject = JSONGroupedObject()
|
||||
|
||||
for group in groups:
|
||||
@ -37,7 +37,7 @@ def _makeJSONObject(*groups: Mapping[str, Any]) -> JSONGroupedObject:
|
||||
if dest:
|
||||
jsonObj.groups.append(dest)
|
||||
|
||||
return jsonObj
|
||||
return jsonObj if jsonObj.groups else None
|
||||
|
||||
## Flags
|
||||
|
||||
@ -108,7 +108,7 @@ class HeaderFlag(IntFlag):
|
||||
|
||||
@staticmethod
|
||||
def fromJSONObject(obj: Mapping[str, Any]) -> Self:
|
||||
flags: HeaderFlag = 0
|
||||
flags: HeaderFlag = HeaderFlag(0)
|
||||
|
||||
flags |= {
|
||||
None: HeaderFlag.FORMAT_NONE,
|
||||
@ -168,7 +168,7 @@ class ChecksumFlag(IntFlag):
|
||||
|
||||
@staticmethod
|
||||
def fromJSONObject(obj: Mapping[str, Any]) -> Self:
|
||||
flags: ChecksumFlag = 0
|
||||
flags: ChecksumFlag = ChecksumFlag(0)
|
||||
|
||||
flags |= {
|
||||
None: ChecksumFlag.CHECKSUM_WIDTH_NONE,
|
||||
@ -222,7 +222,7 @@ class IdentifierFlag(IntFlag):
|
||||
|
||||
@staticmethod
|
||||
def fromJSONObject(obj: Mapping[str, Any]) -> Self:
|
||||
flags: IdentifierFlag = 0
|
||||
flags: IdentifierFlag = IdentifierFlag(0)
|
||||
|
||||
flags |= {
|
||||
None: IdentifierFlag.PRIVATE_TID_TYPE_NONE,
|
||||
@ -275,7 +275,7 @@ class SignatureFlag(IntFlag):
|
||||
|
||||
@staticmethod
|
||||
def fromJSONObject(obj: Mapping[str, Any]) -> Self:
|
||||
flags: SignatureFlag = 0
|
||||
flags: SignatureFlag = SignatureFlag(0)
|
||||
|
||||
flags |= {
|
||||
None: SignatureFlag.SIGNATURE_TYPE_NONE,
|
||||
@ -306,31 +306,74 @@ class SignatureFlag(IntFlag):
|
||||
}
|
||||
)
|
||||
|
||||
class IOBoardType(IntEnum):
|
||||
IO_BOARD_NONE = 0
|
||||
IO_BOARD_ANALOG = 1
|
||||
IO_BOARD_KICK = 2
|
||||
IO_BOARD_FISHING_REEL = 3
|
||||
IO_BOARD_DIGITAL = 4
|
||||
IO_BOARD_DDR_KARAOKE = 5
|
||||
IO_BOARD_GUNMANIA = 6
|
||||
|
||||
@staticmethod
|
||||
def fromJSONObject(obj: str | None) -> Self:
|
||||
return {
|
||||
None: IOBoardType.IO_BOARD_NONE,
|
||||
"GX700-PWB(F)": IOBoardType.IO_BOARD_ANALOG,
|
||||
"GX700-PWB(K)": IOBoardType.IO_BOARD_KICK,
|
||||
"GE765-PWB(B)A": IOBoardType.IO_BOARD_FISHING_REEL,
|
||||
"GX894-PWB(B)A": IOBoardType.IO_BOARD_DIGITAL,
|
||||
"GX921-PWB(B)": IOBoardType.IO_BOARD_DDR_KARAOKE,
|
||||
"PWB0000073070": IOBoardType.IO_BOARD_GUNMANIA
|
||||
}[obj]
|
||||
|
||||
def toJSONObject(self) -> str | None:
|
||||
return {
|
||||
IOBoardType.IO_BOARD_NONE: None,
|
||||
IOBoardType.IO_BOARD_ANALOG: "GX700-PWB(F)",
|
||||
IOBoardType.IO_BOARD_KICK: "GX700-PWB(K)",
|
||||
IOBoardType.IO_BOARD_FISHING_REEL: "GE765-PWB(B)A",
|
||||
IOBoardType.IO_BOARD_DIGITAL: "GX894-PWB(B)A",
|
||||
IOBoardType.IO_BOARD_DDR_KARAOKE: "GX921-PWB(B)",
|
||||
IOBoardType.IO_BOARD_GUNMANIA: "PWB0000073070"
|
||||
}[self]
|
||||
|
||||
class PCMCIADeviceType(IntEnum):
|
||||
PCMCIA_NONE = 0
|
||||
PCMCIA_NETWORK_PCB = 1
|
||||
PCMCIA_FLASH_CARD_8 = 2
|
||||
PCMCIA_FLASH_CARD_16 = 3
|
||||
PCMCIA_FLASH_CARD_32 = 4
|
||||
PCMCIA_FLASH_CARD_64 = 5
|
||||
|
||||
@staticmethod
|
||||
def fromJSONObject(obj: str | None) -> Self:
|
||||
return {
|
||||
None: PCMCIADeviceType.PCMCIA_NONE,
|
||||
"PWB0000100991": PCMCIADeviceType.PCMCIA_NETWORK_PCB,
|
||||
"flashCard8MB": PCMCIADeviceType.PCMCIA_FLASH_CARD_8,
|
||||
"flashCard16MB": PCMCIADeviceType.PCMCIA_FLASH_CARD_16,
|
||||
"flashCard32MB": PCMCIADeviceType.PCMCIA_FLASH_CARD_32,
|
||||
"flashCard64MB": PCMCIADeviceType.PCMCIA_FLASH_CARD_64
|
||||
}[obj]
|
||||
|
||||
def toJSONObject(self) -> str | None:
|
||||
return {
|
||||
PCMCIADeviceType.PCMCIA_NONE: None,
|
||||
PCMCIADeviceType.PCMCIA_NETWORK_PCB: "PWB0000100991",
|
||||
PCMCIADeviceType.PCMCIA_FLASH_CARD_8: "flashCard8MB",
|
||||
PCMCIADeviceType.PCMCIA_FLASH_CARD_16: "flashCard16MB",
|
||||
PCMCIADeviceType.PCMCIA_FLASH_CARD_32: "flashCard32MB",
|
||||
PCMCIADeviceType.PCMCIA_FLASH_CARD_64: "flashCard64MB"
|
||||
}[self]
|
||||
|
||||
class GameFlag(IntFlag):
|
||||
GAME_IO_BOARD_BITMASK = 7 << 0
|
||||
GAME_IO_BOARD_NONE = 0 << 0
|
||||
GAME_IO_BOARD_ANALOG = 1 << 0
|
||||
GAME_IO_BOARD_KICK = 2 << 0
|
||||
GAME_IO_BOARD_FISHING_REEL = 3 << 0
|
||||
GAME_IO_BOARD_DIGITAL = 4 << 0
|
||||
GAME_IO_BOARD_DDR_KARAOKE = 5 << 0
|
||||
GAME_IO_BOARD_GUNMANIA = 6 << 0
|
||||
GAME_INSTALL_RTC_HEADER_REQUIRED = 1 << 3
|
||||
GAME_RTC_HEADER_REQUIRED = 1 << 4
|
||||
GAME_INSTALL_RTC_HEADER_REQUIRED = 1 << 0
|
||||
GAME_RTC_HEADER_REQUIRED = 1 << 1
|
||||
|
||||
@staticmethod
|
||||
def fromJSONObject(obj: Mapping[str, Any]) -> Self:
|
||||
flags: GameFlag = 0
|
||||
|
||||
flags |= {
|
||||
None: GameFlag.GAME_IO_BOARD_NONE,
|
||||
"GX700-PWB(F)": GameFlag.GAME_IO_BOARD_ANALOG,
|
||||
"GX700-PWB(K)": GameFlag.GAME_IO_BOARD_KICK,
|
||||
"GE765-PWB(B)A": GameFlag.GAME_IO_BOARD_FISHING_REEL,
|
||||
"GX894-PWB(B)A": GameFlag.GAME_IO_BOARD_DIGITAL,
|
||||
"GX921-PWB(B)": GameFlag.GAME_IO_BOARD_DDR_KARAOKE,
|
||||
"PWB0000073070": GameFlag.GAME_IO_BOARD_GUNMANIA
|
||||
}[obj.get("ioBoard", None)]
|
||||
flags: GameFlag = GameFlag(0)
|
||||
|
||||
for key, flag in {
|
||||
"installRequiresRTCHeader": GameFlag.GAME_INSTALL_RTC_HEADER_REQUIRED,
|
||||
@ -344,16 +387,6 @@ class GameFlag(IntFlag):
|
||||
def toJSONObject(self) -> JSONGroupedObject:
|
||||
return _makeJSONObject(
|
||||
{
|
||||
"ioBoard": {
|
||||
GameFlag.GAME_IO_BOARD_NONE: None,
|
||||
GameFlag.GAME_IO_BOARD_ANALOG: "GX700-PWB(F)",
|
||||
GameFlag.GAME_IO_BOARD_KICK: "GX700-PWB(K)",
|
||||
GameFlag.GAME_IO_BOARD_FISHING_REEL: "GE765-PWB(B)A",
|
||||
GameFlag.GAME_IO_BOARD_DIGITAL: "GX894-PWB(B)A",
|
||||
GameFlag.GAME_IO_BOARD_DDR_KARAOKE: "GX921-PWB(B)",
|
||||
GameFlag.GAME_IO_BOARD_GUNMANIA: "PWB0000073070"
|
||||
}[self & GameFlag.GAME_IO_BOARD_BITMASK]
|
||||
}, {
|
||||
"installRequiresRTCHeader":
|
||||
(GameFlag.GAME_INSTALL_RTC_HEADER_REQUIRED in self),
|
||||
"requiresRTCHeader": (GameFlag.GAME_RTC_HEADER_REQUIRED in self)
|
||||
@ -362,9 +395,10 @@ class GameFlag(IntFlag):
|
||||
|
||||
## Data structures
|
||||
|
||||
_ROM_HEADER_INFO_STRUCT: Struct = Struct("< 4s 2s 3B x")
|
||||
_CART_INFO_STRUCT: Struct = Struct("< 8s 2s 6B")
|
||||
_GAME_INFO_STRUCT: Struct = Struct("< 4s 36s 3s B 2H 10s 10s 16s 16s")
|
||||
ROM_HEADER_INFO_STRUCT: Struct = Struct("< 4s 2s 3B x")
|
||||
CART_INFO_STRUCT: Struct = Struct("< 8s 2s 6B")
|
||||
GAME_INFO_STRUCT: Struct = Struct("< 4s 36s 4s 2H 4B 10s 10s 16s 16s")
|
||||
|
||||
_MAX_SPECIFICATIONS: int = 4
|
||||
_MAX_REGIONS: int = 12
|
||||
|
||||
@ -401,7 +435,7 @@ class ROMHeaderInfo:
|
||||
)
|
||||
|
||||
def toBinary(self) -> bytes:
|
||||
return _ROM_HEADER_INFO_STRUCT.pack(
|
||||
return ROM_HEADER_INFO_STRUCT.pack(
|
||||
self.signatureField,
|
||||
self.yearField,
|
||||
self.headerFlags,
|
||||
@ -454,7 +488,7 @@ class CartInfo:
|
||||
)
|
||||
|
||||
def toBinary(self) -> bytes:
|
||||
return _CART_INFO_STRUCT.pack(
|
||||
return CART_INFO_STRUCT.pack(
|
||||
self.dataKey,
|
||||
self.yearField,
|
||||
self.pcb,
|
||||
@ -476,6 +510,9 @@ class GameInfo:
|
||||
series: str | None
|
||||
year: int
|
||||
|
||||
ioBoard: IOBoardType
|
||||
pcmcia1: PCMCIADeviceType
|
||||
pcmcia2: PCMCIADeviceType
|
||||
flags: GameFlag
|
||||
|
||||
bootloaderVersion: str | None = None
|
||||
@ -502,6 +539,9 @@ class GameInfo:
|
||||
obj.get("series", None),
|
||||
obj["year"],
|
||||
|
||||
IOBoardType .fromJSONObject(obj.get("ioBoard", None)),
|
||||
PCMCIADeviceType.fromJSONObject(obj.get("pcmcia1", None)),
|
||||
PCMCIADeviceType.fromJSONObject(obj.get("pcmcia2", None)),
|
||||
GameFlag .fromJSONObject(obj.get("flags", {})),
|
||||
|
||||
obj.get("bootloaderVersion", None),
|
||||
@ -524,6 +564,9 @@ class GameInfo:
|
||||
"series": self.series,
|
||||
"year": self.year
|
||||
}, {
|
||||
"ioBoard": self.ioBoard.toJSONObject(),
|
||||
"pcmcia1": self.pcmcia1.toJSONObject(),
|
||||
"pcmcia2": self.pcmcia2.toJSONObject(),
|
||||
"flags": self.flags .toJSONObject()
|
||||
}, {
|
||||
"bootloaderVersion": self.bootloaderVersion
|
||||
@ -552,18 +595,21 @@ class GameInfo:
|
||||
|
||||
# FIXME: identifiers, series and bootloaderVersion are not currently
|
||||
# included in the binary format
|
||||
return _GAME_INFO_STRUCT.pack(
|
||||
b"".join(sorted(ord(spec[1]) for spec in self.specifications)),
|
||||
return GAME_INFO_STRUCT.pack(
|
||||
bytes(sorted(ord(spec[1]) for spec in self.specifications)),
|
||||
b"".join(sorted(
|
||||
region.encode("ascii").ljust(3, b"\0")
|
||||
for region in self.regions
|
||||
)),
|
||||
self.code.encode("ascii"),
|
||||
self.flags,
|
||||
nameOffset,
|
||||
self.year,
|
||||
self.rtcHeader .toBinary(),
|
||||
self.flashHeader.toBinary(),
|
||||
self.installCart.toBinary(),
|
||||
self.gameCart .toBinary()
|
||||
self.ioBoard,
|
||||
self.pcmcia1,
|
||||
self.pcmcia2,
|
||||
self.flags,
|
||||
self.rtcHeader .toBinary() if self.rtcHeader else b"",
|
||||
self.flashHeader.toBinary() if self.flashHeader else b"",
|
||||
self.installCart.toBinary() if self.installCart else b"",
|
||||
self.gameCart .toBinary() if self.gameCart else b""
|
||||
)
|
||||
|
@ -51,7 +51,9 @@ def decodeSigned(value: int, bitLength: int) -> int:
|
||||
# characters (' ', '$', '%', '*') excluded.
|
||||
_BASE41_CHARSET: str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./:"
|
||||
|
||||
_COLOR_REGEX: re.Pattern = re.compile(r"^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$")
|
||||
_NAME_INVALID_REGEX: re.Pattern = re.compile(r"[^0-9A-Z+,-._]", re.IGNORECASE)
|
||||
_COLOR_REGEX: re.Pattern = \
|
||||
re.compile(r"^#?([0-9A-F]{3}|[0-9A-F]{6})$", re.IGNORECASE)
|
||||
|
||||
def toPrintableChar(value: int) -> str:
|
||||
if (value < 0x20) or (value > 0x7e):
|
||||
@ -89,6 +91,9 @@ def decodeBase41(data: str) -> bytearray:
|
||||
|
||||
return output
|
||||
|
||||
def normalizeFileName(value: str) -> str:
|
||||
return _NAME_INVALID_REGEX.sub("_", value)
|
||||
|
||||
def colorFromString(value: str) -> tuple[int, int, int]:
|
||||
matched: re.Match | None = _COLOR_REGEX.match(value)
|
||||
|
||||
|
@ -107,6 +107,8 @@ def main():
|
||||
|
||||
converted: bool = False
|
||||
|
||||
args.output.mkdir(parents = True, exist_ok = True)
|
||||
|
||||
#if os.path.isfile(args.input / "bios.bin"):
|
||||
#copyfile(args.input / "bios.bin", args.output / "700a01.22g")
|
||||
#converted = True
|
||||
|
Loading…
x
Reference in New Issue
Block a user