コード例 #1
0
ファイル: TimingChangeCommand.cs プロジェクト: maxrchung/S2VX
        public override void Apply(double time, S2VXStory story)
        {
            var bpm = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.BPM    = bpm;
            story.Offset = StartTime;
        }
コード例 #2
0
ファイル: StoryMerger.cs プロジェクト: maxrchung/S2VX
        public static Result Merge(string[] inputs, string output)
        {
            var validateResult = ParameterValidator.Validate(inputs, output);

            if (!validateResult.IsSuccessful)
            {
                return(validateResult);
            }

            var(loadResult, loadedStories) = InputsLoader.Load(inputs);
            if (!loadResult.IsSuccessful)
            {
                return(validateResult);
            }

            var outputStory    = new S2VXStory();
            var notesResult    = NotesMerger.Merge(loadedStories, outputStory);
            var commandsResult = CommandsMerger.Merge(loadedStories, outputStory);

            outputStory.Save(output);

            var messages = new[] {
                $"Merged {inputs.Length} stories into \"{output}\"",
                notesResult.Message,
                commandsResult.Message
            };
            var message = string.Join("\n\n", messages);

            return(new Result {
                IsSuccessful = true,
                Message = message
            });
        }
コード例 #3
0
        public static (Result result, List <S2VXStory> loadedStories) Load(string[] inputs)
        {
            var loadedStories = new List <S2VXStory>();

            foreach (var input in inputs)
            {
                var story = new S2VXStory();
                try {
                    story.Open(input, true);
                } catch (Exception e) {
                    return(
                        new Result {
                        IsSuccessful = false,
                        Message = $"Input file failed to load: \"{input}\"\n{e.Message}"
                    },
                        loadedStories
                        );
                }
                loadedStories.Add(story);
            }

            return(new Result {
                IsSuccessful = true
            }, loadedStories);
        }
コード例 #4
0
        public override void Apply(double time, S2VXStory story)
        {
            var position = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Camera.TakeCameraPositionLock(this);
            story.Camera.SetPosition(this, position);
            story.Camera.ReleaseCameraPositionLock(this);
        }
コード例 #5
0
        public override void Apply(double time, S2VXStory story)
        {
            var scale = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Camera.TakeCameraScaleLock(this);
            story.Camera.SetScale(this, scale);
            story.Camera.ReleaseCameraScaleLock(this);
        }
コード例 #6
0
ファイル: CommandsLoaderTests.cs プロジェクト: maxrchung/S2VX
 public void SetUp()
 {
     var(_, loadedStories) = InputsLoader.Load(new[] {
         "Samples/NotesAlphaFrom0To0.s2ry",
         "Samples/NotesAlphaFrom0To1000.s2ry",
     });
     OutputStory = new S2VXStory();
     Result      = CommandsMerger.Merge(loadedStories, OutputStory);
 }
コード例 #7
0
ファイル: NotesMergerTests.cs プロジェクト: maxrchung/S2VX
 public void SetUp()
 {
     var(_, loadedStories) = InputsLoader.Load(new[] {
         "Samples/HoldNoteFrom0To1000.s2ry",
         "Samples/HoldNoteFrom500To1500.s2ry",
     });
     OutputStory = new S2VXStory();
     Result      = NotesMerger.Merge(loadedStories, OutputStory);
 }
コード例 #8
0
        /// <summary>
        /// Note that conflicts will be reported for any notes that share the
        /// same start/end times. This is to prevent a player from trying to
        /// play multiple notes at one time.
        ///
        /// Example time ranges that are not conflicts:
        /// (0-0, 500-500, 1000-1000)
        /// (0-0, 500-1000)
        ///
        /// Example time ranges that are conflicts:
        /// (0-0, 0-0)
        /// (0-0, 0-1000)
        /// (0-1000, 500-1500)
        /// </summary>
        public static Result Merge(IEnumerable <S2VXStory> inputStories, S2VXStory outputStory)
        {
            var infos = new List <NoteTimeInfo>();

            foreach (var input in inputStories)
            {
                foreach (var note in input.Notes.GetNonHoldNotes())
                {
                    outputStory.AddNote(CopyNote(note));
                    infos.Add(new NoteTimeInfo(note));
                }
                foreach (var holdNote in input.Notes.GetHoldNotes())
                {
                    outputStory.AddNote(CopyHoldNote(holdNote));
                    infos.Add(new NoteTimeInfo(holdNote));
                }
            }
            infos.Sort();

            var          messages   = new List <string>();
            NoteTimeInfo latestInfo = null;

            foreach (var info in infos)
            {
                if (latestInfo == null)
                {
                    latestInfo = info;
                    continue;
                }

                if (info.StartTime > latestInfo.EndTime && info.EndTime > latestInfo.EndTime)
                {
                    latestInfo = info;
                }
                else
                {
                    messages.Add($"Note conflict:\n{latestInfo}\n{info}");
                    if (info.EndTime > latestInfo.EndTime)
                    {
                        latestInfo = info;
                    }
                }
            }

            if (messages.Count == 0)
            {
                messages.Add("No note conflicts found");
            }

            return(new Result {
                IsSuccessful = true,
                Message = string.Join("\n\n", messages)
            });
        }
