示例#1
0
        public void Run(IScorePluginArgs args)
        {
            var score      = args.GetCurrentScore();
            var range      = args.GetSelectedRange();
            int startTick  = range.Duration < 0 ? range.StartTick + range.Duration : range.StartTick;
            int endTick    = range.Duration < 0 ? range.StartTick : range.StartTick + range.Duration;
            var endStepDic = score.Notes.Slides.ToDictionary(p => p, p => p.StepNotes.OrderByDescending(q => q.TickOffset).First());
            var airStepDic = score.Notes.Airs
                             .Where(p => endStepDic.Values.Contains(p.ParentNote))
                             .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p);
            var airActionStepDic = score.Notes.AirActions
                                   .Where(p => endStepDic.Values.Contains(p.ParentNote))
                                   .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p);

            var targets = score.Notes.Slides
                          .Where(p => p.StartTick >= startTick && p.StartTick + p.GetDuration() <= endTick)
                          .Where(p => p.StartLaneIndex >= range.StartLaneIndex && p.StartLaneIndex + p.StartWidth <= range.StartLaneIndex + range.SelectedLanesCount)
                          .Where(p => p.StepNotes.All(q => q.LaneIndex >= range.StartLaneIndex && q.LaneIndex + q.Width <= range.StartLaneIndex + range.SelectedLanesCount))
                          .Where(p => !airStepDic.ContainsKey(endStepDic[p]) && !airActionStepDic.ContainsKey(endStepDic[p]))
                          .ToList();

            if (targets.Count == 0)
            {
                return;
            }
            var results = targets.Select(p =>
            {
                var ordered = p.StepNotes.OrderByDescending(q => q.TickOffset).ToList();
                var res     = new Slide()
                {
                    StartTick = startTick + (endTick - ordered[0].Tick)
                };
                res.SetPosition(ordered[0].LaneIndex, ordered[0].Width);
                var trailing = new Slide.StepTap(res)
                {
                    IsVisible = true, TickOffset = startTick + (endTick - p.StartTick) - res.StartTick
                };
                trailing.SetPosition(p.StartLaneIndex - res.StartLaneIndex, p.StartWidth - res.StartWidth);
                var steps = ordered.Skip(1).Select(q =>
                {
                    var step = new Slide.StepTap(res)
                    {
                        IsVisible = q.IsVisible, TickOffset = startTick + (endTick - q.Tick) - res.StartTick
                    };
                    step.SetPosition(q.LaneIndex - res.StartLaneIndex, q.Width - res.StartWidth);
                    return(step);
                })
                            .Concat(new[] { trailing });
                res.StepNotes.AddRange(steps);
                return(res);
            });

            foreach (var slide in targets)
            {
                score.Notes.Slides.Remove(slide);
            }
            score.Notes.Slides.AddRange(results);
            args.UpdateScore(score);
        }
示例#2
0
 public RemoveSlideStepNoteOperation(Slide parent, Slide.StepTap stepNote) : base(parent, stepNote)
 {
 }
示例#3
0
 public InsertSlideStepNoteOperation(Slide parent, Slide.StepTap stepNote) : base(parent, stepNote)
 {
 }
示例#4
0
 public SlideStepNoteCollectionOperation(Slide parent, Slide.StepTap stepNote)
 {
     ParentNote = parent;
     StepNote   = stepNote;
 }
示例#5
0
 public MoveSlideStepNoteOperation(Slide.StepTap note, NotePosition before, NotePosition after)
 {
     StepNote       = note;
     BeforePosition = before;
     AfterPosition  = after;
 }
