1- from bsor .Decoder import *
1+ from .Decoder import *
22from typing import *
3- import json
3+ import logging
4+
45from abc import ABC , abstractmethod
56
67from json import JSONEncoder
@@ -29,24 +30,25 @@ def default(self, o):
2930SABER_LEFT = 1
3031SABER_RIGHT = 0
3132
33+ MAX_SUPPORTED_VERSION = 1
3234MAGIC_HEX = '0x442d3d69'
3335
3436lookup_dict_scoring_type = {
35- 0 : 'Normal' ,
36- 1 : 'Ignore' ,
37- 2 : 'NoScore' ,
38- 3 : 'Normal' ,
39- 4 : 'SliderHead' ,
40- 5 : 'SliderTail' ,
41- 6 : 'BurstSliderHead' ,
42- 7 : 'BurstSliderElement'
37+ NOTE_SCORE_TYPE_NORMAL_1 : 'Normal' ,
38+ NOTE_SCORE_TYPE_IGNORE : 'Ignore' ,
39+ NOTE_SCORE_TYPE_NOSCORE : 'NoScore' ,
40+ NOTE_SCORE_TYPE_NORMAL_2 : 'Normal' ,
41+ NOTE_SCORE_TYPE_SLIDERHEAD : 'SliderHead' ,
42+ NOTE_SCORE_TYPE_SLIDERTAIL : 'SliderTail' ,
43+ NOTE_SCORE_TYPE_BURSTSLIDERHEAD : 'BurstSliderHead' ,
44+ NOTE_SCORE_TYPE_BURSTSLIDERELEMENT : 'BurstSliderElement'
4345}
4446
4547lookup_dict_event_type = {
46- 0 : 'cut' ,
47- 1 : 'badcut' ,
48- 2 : 'miss' ,
49- 3 : 'bomb'
48+ NOTE_EVENT_GOOD : 'cut' ,
49+ NOTE_EVENT_BAD : 'badcut' ,
50+ NOTE_EVENT_MISS : 'miss' ,
51+ NOTE_EVENT_BOMB : 'bomb'
5052}
5153
5254
@@ -101,12 +103,11 @@ class Info(JSONable):
101103 def json_dict (self ):
102104 return self .__dict__
103105
104-
105106def make_info (f ) -> Info :
106107 info_start = decode_byte (f )
107108
108109 if info_start != 0 :
109- raise BSException (f'Info must start with 0, got "{ info_start } " instead' )
110+ raise BSException (f'Info magic number must be 0, got "{ info_start } " instead' )
110111 info = Info ()
111112 info .version = decode_string (f )
112113 info .gameVersion = decode_string (f )
@@ -190,7 +191,7 @@ def json_dict(self):
190191def make_frames (f ) -> List [Frame ]:
191192 frames_start = decode_byte (f )
192193 if frames_start != 1 :
193- raise BSException (f'Frames must start with 1, got "{ frames_start } " instead' )
194+ raise BSException (f'Frames magic number must be 1, got "{ frames_start } " instead' )
194195 result = make_things (f , make_frame )
195196 return result
196197
@@ -267,7 +268,7 @@ def json_dict(self):
267268def make_notes (f ) -> List [Note ]:
268269 notes_starter = decode_byte (f )
269270 if notes_starter != 2 :
270- raise BSException (f'Notes must start with 2, got "{ notes_starter } " instead' )
271+ raise BSException (f'Notes magic number must be 2, got "{ notes_starter } " instead' )
271272
272273 result = make_things (f , make_note )
273274 return result
@@ -440,6 +441,46 @@ def make_pause(f) -> Pause:
440441 return p
441442
442443
444+ class ControllerOffsets (JSONable ):
445+ left : VRObject
446+ right : VRObject
447+
448+ def json_dict (self ):
449+ return self .__dict__
450+
451+ def make_controller_offsets (f ) -> ControllerOffsets :
452+ controller_offset_magic = decode_byte (f )
453+ if controller_offset_magic != 6 :
454+ raise BSException (f'ControllerOffsets magic number must be 6, got "{ controller_offset_magic } " instead' )
455+ c = ControllerOffsets ()
456+ c .left = make_vr_object (f )
457+ c .right = make_vr_object (f )
458+ return c
459+
460+
461+ class UserData (JSONable ):
462+ key : str
463+ bytes : List [bytes ]
464+
465+ def json_dict (self ):
466+ return self .__dict__
467+
468+
469+ def make_user_datas (f ) -> List [UserData ]:
470+ user_data_magic = decode_byte (f )
471+ if user_data_magic != 7 :
472+ raise BSException (f'UserData magic number must be 7, got "{ user_data_magic } " instead' )
473+ return make_things (f , make_user_data )
474+
475+
476+ def make_user_data (f ) -> UserData :
477+ u = UserData ()
478+ u .key = decode_string (f )
479+ byte_count = decode_int (f )
480+ u .bytes = [f .read (decode_byte (f )) for _ in range (byte_count )]
481+ return u
482+
483+
443484class Bsor (JSONable ):
444485 magic_numer : int
445486 file_version : int
@@ -449,6 +490,8 @@ class Bsor(JSONable):
449490 walls : List [Wall ]
450491 heights : List [Height ]
451492 pauses : List [Pause ]
493+ controller_offsets : ControllerOffsets
494+ user_data : List [UserData ]
452495
453496 def json_dict (self ):
454497 return self .__dict__
@@ -461,29 +504,21 @@ def make_bsor(f: typing.BinaryIO) -> Bsor:
461504 if hex (m .magic_numer ) != MAGIC_HEX :
462505 raise BSException (f'File magic number must be { MAGIC_HEX } , got "{ hex (m .magic_numer )} " instead.' )
463506 m .file_version = decode_byte (f )
464- if m .file_version != 1 :
465- raise BSException (f'version { m .file_version } not supported' )
507+
508+ if m .file_version > MAX_SUPPORTED_VERSION :
509+ logging .warning (f'File is version { m .file_version } and might not be compatible or not use all features'
510+ f', highest supported version is { MAX_SUPPORTED_VERSION } ' )
466511 m .info = make_info (f )
467512 m .frames = make_frames (f )
468513 m .notes = make_notes (f )
469514 m .walls = make_walls (f )
470515 m .heights = make_heights (f )
471516 m .pauses = make_pauses (f )
472-
517+ if f .peek (1 ):
518+ m .controller_offsets = make_controller_offsets (f )
519+ m .user_data = make_user_datas (f )
520+ else :
521+ m .controller_offsets = []
522+ m .user_data = []
473523 return m
474524
475-
476- if __name__ == '__main__' :
477- import os
478-
479- filename = 'D:/_TMP/Burst.bsor'
480- print (f'File name : { os .path .basename (filename )} ' )
481- try :
482- with open (filename , "rb" ) as f :
483- m = make_bsor (f )
484- print (f'BSOR Version: { m .file_version } ' )
485- print (f'BSOR notes: { len (m .notes )} ' )
486- except BSException as e :
487- # TODO please improve on this except-raise.
488- # I've modified it to raise e for now because I don't know what you want to do with this, but please have something better.
489- raise e
0 commit comments