// Start is called before the first frame update void Start() { objectContainerCollections = GetComponents <BeatmapObjectContainerCollection>() .Where(x => x is NotesContainer || x is ObstaclesContainer).ToList(); BeatmapObjectContainer.FlaggedForDeletionEvent += FlaggedForDeletion; Settings.NotifyBySettingName("RotateTrack", UpdateRotateTrack); songTimeInBeats = atsc.GetBeatFromSeconds(BeatSaberSongContainer.Instance.loadedSong.length); }
// Start is called before the first frame update IEnumerator Start() { yield return(new WaitForSeconds(0.1f)); //wait for ATSC to get song info, so we can get beats in the song VVV measureTextsByBeat.Add(0, measureLinePrefab); previousEnabledByBeat.Add(0, true); for (int i = 1; i <= Mathf.FloorToInt(atsc.GetBeatFromSeconds(BeatSaberSongContainer.Instance.loadedSong.length)); i++) { TextMeshProUGUI instantiate = Instantiate(measureLinePrefab, parent); instantiate.text = $"{i}"; instantiate.transform.localPosition = new Vector3(0, i * EditorScaleController.EditorScale, 0); measureTextsByBeat.Add(i, instantiate); previousEnabledByBeat.Add(i, true); } init = true; }
public void RefreshMeasureLines() { Debug.Log("Refreshing measure lines..."); init = false; Queue <TextMeshProUGUI> existing = new Queue <TextMeshProUGUI>(measureTextsByBeat.Values); measureTextsByBeat.Clear(); previousEnabledByBeat.Clear(); int rawBeatsInSong = Mathf.FloorToInt(atsc.GetBeatFromSeconds(BeatSaberSongContainer.Instance.loadedSong.length)); float jsonBeat = 0; int modifiedBeats = 0; float songBPM = BeatSaberSongContainer.Instance.song.beatsPerMinute; List <BeatmapBPMChange> allBPMChanges = new List <BeatmapBPMChange>() { new BeatmapBPMChange(songBPM, 0) }; allBPMChanges.AddRange(bpmChangesContainer.LoadedObjects.Cast <BeatmapBPMChange>()); while (jsonBeat <= rawBeatsInSong) { TextMeshProUGUI text = existing.Count > 0 ? existing.Dequeue() : Instantiate(measureLinePrefab, parent); text.text = $"{modifiedBeats}"; text.transform.localPosition = new Vector3(0, jsonBeat * EditorScaleController.EditorScale, 0); measureTextsByBeat.Add(jsonBeat, text); previousEnabledByBeat.Add(jsonBeat, true); modifiedBeats++; BeatmapBPMChange last = allBPMChanges.Last(x => x._Beat <= modifiedBeats); jsonBeat = ((modifiedBeats - last._Beat) / last._BPM * songBPM) + last._time; } // Set proper spacing between Notes grid, Measure lines, and Events grid measureLinesGridChild.Size = modifiedBeats > 1000 ? 1 : 0; foreach (TextMeshProUGUI leftovers in existing) { Destroy(leftovers.gameObject); } init = true; RefreshVisibility(); RefreshPositions(); }
public void RefreshMeasureLines() { init = false; Queue <TextMeshProUGUI> existing = new Queue <TextMeshProUGUI>(measureTextsByBeat.Values); measureTextsByBeat.Clear(); previousEnabledByBeat.Clear(); int rawBeatsInSong = Mathf.FloorToInt(atsc.GetBeatFromSeconds(BeatSaberSongContainer.Instance.loadedSong.length)); float beatsProcessed = 1; float rawBPMtoChangedBPMRatio = 1; int modifiedBeats = 1; BeatmapBPMChange lastBPMChange = null; while (beatsProcessed <= rawBeatsInSong) { TextMeshProUGUI text = existing.Count > 0 ? existing.Dequeue() : Instantiate(measureLinePrefab, parent); text.gameObject.SetActive(true); text.text = $"{modifiedBeats}"; text.transform.localPosition = new Vector3(0, beatsProcessed * EditorScaleController.EditorScale, 0); measureTextsByBeat.Add(beatsProcessed, text); previousEnabledByBeat.Add(beatsProcessed, true); modifiedBeats++; BeatmapBPMChange last = bpmChangesContainer.FindLastBPM(beatsProcessed + rawBPMtoChangedBPMRatio, true); if (last != lastBPMChange && last?._BPM > 0) { lastBPMChange = last; beatsProcessed = last._time; rawBPMtoChangedBPMRatio = BeatSaberSongContainer.Instance.song.beatsPerMinute / last._BPM; } else { beatsProcessed += rawBPMtoChangedBPMRatio; } } foreach (TextMeshProUGUI leftovers in existing) { Destroy(leftovers.gameObject); } init = true; RefreshVisibility(); RefreshPositions(); }
void PlaySound(bool initial, int index, BeatmapObject objectData) { // Filter notes that are too far behind the current beat // (Commonly occurs when Unity freezes for some unrelated f*****g reason) if (objectData._time - container.AudioTimeSyncController.CurrentBeat <= -0.5f) { return; } //actual ding stuff if (objectData._time == lastCheckedTime || !NoteTypeToDing[((BeatmapNote)objectData)._type]) { return; } /* * As for why we are not using "initial", it is so notes that are not supposed to ding do not prevent notes at * the same time that are supposed to ding from triggering the sound effects. */ lastCheckedTime = objectData._time; var soundListId = Settings.Instance.NoteHitSound; var list = soundLists[soundListId]; var shortCut = false; if (index - DensityCheckOffset > 0 && index + DensityCheckOffset < container.LoadedObjects.Count) { BeatmapObject first = container.LoadedObjects.ElementAt(index + DensityCheckOffset); BeatmapObject second = container.LoadedObjects.ElementAt(index - DensityCheckOffset); if (first != null && second != null) { if (first._time - objectData._time <= ThresholdInNoteTime && objectData._time - second._time <= ThresholdInNoteTime) { shortCut = true; } } } var timeUntilDing = objectData._time - atsc.GetBeatFromSeconds(atsc.songAudioSource.time); var hitTime = (atsc.GetSecondsFromBeat(timeUntilDing) / songSpeed) - offset; audioUtil.PlayOneShotSound(list.GetRandomClip(shortCut), Settings.Instance.NoteHitVolume, 1, hitTime); }
private void CreateAutogeneratedBPMChange(int res) { if (res == 2) { return; } Settings.Instance.Reminder_UnsupportedEditorOffset = res == 0; float offset = BeatSaberSongContainer.Instance.difficultyData.customData["_editorOffset"]; BeatSaberSongContainer.Instance.difficultyData.customData.Remove("_editorOffset"); BeatSaberSongContainer.Instance.difficultyData.customData.Remove("_editorOldOffset"); BeatmapBPMChange autoGenerated = new BeatmapBPMChange( BeatSaberSongContainer.Instance.song.beatsPerMinute, AudioTimeSyncController.GetBeatFromSeconds(offset / 1000f)); autoGenerated._customData = new SimpleJSON.JSONObject(); autoGenerated._customData.Add("__note", "Autogenerated by ChroMapper"); SpawnObject(autoGenerated, true, false); RefreshGridShaders(); RefreshPool(true); }