示例#6
0
        public void Run(IScorePluginArgs args)
        {
            var  score      = args.GetCurrentScore();
            var  range      = args.GetSelectedRange();
            bool modified   = false;
            var  targets    = score.Notes.Slides.Where(p => p.StartTick <range.StartTick && p.StepNotes.OrderByDescending(q => q.TickOffset).First().Tick> range.StartTick);
            var  endStepDic = score.Notes.Slides.ToDictionary(p => p, p => p.StepNotes.OrderByDescending(q => q.TickOffset).First());
            var  airStepDic = score.Notes.Airs
                              .Where(p => endStepDic.Values.Contains(p.ParentNote))
                              .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p);
            var airActionStepDic = score.Notes.AirActions
                                   .Where(p => endStepDic.Values.Contains(p.ParentNote))
                                   .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p);

            foreach (var slide in targets.ToList())
            {
                // カーソル位置に中継点が存在しなければ処理しない
                int offset = range.StartTick - slide.StartTick;
                if (slide.StepNotes.All(p => p.TickOffset != offset))
                {
                    continue;
                }

                var first = new Slide()
                {
                    StartTick = slide.StartTick
                };
                first.SetPosition(slide.StartLaneIndex, slide.StartWidth);
                first.StepNotes.AddRange(slide.StepNotes.OrderBy(p => p.TickOffset).TakeWhile(p => p.TickOffset <= offset).Select(p =>
                {
                    var step = new Slide.StepTap(first)
                    {
                        TickOffset = p.TickOffset, IsVisible = p.IsVisible
                    };
                    step.SetPosition(p.LaneIndexOffset, p.WidthChange);
                    return(step);
                }));
                first.StepNotes[first.StepNotes.Count - 1].IsVisible = true;

                var second = new Slide()
                {
                    StartTick = range.StartTick
                };
                var trailing = slide.StepNotes.OrderBy(p => p.TickOffset).SkipWhile(p => p.TickOffset < offset).ToList();
                second.SetPosition(trailing[0].LaneIndex, trailing[0].Width);
                second.StepNotes.AddRange(trailing.Skip(1).Select(p =>
                {
                    var step = new Slide.StepTap(second)
                    {
                        TickOffset = p.TickOffset - offset, IsVisible = p.IsVisible
                    };
                    step.SetPosition(p.LaneIndex - second.StartLaneIndex, p.Width - second.StartWidth);
                    return(step);
                }));

                // 終点AIRをsecondに挿入
                if (airStepDic.ContainsKey(endStepDic[slide]))
                {
                    var origAir = airStepDic[endStepDic[slide]];
                    var air     = new Air(second.StepNotes[second.StepNotes.Count - 1])
                    {
                        VerticalDirection   = origAir.VerticalDirection,
                        HorizontalDirection = origAir.HorizontalDirection
                    };
                    score.Notes.Airs.Remove(origAir);
                    score.Notes.Airs.Add(air);
                }
                if (airActionStepDic.ContainsKey(endStepDic[slide]))
                {
                    var origAirAction = airActionStepDic[endStepDic[slide]];
                    var airAction     = new AirAction(second.StepNotes[second.StepNotes.Count - 1]);
                    airAction.ActionNotes.AddRange(origAirAction.ActionNotes.Select(p => new AirAction.ActionNote(airAction)
                    {
                        Offset = p.Offset
                    }));
                    score.Notes.AirActions.Remove(origAirAction);
                    score.Notes.AirActions.Add(airAction);
                }

                score.Notes.Slides.Add(first);
                score.Notes.Slides.Add(second);
                score.Notes.Slides.Remove(slide);
                modified = true;
            }
            if (modified)
            {
                args.UpdateScore(score);
            }
        }
