1
- from bsor .Decoder import *
1
+ from .Decoder import *
2
2
from typing import *
3
- import json
3
+ import logging
4
+
4
5
from abc import ABC , abstractmethod
5
6
6
7
from json import JSONEncoder
@@ -29,24 +30,25 @@ def default(self, o):
29
30
SABER_LEFT = 1
30
31
SABER_RIGHT = 0
31
32
33
+ MAX_SUPPORTED_VERSION = 1
32
34
MAGIC_HEX = '0x442d3d69'
33
35
34
36
lookup_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'
43
45
}
44
46
45
47
lookup_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'
50
52
}
51
53
52
54
@@ -101,12 +103,11 @@ class Info(JSONable):
101
103
def json_dict (self ):
102
104
return self .__dict__
103
105
104
-
105
106
def make_info (f ) -> Info :
106
107
info_start = decode_byte (f )
107
108
108
109
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' )
110
111
info = Info ()
111
112
info .version = decode_string (f )
112
113
info .gameVersion = decode_string (f )
@@ -190,7 +191,7 @@ def json_dict(self):
190
191
def make_frames (f ) -> List [Frame ]:
191
192
frames_start = decode_byte (f )
192
193
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' )
194
195
result = make_things (f , make_frame )
195
196
return result
196
197
@@ -267,7 +268,7 @@ def json_dict(self):
267
268
def make_notes (f ) -> List [Note ]:
268
269
notes_starter = decode_byte (f )
269
270
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' )
271
272
272
273
result = make_things (f , make_note )
273
274
return result
@@ -440,6 +441,46 @@ def make_pause(f) -> Pause:
440
441
return p
441
442
442
443
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
+
443
484
class Bsor (JSONable ):
444
485
magic_numer : int
445
486
file_version : int
@@ -449,6 +490,8 @@ class Bsor(JSONable):
449
490
walls : List [Wall ]
450
491
heights : List [Height ]
451
492
pauses : List [Pause ]
493
+ controller_offsets : ControllerOffsets
494
+ user_data : List [UserData ]
452
495
453
496
def json_dict (self ):
454
497
return self .__dict__
@@ -461,29 +504,21 @@ def make_bsor(f: typing.BinaryIO) -> Bsor:
461
504
if hex (m .magic_numer ) != MAGIC_HEX :
462
505
raise BSException (f'File magic number must be { MAGIC_HEX } , got "{ hex (m .magic_numer )} " instead.' )
463
506
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 } ' )
466
511
m .info = make_info (f )
467
512
m .frames = make_frames (f )
468
513
m .notes = make_notes (f )
469
514
m .walls = make_walls (f )
470
515
m .heights = make_heights (f )
471
516
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 = []
473
523
return m
474
524
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