public RuntimeScore ReadCompiledScore(Stream stream, string fileName, ReadSourceOptions sourceOptions, ScoreCompileOptions compileOptions) { var score = ReadSourceScore(stream, fileName, sourceOptions); using (var compiler = new SldprojCompiler()) { return(compiler.Compile(score, compileOptions)); } }
public RuntimeScore ReadCompiledScore(Stream stream, string fileName, ReadSourceOptions sourceOptions, ScoreCompileOptions compileOptions) { var sourceScore = ReadSourceScore(stream, fileName, sourceOptions); RuntimeScore runtimeScore; using (var compiler = new SimpleScoreCompiler()) { runtimeScore = compiler.Compile(sourceScore, compileOptions); } return(runtimeScore); }
public SourceScore ReadSourceScore(Stream stream, string fileName, ReadSourceOptions sourceOptions) { var extension = Path.GetExtension(fileName); if (extension == null) { throw new ArgumentException(); } var lz4Extension = Unity3DScoreFormat.Unity3DReadExtensions[1]; var isCompressed = extension.ToLowerInvariant().EndsWith(lz4Extension); ScoreObject scoreObject = null; using (var bundle = new BundleFile(stream, fileName, isCompressed)) { foreach (var asset in bundle.AssetFiles) { foreach (var preloadData in asset.PreloadDataList) { if (preloadData.KnownType != KnownClassID.MonoBehaviour) { continue; } var behaviour = preloadData.LoadAsMonoBehaviour(true); if (!behaviour.Name.Contains("fumen")) { continue; } behaviour = preloadData.LoadAsMonoBehaviour(false); var serializer = new MonoBehaviourSerializer(); scoreObject = serializer.Deserialize <ScoreObject>(behaviour); break; } } } if (scoreObject == null) { throw new FormatException(); } return(ToSourceScore(scoreObject, sourceOptions)); }
private static void Main(string[] args) { var format = new SimpleScoreFormat(); var sourceOptions = new ReadSourceOptions { ScoreIndex = 0 }; SourceScore score; using (var fileStream = File.Open("simple.ss", FileMode.Open, FileAccess.Read, FileShare.Read)) { using (var reader = format.CreateReader()) { score = reader.ReadSourceScore(fileStream, fileStream.Name, sourceOptions); } } Console.WriteLine(score.Notes.Length); #if DEBUG Console.ReadKey(); #endif }
private static SourceScore ToSourceScore(ScoreObject scoreObject, ReadSourceOptions options) { var score = new SourceScore(); var scoreIndex = options.ScoreIndex; var difficulty = (Difficulty)scoreIndex; var trackType = ScoreHelper.MapDifficultyToTrackType(difficulty); var tracks = ScoreHelper.GetTrackIndicesFromTrackType(trackType); score.Notes = scoreObject.NoteEvents .Where(nd => Array.IndexOf(tracks, nd.Track) >= 0) .Select(n => ToNote(n, tracks)) .Where(n => n != null).ToArray(); score.Conductors = scoreObject.ConductorEvents.Select(ToConductor).ToArray(); score.MusicOffset = scoreObject.BgmOffset; score.ScoreIndex = scoreIndex; score.TrackCount = tracks.Length; return(score); }
public SourceScore ReadSourceScore(Stream stream, string fileName, ReadSourceOptions sourceOptions) { var projectVersion = ProjectReader.CheckFormatVersion(fileName); ProjectReader projectReader; switch (projectVersion) { case ProjectVersion.V0_2: projectReader = new SldprojV2Reader(); break; case ProjectVersion.V0_3: case ProjectVersion.V0_3_1: projectReader = new SldprojV3Reader(); break; case ProjectVersion.V0_4: projectReader = new SldprojV4Reader(); break; default: throw new FormatException("Unsupported sldproj format version."); } var project = projectReader.ReadProject(fileName, null); var difficulty = (Difficulty)(sourceOptions.ScoreIndex + 1); var score = project.GetScore(difficulty); if (score == null) { throw new FormatException($"Invalid project or invalid score index (\"{sourceOptions.ScoreIndex}\")."); } return(ToSourceScore(project, score, sourceOptions)); }
public SourceScore ReadSourceScore(Stream stream, string fileName, ReadSourceOptions sourceOptions) { var lines = ReadLines(stream); var c = 0; var offsetTimeSpan = TimeSpan.Parse(lines[c]); ++c; var leadTimeSpan = TimeSpan.Parse(lines[c]); ++c; var trackCount = Convert.ToInt32(lines[c]); ++c; var beatsPerMeasure = Convert.ToInt32(lines[c]); ++c; // splitter ++c; var notes = new List <SourceNote>(); while (!lines[c].StartsWith("---")) { var line = lines[c]; SourceNote[] sourceNotes; if (TapPattern.IsMatch(line)) { var tap = Tap.FromString(line); var sourceNote = new SourceNote { Type = NoteType.Tap }; FillHeader(sourceNote, tap.Header); sourceNote.Size = StrToSize(tap.Body.Size); sourceNotes = new[] { sourceNote }; } else if (HoldPairPattern.IsMatch(line)) { var holds = Hold.CreateHolds(line); var sourceNote = new SourceNote { Type = NoteType.Hold }; FillHeader(sourceNote, holds[0].Header); sourceNote.Size = StrToSize(holds[0].Body.Size); var holdEnd = new SourceNote { Type = NoteType.Hold }; FillHeader(holdEnd, holds[1].Header); holdEnd.Size = sourceNote.Size; holdEnd.FlickDirection = StrToDirection(holds[1].Body.Direction); sourceNote.FollowingNotes = new[] { holdEnd }; sourceNotes = new[] { sourceNote }; } else if (FlickPattern.IsMatch(line)) { var flick = Flick.FromString(line); var sourceNote = new SourceNote { Type = NoteType.Flick }; FillHeader(sourceNote, flick.Header); sourceNote.Size = StrToSize(flick.Body.Size); sourceNote.FlickDirection = StrToDirection(flick.Body.Direction); sourceNotes = new[] { sourceNote }; } else if (SlideSeriesPattern.IsMatch(line)) { var slides = Slide.CreateSlides(line); var sourceNote = new SourceNote { Type = NoteType.Slide }; FillHeader(sourceNote, slides[0].Header); var following = new List <SourceNote>(); for (var i = 1; i < slides.Count; ++i) { var nodeInSeries = new SourceNote { Type = NoteType.Slide }; FillHeader(nodeInSeries, slides[i].Header); if (i == slides.Count - 1) { nodeInSeries.FlickDirection = StrToDirection(slides[i].Body.Direction); } following.Add(nodeInSeries); } sourceNote.FollowingNotes = following.ToArray(); sourceNotes = new[] { sourceNote }; } else if (SpecialPattern.IsMatch(line)) { var special = Special.FromString(line); var sourceNote = new SourceNote { Type = NoteType.Special }; FillHeader(sourceNote, special.Header); sourceNotes = new[] { sourceNote }; } else { throw new FormatException("Error in simple format."); } notes.AddRange(sourceNotes); // next line ++c; } // Sort the added notes. notes.Sort((n1, n2) => n1.Ticks.CompareTo(n2.Ticks)); // splitter ++c; var conductors = new List <Conductor>(); for (; c < lines.Count; ++c) { var ss = lines[c].Split(':'); var measureIndex = Convert.ToInt32(ss[0]); var bpm = Convert.ToDouble(ss[1]); var conductor = new Conductor { Measure = measureIndex - 1, Tempo = bpm, Ticks = (measureIndex - 1) * beatsPerMeasure * NoteBase.TicksPerBeat, SignatureNumerator = beatsPerMeasure, SignatureDenominator = beatsPerMeasure }; conductors.Add(conductor); } conductors.Sort((n1, n2) => n1.Ticks.CompareTo(n2.Ticks)); var score = new SourceScore(); score.Conductors = conductors.ToArray(); score.Notes = notes.ToArray(); score.TrackCount = trackCount; score.MusicOffset = offsetTimeSpan.TotalSeconds; return(score); void FillHeader(SourceNote note, NoteHeader header) { var fraction = (float)(header.Nominator - 1) / header.Denominator; note.Beat = (int)(beatsPerMeasure * fraction); note.StartX = header.Start - 1; note.EndX = header.End - 1; note.Speed = header.Speed; note.LeadTime = leadTimeSpan.TotalSeconds; note.Measure = header.Measure - 1; note.Ticks = 60 * (long)(beatsPerMeasure * ((header.Measure - 1) + fraction) * NoteBase.TicksPerBeat); note.TrackIndex = (int)note.StartX; if (note.TrackIndex < 0 || note.TrackIndex >= trackCount) { Debug.Print("Warning: Invalid track index \"{0}\", changing into range [0, {1}].", note.TrackIndex, trackCount - 1); if (note.TrackIndex < 0) { note.TrackIndex = 0; } else if (note.TrackIndex >= trackCount) { note.TrackIndex = trackCount - 1; } } } NoteSize StrToSize(string str) { if (string.IsNullOrEmpty(str)) { return(NoteSize.Small); } else { switch (str) { case "small": return(NoteSize.Small); case "large": return(NoteSize.Large); default: throw new ArgumentOutOfRangeException(nameof(str), str, null); } } } FlickDirection StrToDirection(string str) { if (string.IsNullOrEmpty(str)) { return(FlickDirection.None); } else { switch (str) { case "left": return(FlickDirection.Left); case "right": return(FlickDirection.Right); case "up": return(FlickDirection.Up); default: throw new ArgumentOutOfRangeException(nameof(str), str, null); } } } }
private static int Main([NotNull, ItemNotNull] string[] args) { if (args.Length == 0) { Console.Error.WriteLine(HelpText); return(0); } var inputFile = Path.GetFullPath(args[0]); string outputScoreFile; if (args.Length >= 2) { outputScoreFile = args[1]; } else { var fi = new FileInfo(inputFile); var name = fi.FullName; outputScoreFile = name.Substring(0, name.Length - fi.Extension.Length) + ".txt"; } string outputScenarioFile; if (args.Length >= 3) { outputScenarioFile = args[2]; } else { var fi = new FileInfo(inputFile); var name = fi.FullName; outputScenarioFile = name.Substring(0, name.Length - fi.Extension.Length) + "_scenario.txt"; } var format = new SimpleScoreFormat(); SourceScore sourceScore; using (var fileStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (var reader = format.CreateReader()) { var sourceOptions = new ReadSourceOptions(); sourceScore = reader.ReadSourceScore(fileStream, fileStream.Name, sourceOptions); } } for (var i = 1; i < sourceScore.Conductors.Length; ++i) { ScorePreprocessor.FixNoteTickInfo(sourceScore.Conductors[i], sourceScore); } foreach (var sourceNote in sourceScore.Notes) { ScorePreprocessor.FixNoteTickInfo(sourceNote, sourceScore); } using (var fileStream = File.Open(outputScoreFile, FileMode.Create, FileAccess.Write, FileShare.Write)) { using (var writer = new StreamWriter(fileStream, Utf8WithoutBom)) { WriteScore.Write(sourceScore, writer); } } using (var fileStream = File.Open(outputScenarioFile, FileMode.Create, FileAccess.Write, FileShare.Write)) { using (var writer = new StreamWriter(fileStream, Utf8WithoutBom)) { WriteScenario.Write(sourceScore, writer); } } return(0); }
private static SourceScore ToSourceScore([NotNull] Project project, [NotNull] Score score, [NotNull] ReadSourceOptions options) { var result = new SourceScore(); var sourceNotes = new List <SourceNote>(); var conductors = new List <Conductor>(); const int beatsPerMeasure = 4; var globalConductor = new Conductor(); globalConductor.Tempo = (float)project.Settings.BeatPerMinute; globalConductor.SignatureNumerator = project.Settings.Signature; globalConductor.SignatureDenominator = beatsPerMeasure; conductors.Add(globalConductor); var allNotes = score.GetAllNotes(); foreach (var note in allNotes) { SourceNote sourceNote = null; Conductor conductor = null; switch (note.Basic.Type) { case NoteType.TapOrFlick: sourceNote = new SourceNote(); FillTapOrFlick(note, sourceNote); break; case NoteType.Hold: if (!note.Helper.IsHoldStart) { continue; } sourceNote = new SourceNote(); FillHold(note, sourceNote); break; case NoteType.Slide: if (!note.Helper.IsSlideStart) { continue; } sourceNote = new SourceNote(); FillSlide(note, sourceNote); break; case NoteType.VariantBpm: { conductor = new Conductor(); FillCommonProperties(note, conductor); Debug.Assert(note.Params != null, "note.Params != null"); conductor.Tempo = (float)note.Params.NewBpm; conductor.SignatureNumerator = project.Settings.Signature; conductor.SignatureDenominator = beatsPerMeasure; } break; default: throw new ArgumentOutOfRangeException(); } if (sourceNote != null) { sourceNotes.Add(sourceNote); } if (conductor != null) { conductors.Add(conductor); } } result.MusicOffset = project.Settings.StartTimeOffset; result.TrackCount = CgssTrackCount; result.ScoreIndex = options.ScoreIndex; sourceNotes.Sort((n1, n2) => n1.Ticks.CompareTo(n2.Ticks)); conductors.Sort((n1, n2) => n1.Ticks.CompareTo(n2.Ticks)); result.Notes = sourceNotes.ToArray(); result.Conductors = conductors.ToArray(); return(result); void FillCommonProperties(Note note, NoteBase sourceNote) { var bar = note.Basic.Bar; sourceNote.Measure = bar.Basic.Index; var fraction = (float)note.Basic.IndexInGrid / bar.GetGridPerSignature() / beatsPerMeasure; sourceNote.Beat = (int)fraction; //sourceNote.GroupID = 0; sourceNote.Ticks = 60 * (long)(beatsPerMeasure * (sourceNote.Measure + fraction) * NoteBase.TicksPerBeat); } void FillSourceNoteProperties(Note note, SourceNote sourceNote) { FillCommonProperties(note, sourceNote); sourceNote.Size = NoteSize.Small; sourceNote.Speed = 1.0f; sourceNote.StartX = (float)(note.Basic.StartPosition - 1); sourceNote.EndX = (float)(note.Basic.FinishPosition - 1); sourceNote.TrackIndex = (int)sourceNote.StartX; if (sourceNote.TrackIndex < 0 || sourceNote.TrackIndex > (CgssTrackCount - 1)) { Debug.Print("Warning: Invalid track index \"{0}\", changing into range [0, {1}].", sourceNote.TrackIndex, CgssTrackCount - 1); if (sourceNote.TrackIndex < 0) { sourceNote.TrackIndex = 0; } else if (sourceNote.TrackIndex > (CgssTrackCount - 1)) { sourceNote.TrackIndex = (CgssTrackCount - 1); } } sourceNote.LeadTime = (float)DefaultLeadTime.TotalSeconds; } void FillTapOrFlick(Note note, SourceNote sourceNote) { FillSourceNoteProperties(note, sourceNote); switch (note.Basic.FlickType) { case NoteFlickType.None: sourceNote.Type = MilliSim.Contributed.Scores.NoteType.Tap; sourceNote.FlickDirection = FlickDirection.None; break; case NoteFlickType.Left: sourceNote.Type = MilliSim.Contributed.Scores.NoteType.Flick; sourceNote.FlickDirection = FlickDirection.Left; break; case NoteFlickType.Right: sourceNote.Type = MilliSim.Contributed.Scores.NoteType.Flick; sourceNote.FlickDirection = FlickDirection.Right; break; default: throw new ArgumentOutOfRangeException(); } } void FillHold(Note note, SourceNote sourceNote) { FillSourceNoteProperties(note, sourceNote); sourceNote.Type = MilliSim.Contributed.Scores.NoteType.Hold; var holdEnd = new SourceNote(); Debug.Assert(note.Editor.HoldPair != null, "note.Editor.HoldPair != null"); FillSourceNoteProperties(note.Editor.HoldPair, holdEnd); holdEnd.Type = MilliSim.Contributed.Scores.NoteType.Hold; switch (note.Editor.HoldPair.Basic.FlickType) { case NoteFlickType.None: holdEnd.FlickDirection = FlickDirection.None; break; case NoteFlickType.Left: holdEnd.FlickDirection = FlickDirection.Left; break; case NoteFlickType.Right: holdEnd.FlickDirection = FlickDirection.Right; break; default: throw new ArgumentOutOfRangeException(); } sourceNote.FollowingNotes = new[] { holdEnd }; } void FillSlide(Note note, SourceNote sourceNote) { FillSourceNoteProperties(note, sourceNote); sourceNote.Type = MilliSim.Contributed.Scores.NoteType.Slide; var following = new List <SourceNote>(); var nextSlideNode = note.Editor.NextSlide; while (nextSlideNode != null) { var node = new SourceNote(); FillSourceNoteProperties(nextSlideNode, node); node.Type = MilliSim.Contributed.Scores.NoteType.Slide; if (nextSlideNode.Helper.IsSlideEnd) { switch (nextSlideNode.Basic.FlickType) { case NoteFlickType.None: node.FlickDirection = FlickDirection.None; break; case NoteFlickType.Left: node.FlickDirection = FlickDirection.Left; break; case NoteFlickType.Right: node.FlickDirection = FlickDirection.Right; break; default: throw new ArgumentOutOfRangeException(); } } following.Add(node); nextSlideNode = nextSlideNode.Editor.NextSlide; } sourceNote.FollowingNotes = following.ToArray(); } }
public void LoadScoreFile([NotNull] string scoreFilePath, int scoreIndex, float scoreOffset) { var theaterDays = Game.ToBaseGame(); var debug = theaterDays.FindSingleElement <DebugOverlay>(); if (string.IsNullOrEmpty(scoreFilePath)) { if (debug != null) { debug.AddLine("ERROR: Score file is not specified."); } return; } if (!File.Exists(scoreFilePath)) { if (debug != null) { debug.AddLine($"ERROR: Score file <{scoreFilePath}> is missing."); } return; } var scoreFormats = theaterDays.PluginManager.GetPluginsOfType <IScoreFormat>(); if (scoreFormats.Count == 0) { if (debug != null) { debug.AddLine("ERROR: No available score reader."); } return; } var sourceOptions = new ReadSourceOptions { ScoreIndex = scoreIndex }; var compileOptions = new ScoreCompileOptions { GlobalSpeed = 1, Offset = scoreOffset }; var successful = false; RuntimeScore runtimeScore = null; SourceScore sourceScore = null; foreach (var format in scoreFormats) { if (!format.SupportsReadingFileType(scoreFilePath)) { continue; } using (var reader = format.CreateReader()) { Stream fileStream = null; if (reader.IsStreamingSupported) { fileStream = File.Open(scoreFilePath, FileMode.Open, FileAccess.Read, FileShare.Read); } if (!successful) { if (format.CanReadAsSource) { try { sourceScore = reader.ReadSourceScore(fileStream, scoreFilePath, sourceOptions); if (!format.CanBeCompiled) { throw new InvalidOperationException("This format must support compiling source score to runtime score."); } using (var compiler = format.CreateCompiler()) { runtimeScore = compiler.Compile(sourceScore, compileOptions); } successful = true; } catch (Exception ex) { if (debug != null) { debug.AddLine($"An exception is thrown while trying to read the score using <{format.PluginDescription}>: {ex.Message}"); debug.AddLine(ex.StackTrace); } } } } if (!successful) { if (format.CanReadAsCompiled) { try { runtimeScore = reader.ReadCompiledScore(fileStream, scoreFilePath, sourceOptions, compileOptions); successful = true; } catch (Exception ex) { if (debug != null) { debug.AddLine($"An exception is thrown while trying to read the score using <{format.PluginDescription}>: {ex.Message}"); debug.AddLine(ex.StackTrace); } } } } if (successful) { break; } fileStream?.Dispose(); } } if (!successful) { if (debug != null) { debug.AddLine($"ERROR: No score reader can read score file <{scoreFilePath}>."); } } else { _sourceScore = sourceScore; RuntimeScore = runtimeScore; if (debug != null) { debug.AddLine($"Loaded score file: {scoreFilePath}"); } } var noteReactor = theaterDays.FindSingleElement <NoteReactor>(); noteReactor?.RecalculateReactions(); var tapPoints = theaterDays.FindSingleElement <TapPoints>(); tapPoints?.RecalcLayout(); }
protected override void OnInitialize() { base.OnInitialize(); var settings = Program.Settings; var scoreFileName = settings.Game.ScoreFile; var debug = Game.AsTheaterDays().FindSingleElement <DebugOverlay>(); if (string.IsNullOrEmpty(scoreFileName)) { if (debug != null) { debug.AddLine("ERROR: Score file is not specified."); } return; } if (!File.Exists(scoreFileName)) { if (debug != null) { debug.AddLine($"ERROR: Score file <{scoreFileName}> is missing."); } return; } if (Program.PluginManager.ScoreFormats.Count == 0) { if (debug != null) { debug.AddLine("ERROR: No available score reader."); } return; } var sourceOptions = new ReadSourceOptions { ScoreIndex = settings.Game.ScoreIndex }; var compileOptions = new ScoreCompileOptions { GlobalSpeed = 1, Offset = settings.Game.ScoreOffset }; var successful = false; RuntimeScore runtimeScore = null; SourceScore sourceScore = null; foreach (var format in Program.PluginManager.ScoreFormats) { if (!format.SupportsReadingFileType(scoreFileName)) { continue; } using (var reader = format.CreateReader()) { using (var fileStream = File.Open(scoreFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (!successful) { if (format.CanReadAsSource) { try { sourceScore = reader.ReadSourceScore(fileStream, scoreFileName, sourceOptions); if (!format.CanBeCompiled) { throw new InvalidOperationException("This format must support compiling source score to runtime score."); } using (var compiler = format.CreateCompiler()) { runtimeScore = compiler.Compile(sourceScore, compileOptions); } successful = true; } catch (Exception ex) { if (debug != null) { debug.AddLine($"An exception is thrown while trying to read the score using <{format.PluginDescription}>: {ex.Message}"); debug.AddLine(ex.StackTrace); } } } } if (!successful) { if (format.CanReadAsCompiled) { try { runtimeScore = reader.ReadCompiledScore(fileStream, scoreFileName, sourceOptions, compileOptions); successful = true; } catch (Exception ex) { if (debug != null) { debug.AddLine($"An exception is thrown while trying to read the score using <{format.PluginDescription}>: {ex.Message}"); debug.AddLine(ex.StackTrace); } } } } if (successful) { break; } } } } if (!successful) { if (debug != null) { debug.AddLine($"ERROR: No score reader can read score file <{scoreFileName}>."); } } else { _score = sourceScore; RuntimeScore = runtimeScore; if (debug != null) { debug.AddLine($"Loaded score file: {scoreFileName}"); } } }