示例#7
0
        public void Run(IScorePluginArgs args)
        {
            var  score      = args.GetCurrentScore();
            var  range      = args.GetSelectedRange();
            bool modified   = false;
            int  startTick  = range.Duration < 0 ? range.StartTick + range.Duration : range.StartTick;
            int  endTick    = range.Duration < 0 ? range.StartTick : range.StartTick + range.Duration;
            var  endStepDic = score.Notes.Slides.ToDictionary(p => p, p => p.StepNotes.OrderByDescending(q => q.TickOffset).First());
            var  airStepDic = score.Notes.Airs
                              .Where(p => endStepDic.Values.Contains(p.ParentNote))
                              .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p);
            var airActionStepDic = score.Notes.AirActions
                                   .Where(p => endStepDic.Values.Contains(p.ParentNote))
                                   .ToDictionary(p => p.ParentNote as Slide.StepTap, p => p);
            var startDic = score.Notes.Slides.Where(p => p.StartTick >= startTick && p.StartTick <= endTick)
                           .Select(p => new { Position = Tuple.Create(p.StartTick, p.StartLaneIndex, p.StartWidth), Note = p })
                           .GroupBy(p => p.Position)
                           .ToDictionary(p => p.Key, p => p.Select(q => q.Note).ToList());
            var endDic = score.Notes.Slides.Where(p => endStepDic[p].Tick >= startTick && endStepDic[p].Tick <= endTick)
                         .Select(p => new { Position = Tuple.Create(endStepDic[p].Tick, endStepDic[p].LaneIndex, endStepDic[p].Width), Note = p })
                         .GroupBy(p => p.Position)
                         .ToDictionary(p => p.Key, p => p.Select(q => q.Note).ToList());

            while (endDic.Count > 0)
            {
                var pos = endDic.First().Key;
                if (endDic[pos].Count == 0 || !startDic.ContainsKey(pos) || startDic[pos].Count == 0)
                {
                    endDic.Remove(pos);
                    continue;
                }

                if (startDic[pos].Count > 0)
                {
                    // 終点AIR付きスライドはheadingの対象外
                    while (endDic[pos].Count > 0 && (airStepDic.ContainsKey(endStepDic[endDic[pos][0]]) || airActionStepDic.ContainsKey(endStepDic[endDic[pos][0]])))
                    {
                        endDic[pos].RemoveAt(0);
                    }
                    if (endDic[pos].Count == 0)
                    {
                        endDic.Remove(pos);
                        continue;
                    }

                    var heading          = endDic[pos][0];
                    var trailing         = startDic[pos][0];
                    var trailingOldSteps = trailing.StepNotes.OrderBy(p => p.TickOffset).ToList();
                    heading.StepNotes.AddRange(trailingOldSteps.Select(p =>
                    {
                        var step = new Slide.StepTap(heading)
                        {
                            TickOffset = p.Tick - heading.StartTick, IsVisible = p.IsVisible
                        };
                        step.SetPosition(p.LaneIndex - heading.StartLaneIndex, p.Width - heading.StartWidth);
                        return(step);
                    }));

                    // trailingにAIRが追加されていれば反映
                    var trailingOldEndStep = trailingOldSteps[trailingOldSteps.Count - 1];
                    var trailingNewEndStep = heading.StepNotes[heading.StepNotes.Count - 1];
                    if (airStepDic.ContainsKey(trailingOldEndStep))
                    {
                        var air = new Air(trailingNewEndStep)
                        {
                            VerticalDirection   = airStepDic[trailingOldEndStep].VerticalDirection,
                            HorizontalDirection = airStepDic[trailingOldEndStep].HorizontalDirection
                        };
                        score.Notes.Airs.Add(air);
                        score.Notes.Airs.Remove(airStepDic[trailingOldEndStep]);
                        airStepDic.Add(trailingNewEndStep, air);
                        airStepDic.Remove(trailingOldEndStep);
                    }
                    if (airActionStepDic.ContainsKey(trailingOldEndStep))
                    {
                        var airAction = new AirAction(trailingNewEndStep);
                        airAction.ActionNotes.AddRange(airActionStepDic[trailingOldEndStep].ActionNotes.Select(p => new AirAction.ActionNote(airAction)
                        {
                            Offset = p.Offset
                        }));
                        score.Notes.AirActions.Add(airAction);
                        score.Notes.AirActions.Remove(airActionStepDic[trailingOldEndStep]);
                        airActionStepDic.Add(trailingNewEndStep, airAction);
                        airActionStepDic.Remove(trailingOldEndStep);
                    }

                    endStepDic[heading] = trailingNewEndStep;
                    score.Notes.Slides.Remove(trailing);
                    startDic[pos].Remove(trailing);
                    var trailingEndPos = Tuple.Create(endStepDic[trailing].Tick, endStepDic[trailing].LaneIndex, endStepDic[trailing].Width);
                    if (endDic.ContainsKey(trailingEndPos))
                    {
                        endDic[trailingEndPos].Remove(trailing);
                    }
                    endDic[pos].Remove(heading);
                    if (!endDic.ContainsKey(trailingEndPos))
                    {
                        endDic.Add(trailingEndPos, new[] { heading }.ToList());
                    }
                    else
                    {
                        endDic[trailingEndPos].Add(heading);
                    }
                    modified = true;
                }
            }
            if (modified)
            {
                args.UpdateScore(score);
            }
        }
