private static void WriteConductor([NotNull] this TextWriter writer, [NotNull] SourceScore sourceScore, int index) { writer.WriteLine($" [{index}]"); var conductor = sourceScore.Conductors[index]; writer.WriteLine(" EventConductorData data"); var absTime = ScoreCompileHelper.TicksToSeconds(conductor.Ticks, sourceScore.Conductors); writer.WriteLine(" double absTime = "+ absTime.ToString(CultureInfo.InvariantCulture)); writer.WriteLine(" UInt8 selected = 0"); writer.WriteLine(" SInt64 tick = "+ conductor.Ticks.ToString()); writer.WriteLine(" int measure = "+ conductor.Measure.ToString()); writer.WriteLine(" int beat = "+ conductor.Beat.ToString()); writer.WriteLine(" int track = 0"); writer.WriteLine(" double tempo = "+ conductor.Tempo.ToString(CultureInfo.InvariantCulture)); writer.WriteLine(" int tsigNumerator = "+ conductor.SignatureNumerator.ToString()); writer.WriteLine(" int tsigDenominator = "+ conductor.SignatureDenominator.ToString()); writer.WriteLine(" string marker = \"\""); }
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); }
private static SourceNote[] GeneratePhantomNotes([NotNull] SourceScore sourceScore) { var result = new List <SourceNote>(); var maxMeasure = 224; var ticksFactor = NoteBase.TicksPerBeat / 8; for (var measure = 0; measure <= maxMeasure; ++measure) { var primary = new SourceNote { TrackIndex = -1, Type = (NoteType)(-1), Speed = 1, Measure = measure + 1, Beat = 1, Ticks = 1920 * measure * ticksFactor }; result.Add(primary); for (var j = 2; j <= 4; ++j) { var secondary = new SourceNote { TrackIndex = -1, Type = (NoteType)(-2), Speed = 1, Measure = measure + 1, Beat = j, Ticks = primary.Ticks + (480 * (j - 1)) * ticksFactor }; result.Add(secondary); } } return(result.ToArray()); }
public static void FixNoteTickInfo([NotNull] NoteBase note, [NotNull] SourceScore sourceScore) { var baseConductor = sourceScore.Conductors[0]; // For a properly-designed beatmap, the extra measure count SHOULD be an integer. // Otherwise you need to move your music start to make it on a beat. var extraMeasures = (int)Math.Round(sourceScore.MusicOffset / (60 / baseConductor.Tempo) / baseConductor.SignatureDenominator); var tickDiff = NoteBase.TicksPerBeat * 60 * extraMeasures * baseConductor.SignatureDenominator; note.Measure += extraMeasures; note.Ticks += tickDiff; if (note is SourceNote n) { if (n.FollowingNotes != null && n.FollowingNotes.Length > 0) { foreach (var fn in n.FollowingNotes) { fn.Ticks += tickDiff; } } } }
public void WriteSourceScore(Stream stream, string fileName, SourceScore score) { throw new NotSupportedException(); }
/// <summary> /// Compiles a <see cref="SourceScore"/> to a <see cref="RuntimeScore"/> with custom note creation dispatcher. The compiled score will be used by the player. /// </summary> /// <param name="score">The <see cref="SourceScore"/> to compile.</param> /// <param name="compileOptions">Compile options.</param> /// <param name="notesCreation">The note creation delegate used to dispatch note creation calls.</param> /// <returns>Compiled score.</returns> public static RuntimeScore CompileScore([NotNull] SourceScore score, [NotNull] ScoreCompileOptions compileOptions, [NotNull] NotesCreation notesCreation) { if (score == null) { throw new ArgumentNullException(nameof(score)); } if (compileOptions == null) { throw new ArgumentNullException(nameof(compileOptions)); } // ReSharper cannot infer from "(score.Notes?.Count ?? 0) == 0" that score.Notes is later no longer null. if (score.Notes.Length == 0) { var notes = new RuntimeNote[0]; return(new RuntimeScore(notes)); } var gameNotes = score.Notes; var list = new List <RuntimeNote>(); var conductors = score.Conductors; var currentID = 0; foreach (var note in gameNotes) { var notesToBeAdded = notesCreation(note, conductors, gameNotes, ref currentID); list.AddRange(notesToBeAdded); } var totalNotesCount = list.Count; list.Sort(RuntimeNoteComparisons.ByTimeThenX); // Fix sync relations. Notice that you should keep NextSync's accessing order being after PrevSync. for (var i = 0; i < totalNotesCount - 1; ++i) { var note = list[i]; var nextNote = list[i + 1]; // About this strange behavior, see remarks on RuntimeNote.Ticks. if (note.HitTime.Equals(nextNote.HitTime)) { note.NextSync = nextNote; nextNote.PrevSync = note; } } // TODO: Fix flick/slide group. // Fix offsets var scoreOffset = compileOptions.Offset; foreach (var note in list) { note.HitTime += scoreOffset; } // Generate ScorePrepare note. var scorePrepareNote = new RuntimeNote(); scorePrepareNote.Type = NoteType.ScorePrepare; // This value should correspond to TapPoints' "score-prepare fade-in" animation duration. scorePrepareNote.HitTime = list[0].HitTime - 1.5f; scorePrepareNote.ID = ++currentID; list.Insert(0, scorePrepareNote); var runtimeNotes = list.ToArray(); return(new RuntimeScore(runtimeNotes) { TrackCount = score.TrackCount }); }
/// <summary> /// Compiles a <see cref="SourceScore"/> to a <see cref="RuntimeScore"/> with default note creation dispatcher. The compiled score will be used by the player. /// </summary> /// <param name="score">The <see cref="SourceScore"/> to compile.</param> /// <param name="compileOptions">Compile options.</param> /// <returns>Compiled score.</returns> public static RuntimeScore CompileScore([NotNull] SourceScore score, [NotNull] ScoreCompileOptions compileOptions) { return(CompileScore(score, compileOptions, CreateNotes)); }
private static void WriteEventNote([NotNull] this TextWriter writer, [NotNull] SourceScore sourceScore, [NotNull, ItemNotNull] SourceNote[] notes, int index, TrackType trackType) { writer.WriteLine($" [{index}]"); var sourceNote = notes[index]; writer.WriteLine(" EventNoteData data"); // MLTD: "offset > 0" means music is AFTER the beatmap // MilliSim: "offset > 0" means music is BEFORE the beatmap var absTime = ScoreCompileHelper.TicksToSeconds(sourceNote.Ticks, sourceScore.Conductors); writer.WriteLine(" double absTime = "+ absTime.ToString(CultureInfo.InvariantCulture)); writer.WriteLine(" UInt8 selected = 0"); writer.WriteLine(" SInt64 tick = "+ (sourceNote.Ticks / (NoteBase.TicksPerBeat / 8)).ToString()); if (sourceNote.Type < 0) { writer.WriteLine(" int measure = "+ sourceNote.Measure.ToString()); writer.WriteLine(" int beat = "+ sourceNote.Beat.ToString()); writer.WriteLine(" int track = -1"); } else { writer.WriteLine(" int measure = 0"); writer.WriteLine(" int beat = 0"); var tracks = MltdHelper.GetTrackIndicesFromTrackType(trackType); writer.WriteLine(" int track = "+ tracks[sourceNote.TrackIndex].ToString()); } writer.WriteLine(" int type = "+ ((int)MltdHelper.GetMltdNoteType(sourceNote)).ToString()); writer.WriteLine(" float startPosx = "+ sourceNote.StartX.ToString(CultureInfo.InvariantCulture)); writer.WriteLine(" float endPosx = "+ sourceNote.EndX.ToString(CultureInfo.InvariantCulture)); writer.WriteLine(" float speed = "+ sourceNote.Speed.ToString(CultureInfo.InvariantCulture)); if (sourceNote.FollowingNotes != null && sourceNote.FollowingNotes.Length > 0) { var duration = (int)((sourceNote.FollowingNotes[sourceNote.FollowingNotes.Length - 1].Ticks - sourceNote.Ticks) / (NoteBase.TicksPerBeat / 8)); writer.WriteLine(" int duration = "+ duration.ToString()); } else { writer.WriteLine(" int duration = 0"); } writer.WritePolyPoints(sourceNote, sourceNote.FollowingNotes); if (sourceNote.FollowingNotes != null && sourceNote.FollowingNotes.Length > 0) { writer.WriteLine(" int endType = "+ ((int)sourceNote.FollowingNotes[sourceNote.FollowingNotes.Length - 1].FlickDirection).ToString()); } else { writer.WriteLine(" int endType = 0"); } if (sourceNote.Type < 0) { writer.WriteLine(" double leadTime = 0"); } else { // TODO: What is this "magic number"? const double someConstant = 198.3471011848414; var bpm = ScorePreprocessor.GetCurrentBpm(sourceNote.Ticks, sourceScore.Conductors); var leadTime = someConstant / bpm; // TODO: Another guess... Didn't look too carefully inside speed variated notes. leadTime /= sourceNote.Speed; writer.WriteLine(" double leadTime = "+ leadTime.ToString(CultureInfo.InvariantCulture)); } }
public RuntimeScore Compile(SourceScore score, ScoreCompileOptions compileOptions) { compileOptions.Offset = (float)score.MusicOffset; return(ScoreCompileHelper.CompileScore(score, compileOptions)); }
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 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(); } }
/** * A demonstration of the usage of ScoreCompilerHelper methods. */ private RuntimeScore MyCompile(SourceScore score, ScoreCompileOptions compileOptions) { return(ScoreCompileHelper.CompileScore(score, compileOptions, CreateNotes)); }
/// <summary> /// Compiles a <see cref="SourceScore"/> to a <see cref="RuntimeScore"/>, which will be used by the player. /// A <see cref="ScoreCompileOptions"/> object can be specified. /// </summary> /// <param name="score">The <see cref="SourceScore"/> to compile.</param> /// <param name="compileOptions">Compile options.</param> /// <returns>Compiled score.</returns> public RuntimeScore Compile(SourceScore score, ScoreCompileOptions compileOptions) { return(ScoreCompileHelper.CompileScore(score, compileOptions)); }
private static void WriteNotes([NotNull] this TextWriter writer, [NotNull] SourceScore score, [NotNull] ScenarioScrObj template) { var notes = score.Notes; var noteList = new List <EventScenarioData>(); var specialNote = notes.FirstOrDefault(n => n.Type == NoteType.Special); // Mofify time: the tap buttons animation before the special note (the big round note) if (specialNote != null) { noteList.AddRange(template.scenario); var animNote = noteList.Find(n => n.type == ScenarioNoteType.BeginTapButtonsAnimation); if (animNote != null) { var specialNoteTime = ScoreCompileHelper.TicksToSeconds(specialNote.Ticks, score.Conductors); animNote.absTime = specialNoteTime - 0.5f; animNote.tick = ScorePreprocessor.SecondsToTicks(animNote.absTime, score.Conductors); } // Modify time: second tap buttons appearing time (the one that is after the special note) var reappearNote = notes.FirstOrDefault(n => n.Ticks > specialNote.Ticks); if (reappearNote != null && animNote != null) { var reaNote = noteList.Where(n => n.type == ScenarioNoteType.ShowTapButtons).Skip(1).FirstOrDefault(); if (reaNote != null) { var reappearNoteTime = ScoreCompileHelper.TicksToSeconds(reappearNote.Ticks, score.Conductors); reaNote.absTime = reappearNoteTime - 0.8f; reaNote.tick = ScorePreprocessor.SecondsToTicks(reaNote.absTime, score.Conductors); } } } noteList.Sort((n1, n2) => { var t = n1.tick.CompareTo(n2.tick); if (t != 0) { return(t); } t = ((int)n1.type).CompareTo((int)n2.type); if (t != 0) { return(t); } t = n1.idol.CompareTo(n2.idol); if (t != 0) { return(t); } return(n1.track.CompareTo(n2.track)); }); writer.Write(@"EventScenarioData scenario Array Array int size = " ); writer.WriteLine(noteList.Count.ToString()); for (var i = 0; i < noteList.Count; ++i) { var sn = noteList[i]; writer.WriteLine(" [{0}]", i.ToString()); writer.WriteScenarioNote(2, "data", sn); } }
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}"); } } }