@@ -344,13 +344,13 @@ private static void ParseTapNote(string code, ChuNote note, List<Alert> alerts,
344344 }
345345 }
346346
347- private void ParseHeightAndColor ( ChuNote n , string str , List < Alert > alerts , string noteType = "" ) // 需要传入noteType是因为,不同版本的不同类型note在实现上还略有区别的。
347+ private void ParseHeightAndColor ( ChuNote n , string str , List < Alert > alerts , int lineNum , string noteType = "" ) // 需要传入noteType是因为,不同版本的不同类型note在实现上还略有区别的。
348348 {
349349 if ( string . IsNullOrEmpty ( str ) ) return ;
350350 if ( str . Length == 1 && noteType is "H" or "S" && Version < 6 )
351351 { // 老版本的:H和:S,单独的一位是height而不是颜色,因此不能套用下面的逻辑
352352 if ( TryH36ToI ( str , out var height ) ) n . Height = U2C_Height ( height ) ;
353- else alerts . Add ( new Alert ( Warning , "解析Air系列音符的高度属性失败!" , n . Time , null , null , FormatNoteRef ( n , str ) ) ) ;
353+ else alerts . Add ( new Alert ( Warning , "解析Air系列音符的高度属性失败!" , n . Time , null , lineNum , FormatNoteRef ( n , str ) ) ) ;
354354 return ;
355355 }
356356
@@ -362,45 +362,49 @@ private void ParseHeightAndColor(ChuNote n, string str, List<Alert> alerts, stri
362362 str = str [ ..posOfComma ] ;
363363 if ( intervalStr == "$" ) n . CrushInterval = 38400 ;
364364 else if ( int . TryParse ( intervalStr , out var interval ) ) n . CrushInterval = interval ;
365- else alerts . Add ( new Alert ( Warning , "解析Air-Crush的interval属性失败!" , n . Time , null , null , FormatNoteRef ( n , str ) ) ) ;
365+ else alerts . Add ( new Alert ( Warning , "解析Air-Crush的interval属性失败!" , n . Time , null , lineNum , FormatNoteRef ( n , str ) ) ) ;
366366 }
367367 else if ( noteType is "C" && str . Length == 2 && Version < 8 )
368368 {
369369 var intervalStr = str . Last ( ) ;
370370 str = str [ ..^ 1 ] + "N" ;
371371 if ( intervalStr == 'Z' ) n . CrushInterval = 38400 ;
372372 else if ( TryHToI ( intervalStr , out var interval ) ) n . CrushInterval = interval ;
373- else alerts . Add ( new Alert ( Warning , "解析Air-Crush的interval属性失败!" , n . Time , null , null , FormatNoteRef ( n , str ) ) ) ;
373+ else alerts . Add ( new Alert ( Warning , "解析Air-Crush的interval属性失败!" , n . Time , null , lineNum , FormatNoteRef ( n , str ) ) ) ;
374374 }
375375
376376 // 剩的部分都满足:最后一位是颜色,前面是高度
377- if ( str . Length > 0 ) n . Tag = U2C_AirColor . GetValueOrDefault ( str . Last ( ) . ToString ( ) , "" ) ;
377+ if ( str . Length > 0 )
378+ { // 解析颜色
379+ var rawColorStr = str . Last ( ) . ToString ( ) ;
380+ n . Tag = U2C_AirColor . GetValueOrDefault ( rawColorStr , rawColorStr ) ;
381+ }
378382 if ( str . Length > 1 )
379- {
383+ { // 解析高度
380384 var heightStr = str [ ..^ 1 ] ;
381385 if ( TryH36ToI ( str [ ..^ 1 ] , out var height ) )
382386 n . Height = U2C_Height ( heightStr . Length == 1 ? height : height / 10m ) ; // 一位时不用除以10,两位时需要除以10
383- else alerts . Add ( new Alert ( Warning , "解析Air系列音符的高度属性失败!" , n . Time , null , null , FormatNoteRef ( n , str ) ) ) ;
387+ else alerts . Add ( new Alert ( Warning , "解析Air系列音符的高度属性失败!" , n . Time , null , lineNum , FormatNoteRef ( n , str ) ) ) ;
384388 }
385389 }
386390
387391 private int ParseHoldNote ( bool isAirHold , string [ ] lines , int idx , string code , ChuNote note , List < Alert > alerts , ChuChart chart )
388392 {
389393 note . Type = isAirHold ? "AHD" : "HLD" ;
390394 ParseCellWidth ( code , 1 , note , alerts , idx + 1 , chart ) ;
391- if ( isAirHold ) ParseHeightAndColor ( note , code [ 3 ..] , alerts , "H" ) ;
395+ if ( isAirHold ) ParseHeightAndColor ( note , code [ 3 ..] , alerts , idx + 1 , "H" ) ;
392396
393397 bool foundFirst = false ;
394398 while ( idx + 1 < lines . Length )
395399 {
396400 var nextLine = lines [ idx + 1 ] . Trim ( ) ;
397- if ( ! TryParseFollowerLine ( nextLine , out var marker , out var duration , out _ , out _ , out _ , false ) )
401+ if ( ! TryParseFollowerLine ( nextLine , out var marker , out var endTick , out _ , out _ , out _ , false ) )
398402 {
399403 if ( nextLine . StartsWith ( '\' ' ) || nextLine . StartsWith ( '@' ) ) { idx ++ ; continue ; }
400404 break ;
401405 }
402406
403- note . Duration + = new Rational ( duration , RSL ) ;
407+ note . Duration = new Rational ( endTick , RSL ) ;
404408 if ( isAirHold && marker == "c" ) note . Type = "AHX" ; // 可能是对应于UMIGURI文档中的 AirHold的 AIR-ACTION 无し终点
405409 idx ++ ;
406410 foundFirst = true ;
@@ -416,7 +420,7 @@ private int ParseSlideNote(bool isAirSlide, string[] lines, int idx, string code
416420 // 注:一开始从外面传进来的previousNote,最后并不会被添加进chart里,只是作为第一段的起点参照而已。
417421 var startTime = previousNote . Time ;
418422 ParseCellWidth ( code , 1 , previousNote , alerts , idx + 1 , chart ) ;
419- if ( isAirSlide ) ParseHeightAndColor ( previousNote , code [ 3 ..] , alerts , "S" ) ;
423+ if ( isAirSlide ) ParseHeightAndColor ( previousNote , code [ 3 ..] , alerts , idx + 1 , "S" ) ;
420424 previousNote . EndCell = previousNote . Cell ;
421425 previousNote . EndWidth = previousNote . Width ;
422426 previousNote . EndHeight = previousNote . Height ;
@@ -425,21 +429,21 @@ private int ParseSlideNote(bool isAirSlide, string[] lines, int idx, string code
425429 while ( idx + 1 < lines . Length )
426430 { // 循环处理所有的跟随行。idx始终指向上一条已经处理完的行。
427431 var nextLine = lines [ idx + 1 ] . Trim ( ) ;
428- if ( ! TryParseFollowerLine ( nextLine , out var marker , out var duration , out var endCell , out var endWidth , out var endHeight , true ) )
432+ if ( ! TryParseFollowerLine ( nextLine , out var marker , out var endTick , out var endCell , out var endWidth , out var endHeight , true ) )
429433 {
430434 if ( nextLine . StartsWith ( '\' ' ) || nextLine . StartsWith ( '@' ) ) { idx ++ ; continue ; }
431435 break ;
432436 }
433437
434438 var type = isAirSlide ? ( marker == "s" ? "ASD" : "ASC" ) : ( marker == "s" ? "SLD" : "SLC" ) ;
435439
436- var segmentEnd = startTime + new Rational ( duration , RSL ) ;
440+ var segmentEnd = startTime + new Rational ( endTick , RSL ) ;
437441 var note = new ChuNote
438442 {
439443 Type = type , Time = previousNote . EndTime ,
440444 Cell = previousNote . EndCell , Width = previousNote . EndWidth , Height = previousNote . EndHeight ,
441445 Duration = segmentEnd - previousNote . EndTime , Tag = previousNote . Tag ,
442- EndCell = endCell , EndWidth = endWidth ,
446+ EndCell = endCell ! . Value , EndWidth = endWidth ! . Value ,
443447 EndHeight = endHeight != null ? U2C_Height ( endHeight . Value ) : previousNote . EndHeight ,
444448 Previous = foundFirst ? previousNote : null ,
445449 } ;
@@ -456,11 +460,11 @@ private int ParseSlideNote(bool isAirSlide, string[] lines, int idx, string code
456460 return idx ;
457461 }
458462
459- private static bool TryParseFollowerLine ( string line , out string marker , out int endTick , out int endCell , out int endWidth , out decimal ? height , bool requireEndCellWidth )
463+ private static bool TryParseFollowerLine ( string line , out string marker , out int endTick , out int ? endCell , out int ? endWidth , out decimal ? height , bool requireEndCellWidth )
460464 {
461465 endTick = 0 ;
462- endCell = 0 ;
463- endWidth = 1 ;
466+ endCell = null ;
467+ endWidth = null ;
464468 marker = "" ;
465469 height = null ;
466470
@@ -537,7 +541,7 @@ private void ParseAirNote(string code, ChuNote note, List<Alert> alerts, int lin
537541 note . Type = "AIR" ;
538542 alerts . Add ( new Alert ( Warning , $ "未知的 AIR 方向: { dir } ") { Line = lineNum , RelevantNote = FormatNoteRef ( note , code ) } ) ;
539543 }
540- ParseHeightAndColor ( note , mainPart [ 2 ..] , alerts , "a" ) ;
544+ ParseHeightAndColor ( note , mainPart [ 2 ..] , alerts , lineNum , "a" ) ;
541545 }
542546
543547 private static int ParseAirCrushNote ( string [ ] lines , int idx , string code , ChuNote previousNote , List < Alert > alerts , ChuChart chart )
0 commit comments