示例#8
0
        private Score ConvertScore(IScoreBookImportPluginArgs args, SusScoreData raw)
        {
            var res = new Score()
            {
                TicksPerBeat = raw.TicksPerBeat
            };

            res.Events.BpmChangeEvents = raw.BpmDefinitions.Select(p => new BpmChangeEvent()
            {
                Tick = p.Key, Bpm = p.Value
            }).ToList();
            res.Events.TimeSignatureChangeEvents = raw.TimeSignatures.Select(p =>
            {
                int factor = 1;
                for (int i = 2; i < 10; i++)
                {
                    if (factor * p.Value % 1 == 0)
                    {
                        return new TimeSignatureChangeEvent()
                        {
                            Tick = p.Key, Numerator = (int)(factor * p.Value), DenominatorExponent = i
                        }
                    }
                    ;
                    factor *= 2;
                }
                throw new ArgumentException("Invalid time signature");
            }).ToList();

            foreach (var item in raw.ShortNotes['1'])
            {
                switch (item.Type)
                {
                case '1':
                    res.Notes.Taps.Add(SetNotePosition(new Tap(), item.Position));
                    break;

                case '2':
                    res.Notes.ExTaps.Add(SetNotePosition(new ExTap(), item.Position));
                    break;

                case '5':
                case '6':
                    args.ReportDiagnostic(new Diagnostic(DiagnosticSeverity.Warning, $"やべーExTAPは通常ExTAPとしてインポートされます。(行: {item.LineIndex + 1})"));
                    res.Notes.ExTaps.Add(SetNotePosition(new ExTap(), item.Position));
                    break;

                case '3':
                    res.Notes.Flicks.Add(SetNotePosition(new Flick(), item.Position));
                    break;

                case '4':
                    res.Notes.Damages.Add(SetNotePosition(new Damage(), item.Position));
                    break;
                }
            }

            foreach (var hold in raw.LongNotes['2'])
            {
                if (hold.Count != 2)
                {
                    args.ReportDiagnostic(new Diagnostic(DiagnosticSeverity.Warning, $"始点と終点以外を含むホールド定義です。このホールドは無視されます。(行: {string.Join(", ", hold.Select(p => p.LineIndex + 1))})"));
                    continue;
                }
                if (hold[0].Position.LaneIndex != hold[1].Position.LaneIndex || hold[0].Position.Width != hold[1].Position.Width)
                {
                    args.ReportDiagnostic(new Diagnostic(DiagnosticSeverity.Warning, $"始点と終点のレーン位置が対応していないホールド定義です。このホールドは無視されます。(行: {string.Join(", ", hold.Select(p => p.LineIndex + 1))})"));
                    continue;
                }
                res.Notes.Holds.Add(new Hold()
                {
                    StartTick = hold[0].Position.Tick,
                    Duration  = hold[1].Position.Tick - hold[0].Position.Tick,
                    LaneIndex = hold[0].Position.LaneIndex,
                    Width     = hold[0].Position.Width
                });
            }

            foreach (var steps in raw.LongNotes['3'])
            {
                var slide = new Slide()
                {
                    StartTick      = steps[0].Position.Tick,
                    StartLaneIndex = steps[0].Position.LaneIndex,
                    StartWidth     = steps[0].Position.Width
                };
                foreach (var step in steps.Skip(1))
                {
                    if (step.Type == '4')
                    {
                        args.ReportDiagnostic(new Diagnostic(DiagnosticSeverity.Warning, $"スライド変曲点は中継点としてインポートされます。(行: {step.LineIndex + 1})"));
                    }
                    var stepTap = new Slide.StepTap(slide)
                    {
                        IsVisible  = step.Type == '3' || step.Type == '2',
                        TickOffset = step.Position.Tick - slide.StartTick
                    };
                    stepTap.SetPosition(step.Position.LaneIndex - slide.StartLaneIndex, step.Position.Width - slide.StartWidth);
                    slide.StepNotes.Add(stepTap);
                }
                res.Notes.Slides.Add(slide);
            }

            var airables = res.Notes.GetShortNotes().Cast <IAirable>()
                           .Concat(res.Notes.Holds.Select(p => p.EndNote))
                           .Concat(res.Notes.Slides.Select(p => p.StepNotes.OrderByDescending(q => q.Tick).First()));
            var airablesDic = airables.Select(p => new { Note = p, Position = new NotePosition()
                                                         {
                                                             Tick = p.Tick, LaneIndex = p.LaneIndex, Width = p.Width
                                                         } })
                              .GroupBy(p => p.Position)
                              .ToDictionary(p => p.Key, p => p.Select(q => q.Note).ToList());

            var usedAirs = new HashSet <IAirable>();

            foreach (var item in raw.ShortNotes['5'])
            {
                if (!airablesDic.ContainsKey(item.Position))
                {
                    continue;
                }
                foreach (var airable in airablesDic[item.Position])
                {
                    if (usedAirs.Contains(airable))
                    {
                        continue;
                    }
                    var air = new Air(airable);
                    switch (item.Type)
                    {
                    case '1':
                    case '2':
                        air.HorizontalDirection = HorizontalAirDirection.Center;
                        break;

                    case '3':
                    case '5':
                        air.HorizontalDirection = HorizontalAirDirection.Left;
                        break;

                    case '4':
                    case '6':
                        air.HorizontalDirection = HorizontalAirDirection.Right;
                        break;
                    }
                    switch (item.Type)
                    {
                    case '1':
                    case '3':
                    case '4':
                        air.VerticalDirection = VerticalAirDirection.Up;
                        break;

                    case '2':
                    case '5':
                    case '6':
                        air.VerticalDirection = VerticalAirDirection.Down;
                        break;
                    }
                    res.Notes.Airs.Add(air);
                    usedAirs.Add(airable);
                    break;
                }
            }

            var usedAirActions = new HashSet <IAirable>();

            foreach (var item in raw.LongNotes['4'])
            {
                if (!airablesDic.ContainsKey(item[0].Position))
                {
                    continue;
                }
                foreach (var airable in airablesDic[item[0].Position])
                {
                    if (usedAirActions.Contains(airable))
                    {
                        continue;
                    }
                    var airAction = new AirAction(airable);
                    foreach (var note in item.Skip(1))
                    {
                        if (note.Position.LaneIndex != item[0].Position.LaneIndex || note.Position.Width != item[0].Position.Width)
                        {
                            args.ReportDiagnostic(new Diagnostic(DiagnosticSeverity.Warning, $"レーン位置が対応していないAir Action定義です。このAir Actionは無視されます。(行: {note.LineIndex + 1})"));

                            continue;
                        }
                        var actionNote = new AirAction.ActionNote(airAction)
                        {
                            Offset = note.Position.Tick - item[0].Position.Tick
                        };
                        airAction.ActionNotes.Add(actionNote);
                    }
                    res.Notes.AirActions.Add(airAction);
                    usedAirActions.Add(airable);
                    break;
                }
            }

            return(res);
        }