コード例 #9
0
 private void LoadPlay()
 {
     try {
         var story = new S2VXStory(StoryPath, false);
         var track = S2VXTrack.Open(AudioPath, Audio);
         Screens.Push(new PlayScreen(false, story, track));
     } catch (Exception exception) {
         BtnPlay.BorderThickness = 5;
         Console.WriteLine(exception);
     }
 }
コード例 #10
0
ファイル: CommandsMerger.cs プロジェクト: maxrchung/S2VX
        /// <summary>
        /// Note that different from notes, commands can share time boundaries.
        /// For example, (0-0, 0-1000) is valid. However, duplicate commands,
        /// e.g. (0-0, 0-0) are not allowed.
        ///
        /// Example time ranges that are not conflicts:
        /// (0-0, 500-500, 1000-1000)
        /// (0-0, 500-1000)
        /// (0-0, 0-1000)
        ///
        /// Example time ranges that are conflicts:
        /// (0-0, 0-0)
        /// (0-1000, 500-1500)
        /// </summary>
        public static Result Merge(IEnumerable <S2VXStory> inputStories, S2VXStory outputStory)
        {
            var infos = new List <CommandTimeInfo>();

            foreach (var input in inputStories)
            {
                foreach (var command in input.Commands)
                {
                    outputStory.AddCommand(command);
                    infos.Add(new CommandTimeInfo(command));
                }
            }
            infos.Sort();

            var messages = new List <string>();
            var dictInfo = new Dictionary <string, CommandTimeInfo>();

            foreach (var info in infos)
            {
                var type = info.Type;
                if (!dictInfo.TryGetValue(type, out var latestInfo))
                {
                    dictInfo[type] = info;
                    continue;
                }

                if (info.StartTime == latestInfo.StartTime && info.EndTime == latestInfo.EndTime)
                {
                    messages.Add($"Command conflict:\n{latestInfo}\n{info}");
                }
                else if (info.StartTime >= latestInfo.EndTime && info.EndTime >= latestInfo.EndTime)
                {
                    dictInfo[type] = info;
                }
                else
                {
                    messages.Add($"Command conflict:\n{latestInfo}\n{info}");
                    if (info.EndTime > latestInfo.EndTime)
                    {
                        dictInfo[type] = info;
                    }
                }
            }

            if (messages.Count == 0)
            {
                messages.Add("No command conflicts found");
            }

            return(new Result {
                IsSuccessful = true,
                Message = string.Join("\n\n", messages)
            });
        }
コード例 #11
0
ファイル: NotesTimelineTests.cs プロジェクト: maxrchung/S2VX
        private void Load(AudioManager audio)
        {
            var storyPath = Path.Combine("VisualTests", "EditorScreenTests", "ValidStory.s2ry");

            Story = new S2VXStory();
            Story.Open(storyPath, true);
            var audioPath = Path.Combine("TestTracks", "10-seconds-of-silence.mp3");

            Track = S2VXTrack.Open(audioPath, audio);

            Add(new ScreenStack(Editor = new EditorScreen(Story, Track)));
        }
コード例 #12
0
ファイル: DifficultySettings.cs プロジェクト: maxrchung/S2VX
        // Updates properties based on story configuration
        public void Calculate(S2VXStory story)
        {
            var commands = story.Commands;

            CommandCount = commands.Count;
            var timingCommands = story.Commands.OfType <TimingChangeCommand>();

            if (timingCommands.Any())
            {
                SlowestBPM = timingCommands.Min(t => Math.Min(t.StartValue, t.EndValue));
                FastestBPM = timingCommands.Max(t => Math.Max(t.StartValue, t.EndValue));
            }

            var notes = story.Notes.Children;

            NoteCount = notes.Count;
            if (NoteCount > 0)
            {
                var min = notes.Min(n => n.HitTime);
                var max = notes.Max(n => n.HitTime);
                StoryLength = max - min;
            }
        }
コード例 #13
0
ファイル: S2VXStoryTests.cs プロジェクト: maxrchung/S2VX
            public void SetUp()
            {
                var story    = new S2VXStory();
                var holdNote = new EditorHoldNote {
                    HitTime        = 100,
                    EndTime        = 400,
                    Coordinates    = new(1, 1),
                    EndCoordinates = new(4, 4),
                };

                holdNote.MidCoordinates.Add(new(2, 2));
                holdNote.MidCoordinates.Add(new(3, 3));
                story.AddNote(holdNote);

                var filePath = "HoldNoteLoadingTests_Open_HoldNote_SetUp.s2ry";

                story.Save(filePath);

                var newStory = new S2VXStory();

                newStory.Open(filePath, true);
                LoadedHoldNote = newStory.Notes.GetHoldNotes().First();
            }
