// Should be called once the physics system has settled down void Init() { ChartEditor editor = ChartEditor.Instance; Debug.Assert(!hitWindowFeeder.enabled); hitWindowFeeder.enabled = true; if (botEnabled) { // We want the bot to automatically hit any sustains that are currently active in the view, but for which the notes are already past the strikeline Song song = editor.currentSong; float currentTime = editor.currentVisibleTime; uint currentTick = song.TimeToTick(currentTime, song.resolution); int index = SongObjectHelper.FindClosestPositionRoundedDown(currentTick, editor.currentChart.notes); if (index != SongObjectHelper.NOTFOUND) { Note note = editor.currentChart.notes[index]; List <Note> sustainNotes = new List <Note>(); NoteFunctions.GetPreviousOfSustains(sustainNotes, note, GameSettings.extendedSustainsEnabled); foreach (Note chordNote in note.chord) { sustainNotes.Add(chordNote); } foreach (Note sustainNote in sustainNotes) { if (sustainNote.controller != null) { hitWindowFeeder.TryAddNote(sustainNote.controller); } } } } }
static void AddNote(Note note, IList <BaseAction> subActions, bool extendedSustainsEnabled) { ChartEditor editor = ChartEditor.Instance; Chart chart = editor.currentChart; Song song = editor.currentSong; NoteFunctions.PerformPreChartInsertCorrections(note, chart, subActions, extendedSustainsEnabled); AddAndInvokeSubAction(new AddAction(note), subActions); int arrayPos = SongObjectHelper.FindObjectPosition(note, chart.chartObjects); if (arrayPos != SongObjectHelper.NOTFOUND) { Note justAdded = chart.chartObjects[arrayPos] as Note; if (justAdded == null) { UnityEngine.Debug.LogError("Object just added was not a note"); } else { NoteFunctions.PerformPostChartInsertCorrections(justAdded, subActions, extendedSustainsEnabled); } } else { UnityEngine.Debug.LogError("Unable to find note that was just added"); } }
static void CapNoteCheck(Chart chart, Note noteToAdd, IList <BaseAction> subActions, Song song, bool extendedSustainsEnabled) { Note[] previousNotes = NoteFunctions.GetPreviousOfSustains(noteToAdd, extendedSustainsEnabled); if (!Globals.gameSettings.extendedSustainsEnabled) { // Cap all the notes foreach (Note prevNote in previousNotes) { uint newLength = prevNote.GetCappedLength(noteToAdd, song); if (prevNote.length != newLength) { Note newNote = new Note(prevNote.tick, prevNote.rawNote, newLength, prevNote.flags); SongEditCommand.AddAndInvokeSubAction(new DeleteAction(prevNote), subActions); SongEditCommand.AddAndInvokeSubAction(new AddAction(newNote), subActions); } } foreach (Note chordNote in noteToAdd.chord) { uint newLength = noteToAdd.length; if (chordNote.length != newLength) { Note newNote = new Note(chordNote.tick, chordNote.rawNote, newLength, chordNote.flags); SongEditCommand.AddAndInvokeSubAction(new DeleteAction(chordNote), subActions); SongEditCommand.AddAndInvokeSubAction(new AddAction(newNote), subActions); } } } else { // Cap only the sustain of the same fret type and open notes foreach (Note prevNote in previousNotes) { if ( #if OPEN_NOTES_BLOCK_EXTENDED_SUSTAINS noteToAdd.IsOpenNote() || #endif prevNote.guitarFret == noteToAdd.guitarFret ) { uint newLength = prevNote.GetCappedLength(noteToAdd, song); if (prevNote.length != newLength) { Note newNote = new Note(prevNote.tick, prevNote.rawNote, newLength, prevNote.flags); SongEditCommand.AddAndInvokeSubAction(new DeleteAction(prevNote), subActions); SongEditCommand.AddAndInvokeSubAction(new AddAction(newNote), subActions); } } } } }
static void CapNoteCheck(Chart chart, Note noteToAdd, IList <SongObject> overwrittenList, IList <SongObject> replacementNotes, Song song, bool extendedSustainsEnabled) { Note[] previousNotes = NoteFunctions.GetPreviousOfSustains(noteToAdd, extendedSustainsEnabled); if (!GameSettings.extendedSustainsEnabled) { // Cap all the notes foreach (Note prevNote in previousNotes) { uint newLength = prevNote.GetCappedLength(noteToAdd, song); if (prevNote.length != newLength) { Note newNote = new Note(prevNote.tick, prevNote.rawNote, newLength, prevNote.flags); AddOrReplaceNote(chart, prevNote, newNote, overwrittenList, replacementNotes); } } foreach (Note chordNote in noteToAdd.chord) { uint newLength = noteToAdd.length; if (chordNote.length != newLength) { if (noteToAdd == chordNote) { noteToAdd.length = newLength; } else { Note newNote = new Note(chordNote.tick, chordNote.rawNote, newLength, chordNote.flags); AddOrReplaceNote(chart, chordNote, newNote, overwrittenList, replacementNotes); } } } } else { // Cap only the sustain of the same fret type and open notes foreach (Note prevNote in previousNotes) { if (noteToAdd.IsOpenNote() || prevNote.guitarFret == noteToAdd.guitarFret) { uint newLength = prevNote.GetCappedLength(noteToAdd, song); if (prevNote.length != newLength) { overwrittenList.Add(prevNote); chart.Add(new Note(prevNote.tick, prevNote.rawNote, newLength, prevNote.flags)); } } } } }
void UpdateTogglesInteractable() { // Prevent users from forcing notes when they shouldn't be forcable but retain the previous user-set forced property when using the note tool bool drumsMode = Globals.drumMode; bool proDrumsMode = drumsMode && Globals.gameSettings.drumsModeOptions == GameSettings.DrumModeOptions.ProDrums; forcedToggle.gameObject.SetActive(!drumsMode); tapToggle.gameObject.SetActive(!drumsMode); cymbalToggle.gameObject.SetActive(proDrumsMode); doubleKickToggle.gameObject.SetActive(proDrumsMode); if (!drumsMode) { if (IsInNoteTool() && (noteToolObject.activeSelf || Globals.gameSettings.keysModeEnabled)) { forcedToggle.interactable = noteToolController.forcedInteractable; tapToggle.interactable = noteToolController.tapInteractable; } else if (!IsInNoteTool()) { forcedToggle.interactable = !(currentNote.cannotBeForced && !Globals.gameSettings.keysModeEnabled); tapToggle.interactable = !currentNote.IsOpenNote(); } else { forcedToggle.interactable = true; tapToggle.interactable = true; } } else { if (IsInNoteTool() && noteToolObject.activeSelf) { cymbalToggle.interactable = noteToolController.cymbalInteractable; doubleKickToggle.interactable = noteToolController.doubleKickInteractable; } else if (!IsInNoteTool()) { cymbalToggle.interactable = NoteFunctions.AllowedToBeCymbal(currentNote); doubleKickToggle.interactable = NoteFunctions.AllowedToBeDoubleKick(currentNote, editor.currentDifficulty); } else { cymbalToggle.interactable = true; doubleKickToggle.interactable = true; } } }
protected static ActionHistory.Action[] CapNoteCheck(Note noteToAdd) { List <ActionHistory.Action> actionRecord = new List <ActionHistory.Action>(); Note[] previousNotes = NoteFunctions.GetPreviousOfSustains(noteToAdd); if (!GameSettings.extendedSustainsEnabled) { // Cap all the notes foreach (Note prevNote in previousNotes) { if (prevNote.controller != null) { ActionHistory.Action action = prevNote.CapSustain(noteToAdd); if (action != null) { actionRecord.Add(action); } } } foreach (Note chordNote in noteToAdd.chord) { if (chordNote.controller != null) { chordNote.controller.note.length = noteToAdd.length; } } } else { // Cap only the sustain of the same fret type and open notes foreach (Note prevNote in previousNotes) { if (prevNote.controller != null && (noteToAdd.IsOpenNote() || prevNote.guitarFret == noteToAdd.guitarFret)) { ActionHistory.Action action = prevNote.CapSustain(noteToAdd); if (action != null) { actionRecord.Add(action); } } } } return(actionRecord.ToArray()); }
static void AddNote(Note note, IList <SongObject> overwrittenList, bool extendedSustainsEnabled, List <SongObject> validatedNotes) { ChartEditor editor = ChartEditor.Instance; Chart chart = editor.currentChart; Song song = editor.currentSong; Note noteToAdd = new Note(note); NoteFunctions.PerformPreChartInsertCorrections(noteToAdd, chart, validatedNotes, overwrittenList, extendedSustainsEnabled); chart.Add(noteToAdd, false); NoteFunctions.PerformPostChartInsertCorrections(noteToAdd, validatedNotes, overwrittenList, extendedSustainsEnabled); // Queue visual refresh { foreach (Note chordNote in noteToAdd.chord) { if (chordNote.controller) { chordNote.controller.SetDirty(); } } Note next = noteToAdd.nextSeperateNote; if (next != null) { foreach (Note chordNote in next.chord) { if (chordNote.controller) { chordNote.controller.SetDirty(); } } } } if (!validatedNotes.Contains(noteToAdd)) { validatedNotes.Add(noteToAdd); } }
private static void ReadNotes(IList <MidiEvent> track, Song song, Song.Instrument instrument) { List <NoteOnEvent> forceNotesList = new List <NoteOnEvent>(); List <NoteOnEvent> proDrumsNotesList = new List <NoteOnEvent>(); List <SysexEvent> tapAndOpenEvents = new List <SysexEvent>(); Chart unrecognised = new Chart(song, Song.Instrument.Unrecognised); Chart.GameMode gameMode = Song.InstumentToChartGameMode(instrument); if (instrument == Song.Instrument.Unrecognised) { song.unrecognisedCharts.Add(unrecognised); } int rbSustainFixLength = (int)(64 * song.resolution / SongConfig.STANDARD_BEAT_RESOLUTION); // Load all the notes for (int i = 0; i < track.Count; i++) { var text = track[i] as TextEvent; if (text != null) { if (i == 0) { if (instrument == Song.Instrument.Unrecognised) { unrecognised.name = text.Text; } continue; // We don't want the first event because that is the name of the track } var tick = (uint)text.AbsoluteTime; var eventName = text.Text.Trim(new char[] { '[', ']' }); ChartEvent chartEvent = new ChartEvent(tick, eventName); if (instrument == Song.Instrument.Unrecognised) { unrecognised.Add(chartEvent); } else { song.GetChart(instrument, Song.Difficulty.Expert).Add(chartEvent); } } var note = track[i] as NoteOnEvent; if (note != null && note.OffEvent != null) { Song.Difficulty difficulty; var tick = (uint)note.AbsoluteTime; var sus = (uint)(note.OffEvent.AbsoluteTime - tick); if (instrument == Song.Instrument.Unrecognised) { int rawNote = SelectRawNoteValue(note.NoteNumber); Note newNote = new Note(tick, rawNote, sus); //difficulty = SelectRawNoteDifficulty(note.NoteNumber); unrecognised.Add(newNote); continue; } // Check if starpower event if (note.NoteNumber == MidIOHelper.STARPOWER_NOTE) { foreach (Song.Difficulty diff in EnumX <Song.Difficulty> .Values) { song.GetChart(instrument, diff).Add(new Starpower(tick, sus), false); } continue; } if (note.NoteNumber == MidIOHelper.SOLO_NOTE) { foreach (Song.Difficulty diff in EnumX <Song.Difficulty> .Values) { Chart chart = song.GetChart(instrument, diff); chart.Add(new ChartEvent(tick, MidIOHelper.SoloEventText)); chart.Add(new ChartEvent(tick + sus, MidIOHelper.SoloEndEventText)); } continue; } if (gameMode == Chart.GameMode.Drums) { Note.DrumPad dummy; if (MidIOHelper.CYMBAL_TO_PAD_LOOKUP.TryGetValue(note.NoteNumber, out dummy)) { // Cymbals toggles proDrumsNotesList.Add(note); continue; } } // Determine which difficulty we are manipulating try { if (gameMode == Chart.GameMode.GHLGuitar) { difficulty = SelectGHLNoteDifficulty(note.NoteNumber); } else { difficulty = SelectNoteDifficulty(note.NoteNumber); } } catch { continue; } // Check if we're reading a forcing event instead of a regular note if (gameMode != Chart.GameMode.Drums) { switch (note.NoteNumber) { case 65: case 66: case 77: case 78: case 89: case 90: case 101: case 102: forceNotesList.Add(note); // Store the event for later processing and continue continue; default: break; } } int fret; if (sus <= rbSustainFixLength) { sus = 0; } Note.Flags flags = Note.Flags.None; if (gameMode == Chart.GameMode.Drums) { fret = (int)GetDrumFretType(note.NoteNumber); int cymbalToggleId; if (MidIOHelper.PAD_TO_CYMBAL_LOOKUP.TryGetValue((Note.DrumPad)fret, out cymbalToggleId)) { flags |= Note.Flags.ProDrums_Cymbal; } } else if (gameMode == Chart.GameMode.GHLGuitar) { fret = (int)GetGHLFretType(note.NoteNumber); } else { fret = (int)GetStandardFretType(note.NoteNumber); } { // Add the note to the correct chart Note newNote = new Note(tick, fret, sus, flags); song.GetChart(instrument, difficulty).Add(newNote, false); } } var sysexEvent = track[i] as SysexEvent; if (sysexEvent != null) { tapAndOpenEvents.Add(sysexEvent); } } // Update all chart arrays if (instrument != Song.Instrument.Unrecognised) { foreach (Song.Difficulty diff in EnumX <Song.Difficulty> .Values) { song.GetChart(instrument, diff).UpdateCache(); } } else { unrecognised.UpdateCache(); } // Apply tap and open note events Chart[] chartsOfInstrument; if (instrument == Song.Instrument.Unrecognised) { chartsOfInstrument = new Chart[] { unrecognised }; } else { chartsOfInstrument = new Chart[EnumX <Song.Difficulty> .Count]; int difficultyCount = 0; foreach (Song.Difficulty difficulty in EnumX <Song.Difficulty> .Values) { chartsOfInstrument[difficultyCount++] = song.GetChart(instrument, difficulty); } } for (int i = 0; i < tapAndOpenEvents.Count; ++i) { var se1 = tapAndOpenEvents[i]; byte[] bytes = se1.GetData(); // Check for tap event if (bytes.Length == 8 && bytes[5] == 255 && bytes[7] == 1) { // Identified a tap section // 8 total bytes, 5th byte is FF, 7th is 1 to start, 0 to end uint tick = (uint)se1.AbsoluteTime; uint endPos = 0; // Find the end of the tap section for (int j = i; j < tapAndOpenEvents.Count; ++j) { var se2 = tapAndOpenEvents[j]; var bytes2 = se2.GetData(); /// Check for tap section end if (bytes2.Length == 8 && bytes2[5] == 255 && bytes2[7] == 0) { endPos = (uint)(se2.AbsoluteTime - tick); if (endPos > 0) { --endPos; } break; } } // Apply tap property foreach (Chart chart in chartsOfInstrument) { int index, length; SongObjectHelper.GetRange(chart.notes, tick, tick + endPos, out index, out length); for (int k = index; k < index + length; ++k) { chart.notes[k].SetType(Note.NoteType.Tap); } } } // Check for open notes // 5th byte determines the difficulty to apply to else if (bytes.Length == 8 && bytes[5] >= 0 && bytes[5] < 4 && bytes[7] == 1) { uint tick = (uint)se1.AbsoluteTime; Song.Difficulty difficulty; switch (bytes[5]) { case 0: difficulty = Song.Difficulty.Easy; break; case 1: difficulty = Song.Difficulty.Medium; break; case 2: difficulty = Song.Difficulty.Hard; break; case 3: difficulty = Song.Difficulty.Expert; break; default: continue; } uint endPos = 0; for (int j = i; j < tapAndOpenEvents.Count; ++j) { var se2 = tapAndOpenEvents[j] as SysexEvent; if (se2 != null) { var b2 = se2.GetData(); if (b2.Length == 8 && b2[5] == bytes[5] && b2[7] == 0) { endPos = (uint)(se2.AbsoluteTime - tick); if (endPos > 0) { --endPos; } break; } } } int index, length; SongObjectCache <Note> notes; if (instrument == Song.Instrument.Unrecognised) { notes = unrecognised.notes; } else { notes = song.GetChart(instrument, difficulty).notes; } SongObjectHelper.GetRange(notes, tick, tick + endPos, out index, out length); for (int k = index; k < index + length; ++k) { notes[k].guitarFret = Note.GuitarFret.Open; if (gameMode == Chart.GameMode.Drums) { notes[k].guitarFret = NoteFunctions.LoadDrumNoteToGuitarNote(notes[k].guitarFret); } } } } // Apply forcing events foreach (NoteOnEvent flagEvent in forceNotesList) { uint tick = (uint)flagEvent.AbsoluteTime; uint endPos = (uint)(flagEvent.OffEvent.AbsoluteTime - tick); Song.Difficulty difficulty; // Determine which difficulty we are manipulating try { difficulty = SelectNoteDifficulty(flagEvent.NoteNumber); } catch { continue; } Chart chart; if (instrument != Song.Instrument.Unrecognised) { chart = song.GetChart(instrument, difficulty); } else { chart = unrecognised; } int index, length; SongObjectHelper.GetRange(chart.notes, tick, tick + endPos, out index, out length); for (int i = index; i < index + length; ++i) { if ((chart.notes[i].flags & Note.Flags.Tap) != 0) { continue; } // if NoteNumber is odd force hopo, if even force strum if (flagEvent.NoteNumber % 2 != 0) { chart.notes[i].SetType(Note.NoteType.Hopo); } else { chart.notes[i].SetType(Note.NoteType.Strum); } } } foreach (var flagEvent in proDrumsNotesList) { uint tick = (uint)flagEvent.AbsoluteTime; uint endPos = (uint)(flagEvent.OffEvent.AbsoluteTime - tick); if (endPos > 0) { --endPos; } Debug.Assert(instrument == Song.Instrument.Drums); foreach (Song.Difficulty difficulty in EnumX <Song.Difficulty> .Values) { Chart chart = song.GetChart(instrument, difficulty); int index, length; SongObjectHelper.GetRange(chart.notes, tick, tick + endPos, out index, out length); Note.DrumPad drumPadForFlag; if (!MidIOHelper.CYMBAL_TO_PAD_LOOKUP.TryGetValue(flagEvent.NoteNumber, out drumPadForFlag)) { Debug.Assert(false, "Unknown note number flag " + flagEvent.NoteNumber); continue; } for (int i = index; i < index + length; ++i) { Note note = chart.notes[i]; if (note.drumPad == drumPadForFlag) { // Reverse cymbal flag note.flags ^= Note.Flags.ProDrums_Cymbal; } } } } }
void CollectNotesInViewRange(IList <Note> notes) { bool extendedSustainsEnabled = GameSettings.extendedSustainsEnabled; uint min_pos = editor.minPos; if (noteVisibilityRangeYPosOverride.HasValue) { uint gameplayPos = editor.currentSong.WorldYPositionToTick(noteVisibilityRangeYPosOverride.Value, editor.currentSong.resolution); if (min_pos < gameplayPos) { min_pos = gameplayPos; } } collectedNotesInRange.Clear(); int index, length; SongObjectHelper.GetRange(notes, min_pos, editor.maxPos, out index, out length); for (int i = index; i < index + length; ++i) { collectedNotesInRange.Add(notes[i]); } if (min_pos == editor.minPos) { if (collectedNotesInRange.Count > 0) { NoteFunctions.GetPreviousOfSustains(prevSustainCache, collectedNotesInRange[0], extendedSustainsEnabled); // Find the last known note of each fret type to find any sustains that might overlap into the camera view foreach (Note prevNote in prevSustainCache) { if (prevNote.tick + prevNote.length > editor.minPos) { collectedNotesInRange.Add(prevNote); } } } else { int minArrayPos = SongObjectHelper.FindClosestPosition(editor.minPos, editor.currentChart.notes); if (minArrayPos != SongObjectHelper.NOTFOUND) { while (minArrayPos > 0 && editor.currentChart.notes[minArrayPos].tick == editor.currentChart.notes[minArrayPos - 1].tick) { --minArrayPos; } Note minNote = editor.currentChart.notes[minArrayPos]; if (minNote.tick + minNote.length > editor.minPos && minNote.tick < editor.maxPos) { foreach (Note note in minNote.chord) { if (note.tick + note.length > editor.minPos) { collectedNotesInRange.Add(note); } } } NoteFunctions.GetPreviousOfSustains(prevSustainCache, minNote, extendedSustainsEnabled); foreach (Note prevNote in prevSustainCache) { if (prevNote.tick + prevNote.length > editor.minPos) { collectedNotesInRange.Add(prevNote); } } } } } // Make sure the notes are within the allowable lanes for (int i = collectedNotesInRange.Count - 1; i >= 0; --i) { Note note = collectedNotesInRange[i]; if (!note.IsOpenNote() && ((1 << note.rawNote) & editor.laneInfo.laneMask) == 0) { collectedNotesInRange.RemoveAt(i); } } }
public static Note.Flags GetFlagsToSetType(this Note note, Note.NoteType type) { Note.Flags flags = Note.Flags.None; switch (type) { case (Note.NoteType.Strum): if (note.isChord) { flags &= ~Note.Flags.Forced; } else { if (note.isNaturalHopo) { flags |= Note.Flags.Forced; } else { flags &= ~Note.Flags.Forced; } } break; case (Note.NoteType.Hopo): if (!note.cannotBeForced) { if (note.isChord) { flags |= Note.Flags.Forced; } else { if (!note.isNaturalHopo) { flags |= Note.Flags.Forced; } else { flags &= ~Note.Flags.Forced; } } } break; case (Note.NoteType.Tap): if (!note.IsOpenNote()) { flags |= Note.Flags.Tap; } break; case (Note.NoteType.Cymbal): if (NoteFunctions.AllowedToBeCymbal(note)) { flags |= Note.Flags.ProDrums_Cymbal; } break; default: break; } if (type != Note.NoteType.Natural && ((note.flags & Note.Flags.DoubleKick) != 0) && AllowedToBeDoubleKickIgnoreDifficulty(note)) { flags |= Note.Flags.DoubleKick; } return(flags); }
public static void LoadChart(Chart chart, string[] data, Song.Instrument instrument = Song.Instrument.Guitar) { #if TIMING_DEBUG float time = Time.realtimeSinceStartup; #endif List <NoteFlag> flags = new List <NoteFlag>(); chart.SetCapacity(data.Length); const int SPLIT_POSITION = 0; const int SPLIT_EQUALITY = 1; const int SPLIT_TYPE = 2; const int SPLIT_VALUE = 3; const int SPLIT_LENGTH = 4; try { // Load notes, collect flags foreach (string line in data) { try { string[] splitString = line.Split(' '); uint tick = uint.Parse(splitString[SPLIT_POSITION]); string type = splitString[SPLIT_TYPE].ToLower(); switch (type) { case ("n"): // Split string to get note information string[] digits = splitString; int fret_type = int.Parse(digits[SPLIT_VALUE]); uint length = uint.Parse(digits[SPLIT_LENGTH]); if (instrument == Song.Instrument.Unrecognised) { Note newNote = new Note(tick, fret_type, length); chart.Add(newNote, false); } else if (instrument == Song.Instrument.Drums) { LoadDrumNote(chart, tick, fret_type, length); } else if (instrument == Song.Instrument.GHLiveGuitar || instrument == Song.Instrument.GHLiveBass) { LoadGHLiveNote(chart, tick, fret_type, length, flags); } else { LoadStandardNote(chart, tick, fret_type, length, flags); } break; case ("s"): fret_type = int.Parse(splitString[SPLIT_VALUE]); if (fret_type != 2) { continue; } length = uint.Parse(splitString[SPLIT_LENGTH]); chart.Add(new Starpower(tick, length), false); break; case ("e"): string[] strings = splitString; string eventName = strings[SPLIT_VALUE]; chart.Add(new ChartEvent(tick, eventName), false); break; default: break; } } catch (System.Exception e) { Logger.LogException(e, "Error parsing chart reader line \"" + line); } } chart.UpdateCache(); // Load flags foreach (NoteFlag flag in flags) { int index, length; SongObjectHelper.FindObjectsAtPosition(flag.tick, chart.notes, out index, out length); if (length > 0) { NoteFunctions.GroupAddFlags(chart.notes, flag.flag, index, length); } } #if TIMING_DEBUG Debug.Log("Chart load time: " + (Time.realtimeSinceStartup - time)); #endif } catch (System.Exception e) { // Bad load, most likely a parsing error Logger.LogException(e, "Error parsing chart reader chart data"); chart.Clear(); } }
public static void LoadChart(Chart chart, string[] data, Song.Instrument instrument = Song.Instrument.Guitar) { #if TIMING_DEBUG float time = Time.realtimeSinceStartup; #endif List <NoteFlag> flags = new List <NoteFlag>(); chart.SetCapacity(data.Length); const int SPLIT_POSITION = 0; const int SPLIT_EQUALITY = 1; const int SPLIT_TYPE = 2; const int SPLIT_VALUE = 3; const int SPLIT_LENGTH = 4; try { // Load notes, collect flags foreach (string line in data) { try { string[] splitString = line.Split(' '); uint tick = uint.Parse(splitString[SPLIT_POSITION]); string type = splitString[SPLIT_TYPE].ToLower(); switch (type) { case ("n"): // Split string to get note information string[] digits = splitString; int fret_type = int.Parse(digits[SPLIT_VALUE]); uint length = uint.Parse(digits[SPLIT_LENGTH]); if (instrument == Song.Instrument.Unrecognised) { Note newNote = new Note(tick, fret_type, length); chart.Add(newNote, false); } else if (instrument == Song.Instrument.Drums) { LoadDrumNote(chart, tick, fret_type, length, flags); } else if (instrument == Song.Instrument.GHLiveGuitar || instrument == Song.Instrument.GHLiveBass) { LoadGHLiveNote(chart, tick, fret_type, length, flags); } else { LoadStandardNote(chart, tick, fret_type, length, flags); } break; case ("s"): fret_type = int.Parse(splitString[SPLIT_VALUE]); if (fret_type != 2) { continue; } length = uint.Parse(splitString[SPLIT_LENGTH]); chart.Add(new Starpower(tick, length), false); break; case ("e"): string[] strings = splitString; string eventName = strings[SPLIT_VALUE]; chart.Add(new ChartEvent(tick, eventName), false); break; default: break; } } catch (System.Exception e) { Logger.LogException(e, "Error parsing chart reader line \"" + line); } } chart.UpdateCache(); // Load flags foreach (NoteFlag flag in flags) { if (flag.flag == Note.Flags.ProDrums_Cymbal) { // The note number indicates which note it should attach to int noteNumber = flag.noteNumber - ChartIOHelper.c_proDrumsOffset; Debug.Assert(noteNumber >= 0, "Incorrectly parsed a note flag as a pro-drums flag. Note number was " + flag.noteNumber); int index, length; SongObjectHelper.FindObjectsAtPosition(flag.tick, chart.notes, out index, out length); if (length > 0) { for (int i = index; i < index + length; ++i) { Note note = chart.notes[i]; int saveNoteNum; if (!ChartIOHelper.c_drumNoteToSaveNumberLookup.TryGetValue(note.rawNote, out saveNoteNum)) { continue; } if (noteNumber == saveNoteNum) { // Reverse cymbal flag note.flags ^= Note.Flags.ProDrums_Cymbal; } } } } else { int index, length; SongObjectHelper.FindObjectsAtPosition(flag.tick, chart.notes, out index, out length); if (length > 0) { NoteFunctions.GroupAddFlags(chart.notes, flag.flag, index, length); } } } #if TIMING_DEBUG Debug.Log("Chart load time: " + (Time.realtimeSinceStartup - time)); #endif } catch (System.Exception e) { // Bad load, most likely a parsing error Logger.LogException(e, "Error parsing chart reader chart data"); chart.Clear(); } }