コード例 #14
0
ファイル: S2VXCommand.cs プロジェクト: maxrchung/S2VX
 public abstract void Apply(double time, S2VXStory story);
コード例 #15
0
        public override void Apply(double time, S2VXStory story)
        {
            var showTime = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Notes.ShowTime = showTime;
        }
コード例 #16
0
        public override void Apply(double time, S2VXStory story)
        {
            var value = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Notes.NoteOutlineColor = value;
        }
コード例 #17
0
 public override void ReversibleRemove(S2VXStory story, EditorScreen editor) =>
 editor.Reversibles.Push(new ReversibleRemoveHoldNote(story, this, editor));
コード例 #18
0
 public ReversibleRemoveNote(S2VXStory story, S2VXNote note, EditorScreen editor)
 {
     Story  = story;
     Note   = note;
     Editor = editor;
 }
コード例 #19
0
 public ReversibleAddHoldNote(S2VXStory story, HoldNote note, EditorScreen editor)
 {
     Story  = story;
     Note   = note;
     Editor = editor;
 }
コード例 #20
0
        private void Load()
        {
            var width             = Width;
            var songInfoHeight    = width * 0.4f;
            var leaderboardWidth  = width * 0.6f;
            var leaderboardHeight = width * 0.4f;
            var btnHeight         = width * 0.2f;
            var spacingMargin     = 0.05f;
            var textSize          = SizeConsts.TextSize1;
            var thumbnailSize     = width * 0.3f;
            var btnSize           = new Vector2(width / 5, width / 10);

            BtnEdit = new() {
                Origin       = Anchor.Centre,
                Anchor       = Anchor.Centre,
                Size         = btnSize,
                Icon         = FontAwesome.Solid.Edit,
                BorderColour = Color4.Red,
                Masking      = true,
                Action       = LoadEditor
            };
            BtnPlay = new() {
                Origin       = Anchor.Centre,
                Anchor       = Anchor.Centre,
                Size         = btnSize,
                Icon         = FontAwesome.Solid.Play,
                BorderColour = Color4.Red,
                Masking      = true,
                Action       = LoadPlay
            };

            InternalChildren = new Drawable[] {
                // TODO: add blurred background
                new FillFlowContainer {
                    Width    = width,
                    Height   = songInfoHeight,
                    Children = new Drawable[] {
                        // Thumbnail
                        new IconButton {
                            Size   = new Vector2(thumbnailSize),
                            Anchor = Anchor.TopLeft,
                            Origin = Anchor.TopLeft,
                            Margin = new MarginPadding {
                                Horizontal = width * spacingMargin,
                                Vertical   = width * spacingMargin,
                            },
                            Texture     = ThumbnailTexture,
                            TextureName = "logo",
                        },
                        TextContainer = new TextFlowContainer(s => s.Font = new FontUsage("default", textSize))
                        {
                            Width  = width - thumbnailSize - width * spacingMargin * 2,
                            Height = songInfoHeight,
                            Margin = new MarginPadding {
                                Vertical = width * spacingMargin,
                            },
                            TextAnchor = Anchor.TopLeft,
                            Colour     = Color4.White,
                            // TODO: truncate text if it's too long
                        },
                    }
                },
                LeaderboardContainer = new LeaderboardContainer(StoryDirectory)
                {
                    Width  = leaderboardWidth,
                    Height = leaderboardHeight,
                    Y      = songInfoHeight,
                    Anchor = Anchor.TopCentre,
                    Origin = Anchor.TopCentre,
                },
                new FillFlowContainer {
                    Width     = width,
                    Height    = btnHeight,
                    Y         = songInfoHeight + leaderboardHeight,
                    Anchor    = Anchor.TopCentre,
                    Origin    = Anchor.TopCentre,
                    Direction = FillDirection.Horizontal,
                    Children  = new[] {
                        BtnEdit,
                        BtnPlay,
                    }
                }
            };

            LoadSongMetadata();
        }

        private void LoadEditor()
        {
            try {
                var story = new S2VXStory(StoryPath, true);
                var track = S2VXTrack.Open(AudioPath, Audio);
                Screens.Push(new EditorScreen(story, track));
            } catch (Exception exception) {
                BtnEdit.BorderThickness = 5;
                Console.WriteLine(exception);
            }
        }
コード例 #21
0
        public override void Apply(double time, S2VXStory story)
        {
            var value = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Approaches.HoldApproachColor = value;
        }
コード例 #22
0
        public override void Apply(double time, S2VXStory story)
        {
            var color = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Background.Colour = color;
        }
コード例 #23
0
        public override void Apply(double time, S2VXStory story)
        {
            var alpha = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Grid.Alpha = alpha;
        }
コード例 #24
0
        public override void Apply(double time, S2VXStory story)
        {
            var distance = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Approaches.Distance = distance;
        }
コード例 #25
0
        public override void Apply(double time, S2VXStory story)
        {
            var thickness = S2VXUtils.ClampedInterpolation(time, StartValue, EndValue, StartTime, EndTime, Easing);

            story.Approaches.Thickness = thickness;
        }