diff --git a/scripts/SoundManager.cs b/scripts/SoundManager.cs index 7bf7cbb..7b78337 100644 --- a/scripts/SoundManager.cs +++ b/scripts/SoundManager.cs @@ -6,12 +6,20 @@ public partial class SoundManager : Node, ISkinnable { + public enum PlaybackScope + { + Silent, + Preview, + GameplayResults, + } + public static SoundManager Instance; public static AudioStreamPlayer HitSound; public static AudioStreamPlayer MissSound; public static AudioStreamPlayer FailSound; public static AudioStreamPlayer Song; + public static AudioStreamPlayer MenuMusic; public Action JukeboxPlayed; @@ -22,9 +30,11 @@ public partial class SoundManager : Node, ISkinnable public static bool JukeboxPaused = false; public static ulong LastRewind = 0; public static Map Map; + public static PlaybackScope Scope = PlaybackScope.Silent; private static bool volumePopupShown = false; private static ulong lastVolumeChange = 0; + private static bool? jeeping = null; // we're jeeping (last state of a song) public override void _Ready() { @@ -34,13 +44,16 @@ public override void _Ready() MissSound = new(); FailSound = new(); Song = new(); + MenuMusic = new(); HitSound.MaxPolyphony = 16; + MissSound.MaxPolyphony = 16; AddChild(HitSound); AddChild(MissSound); AddChild(FailSound); AddChild(Song); + AddChild(MenuMusic); SkinManager.Instance.Loaded += UpdateSkin; @@ -48,6 +61,12 @@ public override void _Ready() Song.Finished += () => { + if (isScopedPlayback()) + { + StopScopedSession(); + return; + } + switch (SceneManager.Scene.Name) { case "SceneMenu": @@ -67,15 +86,7 @@ public override void _Ready() SettingsManager.Instance.Loaded += UpdateVolume; Lobby.Instance.SpeedChanged += (speed) => { SoundManager.Song.PitchScale = (float)speed; }; - MapManager.Selected.ValueChanged += (_, selected) => - { - var map = selected.Value; - - if (Map == null || Map.Name != map.Name) - { - PlayJukebox(map); - } - }; + MapManager.Selected.ValueChanged += (_, _) => RefreshMenuMusicPlayback(); MapManager.MapDeleted += (map) => { @@ -86,6 +97,12 @@ public override void _Ready() return; } + if (isScopedPlayback()) + { + StopScopedSession(); + return; + } + if (JukeboxQueue.Length == 0) { Song.Stop(); @@ -108,19 +125,30 @@ static void start() { PlayJukebox(new Random().Next(0, JukeboxQueue.Length)); } + else + { + StopScopedSession(); + } } if (MapManager.Initialized) { start(); + printSongPlaybackState(); return; } MapManager.MapsInitialized += _ => start(); + + RefreshMenuMusicPlayback(); + printSongPlaybackState(); } public override void _Process(double delta) { + RefreshMenuMusicPlayback(); + printSongPlaybackState(); + if (volumePopupShown && Time.GetTicksMsec() - lastVolumeChange >= 1000) { volumePopupShown = false; @@ -167,6 +195,19 @@ public override void _UnhandledInput(InputEvent @event) public static void PlayJukebox(Map map, bool setRichPresence = true) { + if (map == null) + { + return; + } + + if (isScopedPlayback()) + { + StartMapSelectionPlayback(map, setRichPresence); + return; + } + + MenuMusic?.Stop(); + Map = map; if (map.AudioBuffer == null) @@ -212,6 +253,69 @@ public static void PlayJukebox(int index = -1, bool setRichPresence = true) PlayJukebox(map, setRichPresence); } + public static void StartMapSelectionPlayback(Map map, bool setRichPresence = true) + { + if (map == null) + { + return; + } + + Song.Stop(); + Song.StreamPaused = false; + Song.PitchScale = (float)Lobby.Speed; + MenuMusic?.Stop(); + + Map = map; + Scope = PlaybackScope.Preview; + + if (MapManager.Maps != null) + { + int mapIndex = MapManager.Maps.FindIndex(x => x.Id == map.Id); + if (mapIndex >= 0) + { + JukeboxIndex = mapIndex; + } + } + + Song.Stream = Util.Audio.LoadFromFile($"{MapUtil.MapsCacheFolder}/{map.Name}/audio.{map.AudioExt}"); + Song.Play(0); + + Instance.JukeboxPlayed?.Invoke(map); + + if (setRichPresence) + { + Discord.Client.UpdateState($"Listening to {map.PrettyTitle}"); + } + } + + public static void BeginGameplayScope(Map map) + { + if (!isScopedPlayback()) + { + return; + } + + Map = map; + Scope = PlaybackScope.GameplayResults; + MenuMusic?.Stop(); + } + + public static void StopScopedSession() + { + Song.Stop(); + Song.StreamPaused = false; + Map = null; + Scope = PlaybackScope.Silent; + Instance.JukeboxEmpty?.Invoke(); + + RefreshMenuMusicPlayback(); + } + + private static bool isScopedPlayback() + { + return !SettingsManager.Instance.Settings.AutoplayJukebox.Value; + } + public static float ComputeVolumeDb(float volume, float master, float range) { if (volume <= 0 || master <= 0) return float.NegativeInfinity; @@ -223,10 +327,32 @@ public static void UpdateVolume() var settings = SettingsManager.Instance.Settings; Song.VolumeDb = ComputeVolumeDb(settings.VolumeMusic.Value, settings.VolumeMaster.Value, 70); - HitSound.VolumeDb = ComputeVolumeDb(settings.VolumeSFX.Value, settings.VolumeMaster.Value, 80); + MenuMusic.VolumeDb = ComputeVolumeDb(settings.VolumeMenuMusic.Value, settings.VolumeMaster.Value, 70); + HitSound.VolumeDb = ComputeVolumeDb(settings.VolumeHitSound.Value, settings.VolumeMaster.Value, 80); + MissSound.VolumeDb = ComputeVolumeDb(settings.VolumeMissSound.Value, settings.VolumeMaster.Value, 80); FailSound.VolumeDb = ComputeVolumeDb(settings.VolumeSFX.Value, settings.VolumeMaster.Value, 80); } + public static void PlayHitSound() + { + if (!isSoundEffectEnabled(SettingsManager.Instance?.Settings.EnableHitSound, HitSound)) + { + return; + } + + HitSound.Play(); + } + + public static void PlayMissSound() + { + if (!isSoundEffectEnabled(SettingsManager.Instance?.Settings.EnableMissSound, MissSound)) + { + return; + } + + MissSound.Play(); + } + public static void UpdateJukeboxQueue() { JukeboxQueue = [.. MapManager.Maps.Select(x => x.Id)]; @@ -235,6 +361,72 @@ public static void UpdateJukeboxQueue() public void UpdateSkin(SkinProfile skin) { HitSound.Stream = Util.Audio.LoadStream(skin.HitSoundBuffer); + MissSound.Stream = Util.Audio.LoadStream(skin.MissSoundBuffer); FailSound.Stream = Util.Audio.LoadStream(skin.FailSoundBuffer); + MenuMusic.Stream = Util.Audio.LoadStream(skin.MenuMusicBuffer); + + RefreshMenuMusicPlayback(); + } + + public static void RefreshMenuMusicPlayback() + { + if (MenuMusic == null) + { + return; + } + + if (shouldPlayMenuMusic()) + { + if (!MenuMusic.Playing) + { + MenuMusic.Play(); + } + } + else if (MenuMusic.Playing) + { + MenuMusic.Stop(); + } + } + + private static bool shouldPlayMenuMusic() + { + if (!SettingsManager.Instance.Settings.EnableMenuMusic.Value) + { + return false; + } + + if (MenuMusic.Stream == null) + { + return false; + } + + if (SceneManager.Scene is not MainMenu) + { + return false; + } + + if (Song != null && Song.Playing) + { + return false; + } + + return true; + } + + private static bool isSoundEffectEnabled(SettingsItem setting, AudioStreamPlayer player) + { + return setting != null && setting.Value && player?.Stream != null; + } + + private static void printSongPlaybackState() + { + bool isSongPlaying = Song != null && Song.Playing; + + if (jeeping == isSongPlaying) // vroom vroom jeep + { + return; + } + + jeeping = isSongPlaying; //jeeps go beep beep } } diff --git a/scripts/database/settings/SettingsProfile.cs b/scripts/database/settings/SettingsProfile.cs index 2a51da9..13f3441 100644 --- a/scripts/database/settings/SettingsProfile.cs +++ b/scripts/database/settings/SettingsProfile.cs @@ -197,6 +197,12 @@ public partial class SettingsProfile [Order] public SettingsItem SimpleHUD { get; private set; } + /// + /// Toggles super minimal HUD + /// + [Order] + public SettingsItem SuperSimpleHUD { get; private set; } + /// /// Toggles a popup on a hit /// @@ -253,12 +259,48 @@ public partial class SettingsProfile [Order] public SettingsItem VolumeSFX { get; private set; } + /// + /// Audio control for hit sound + /// + [Order] + public SettingsItem VolumeHitSound { get; private set; } + + /// + /// Audio control for miss sound + /// + [Order] + public SettingsItem VolumeMissSound { get; private set; } + + /// + /// Audio control for menu music + /// + [Order] + public SettingsItem VolumeMenuMusic { get; private set; } + /// /// Toggles hit sound to always play /// [Order] public SettingsItem AlwaysPlayHitSound { get; private set; } + /// + /// Enables hit sound playback + /// + [Order] + public SettingsItem EnableHitSound { get; private set; } + + /// + /// Enables miss sound playback + /// + [Order] + public SettingsItem EnableMissSound { get; private set; } + + /// + /// Enables menu music playback + /// + [Order] + public SettingsItem EnableMenuMusic { get; private set; } + /// /// Automatically plays the jukebox on start /// @@ -694,6 +736,14 @@ public SettingsProfile() Section = SettingsSection.Visual, }; + SuperSimpleHUD = new(false) + { + Id = "SuperSimpleHUD", + Title = "Super Simple HUD", + Description = "Hides health bar, song duration, and song name", + Section = SettingsSection.Visual, + }; + HitPopups = new(true) { Id = "HitPopups", @@ -766,6 +816,37 @@ public SettingsProfile() Section = SettingsSection.Audio, }; + EnableHitSound = new(true) + { + Id = "EnableHitSound", + Title = "Enable Hit Sound", + Description = "Enables hit sound playback", + Section = SettingsSection.Audio, + }; + + EnableMissSound = new(true) + { + Id = "EnableMissSound", + Title = "Enable Miss Sound", + Description = "Enables miss sound playback", + Section = SettingsSection.Audio, + }; + + EnableMenuMusic = new(true) + { + Id = "EnableMenuMusic", + Title = "Enable Menu Music", + Description = "Enables menu music playback when the menu is quiet", + Section = SettingsSection.Audio, + UpdateAction = (_, init) => + { + if (!init) + { + SoundManager.RefreshMenuMusicPlayback(); + } + } + }; + VolumeMaster = new(50) { Id = "VolumeMaster", @@ -800,7 +881,52 @@ public SettingsProfile() { Id = "VolumeSFX", Title = "SFX Volume", - Description = "Audio control for sound effects", + Description = "Audio control for other sound effects", + Section = SettingsSection.Audio, + UpdateAction = (_, init) => { if (!init) { SoundManager.UpdateVolume(); } }, + Slider = new() + { + Step = 1, + MinValue = 0, + MaxValue = 100 + } + }; + + VolumeHitSound = new(50) + { + Id = "VolumeHitSound", + Title = "Hit Sound Volume", + Description = "Audio control for hit sound", + Section = SettingsSection.Audio, + UpdateAction = (_, init) => { if (!init) { SoundManager.UpdateVolume(); } }, + Slider = new() + { + Step = 1, + MinValue = 0, + MaxValue = 100 + } + }; + + VolumeMissSound = new(50) + { + Id = "VolumeMissSound", + Title = "Miss Sound Volume", + Description = "Audio control for miss sound", + Section = SettingsSection.Audio, + UpdateAction = (_, init) => { if (!init) { SoundManager.UpdateVolume(); } }, + Slider = new() + { + Step = 1, + MinValue = 0, + MaxValue = 100 + } + }; + + VolumeMenuMusic = new(50) + { + Id = "VolumeMenuMusic", + Title = "Menu Music Volume", + Description = "Audio control for menu music", Section = SettingsSection.Audio, UpdateAction = (_, init) => { if (!init) { SoundManager.UpdateVolume(); } }, Slider = new() diff --git a/scripts/map/Leaderboard.cs b/scripts/map/Leaderboard.cs index 0450b4c..e3fe78e 100644 --- a/scripts/map/Leaderboard.cs +++ b/scripts/map/Leaderboard.cs @@ -3,6 +3,7 @@ using System.Data.Common; using System.IO; using System.Security.Cryptography; +using System.Text; using Godot; public struct Leaderboard @@ -86,12 +87,14 @@ public void Save() foreach (Score score in Scores) { ulong offset = file.GetPosition(); + byte[] attemptIdBytes = Encoding.UTF8.GetBytes(score.AttemptID ?? string.Empty); + byte[] playerBytes = Encoding.UTF8.GetBytes(score.Player ?? string.Empty); file.Store32(0); // reserved for length - file.Store32((uint)score.AttemptID.Length); - file.StoreString(score.AttemptID); - file.Store32((uint)score.Player.Length); - file.StoreString(score.Player); + file.Store32((uint)attemptIdBytes.Length); + file.StoreBuffer(attemptIdBytes); + file.Store32((uint)playerBytes.Length); + file.StoreBuffer(playerBytes); file.Store8((byte)(score.Qualifies ? 1 : 0)); file.Store64(score.Value); file.StoreDouble(score.Accuracy); @@ -108,9 +111,10 @@ public void Save() } string json = Json.Stringify(modifiers); + byte[] modifiersBytes = Encoding.UTF8.GetBytes(json); - file.Store32((uint)json.Length); - file.StoreString(json); + file.Store32((uint)modifiersBytes.Length); + file.StoreBuffer(modifiersBytes); ulong end = file.GetPosition(); @@ -151,8 +155,14 @@ public Score(byte[] buffer) { FileParser FileBuffer = new(buffer); - AttemptID = FileBuffer.GetString((int)FileBuffer.GetUInt32()); - Player = FileBuffer.GetString((int)FileBuffer.GetUInt32()); + int attemptIdLength = (int)FileBuffer.GetUInt32(); + Console.WriteLine($"[Leaderboard] attemptId length={attemptIdLength}, remaining={FileBuffer.Length - FileBuffer.Pointer}"); + AttemptID = FileBuffer.GetString(attemptIdLength); + + int playerLength = (int)FileBuffer.GetUInt32(); + Console.WriteLine($"[Leaderboard] player length={playerLength}, remaining={FileBuffer.Length - FileBuffer.Pointer}"); + Player = FileBuffer.GetString(playerLength); + Qualifies = FileBuffer.GetBool(); Value = FileBuffer.GetUInt64(); Accuracy = FileBuffer.GetDouble(); @@ -162,7 +172,10 @@ public Score(byte[] buffer) Speed = FileBuffer.GetDouble(); Modifiers = []; - foreach (KeyValuePair entry in (Godot.Collections.Dictionary)Json.ParseString(FileBuffer.GetString((int)FileBuffer.GetUInt32()))) + int modifiersLength = (int)FileBuffer.GetUInt32(); + Console.WriteLine($"[Leaderboard] modifiers length={modifiersLength}, remaining={FileBuffer.Length - FileBuffer.Pointer}"); + + foreach (KeyValuePair entry in (Godot.Collections.Dictionary)Json.ParseString(FileBuffer.GetString(modifiersLength))) { Modifiers[entry.Key] = entry.Value; } diff --git a/scripts/scenes/LegacyRunner.cs b/scripts/scenes/LegacyRunner.cs index 0081f09..e79dd36 100644 --- a/scripts/scenes/LegacyRunner.cs +++ b/scripts/scenes/LegacyRunner.cs @@ -29,6 +29,8 @@ public partial class LegacyRunner : BaseScene private static MultiMeshInstance3D notesMultimesh; private static MultiMeshInstance3D cursorTrailMultimesh; private static TextureRect healthTexture; + private static Node healthPanel; + private static Node progressBarNode; private static TextureRect progressBarTexture; private static SubViewport panelLeft; private static SubViewport panelRight; @@ -290,7 +292,7 @@ public void Hit(int index) if (!settings.AlwaysPlayHitSound.Value) { - SoundManager.HitSound.Play(); + SoundManager.PlayHitSound(); } hitTween?.Kill(); @@ -368,6 +370,8 @@ public void Miss(int index) } } + SoundManager.PlayMissSound(); + multiplierLabel.Text = $"{ComboMultiplier}x"; missesLabel.Text = $"{Misses}"; simpleMissesLabel.Text = $"{Misses}"; @@ -489,8 +493,10 @@ public override void _Ready() cursorTrailMultimesh = holder.GetNode("CursorTrail"); //jesus = GetNode("Jesus"); - healthTexture = holder.GetNode("Health").GetNode("HealthViewport").GetNode("Main"); - progressBarTexture = holder.GetNode("ProgressBar").GetNode("ProgressBarViewport").GetNode("Main"); + healthPanel = holder.GetNode("Health"); + healthTexture = healthPanel.GetNode("HealthViewport").GetNode("Main"); + progressBarNode = holder.GetNode("ProgressBar"); + progressBarTexture = progressBarNode.GetNode("ProgressBarViewport").GetNode("Main"); panelLeft = holder.GetNode("PanelLeft").GetNode("PanelLeftViewport"); panelRight = holder.GetNode("PanelRight").GetNode("PanelRightViewport"); //bell = GetNode("Bell"); @@ -656,6 +662,32 @@ public override void _Ready() simpleMissesLabel.Visible = true; } + bool superSimpleHUD = settings.SuperSimpleHUD.Value; + if (superSimpleHUD) + { + // Apply everything SimpleHUD hides + Godot.Collections.Array widgets = panelLeft.GetChildren(); + widgets.AddRange(panelRight.GetChildren()); + foreach (Node widget in widgets) + (widget as CanvasItem).Visible = false; + simpleMissesLabel.Visible = true; + + // Additionally hide title, progress text, combo, health, and progress bar + titleLabel.Visible = false; + progressLabel.Visible = false; + comboLabel.Visible = false; + + if (healthPanel is CanvasItem healthCanvas) + healthCanvas.Visible = false; + else if (healthPanel is Node3D healthNode3D) + healthNode3D.Visible = false; + + if (progressBarNode is CanvasItem progressBarCanvas) + progressBarCanvas.Visible = false; + else if (progressBarNode is Node3D progressBarNode3D) + progressBarNode3D.Visible = false; + } + float fov = (float)(CurrentAttempt.IsReplay ? CurrentAttempt.Replays[0].FoV : settings.FoV.Value); MenuShown = false; @@ -691,7 +723,7 @@ public override void _Ready() try { StandardMaterial3D cursorMaterial = cursor.MaterialOverride as StandardMaterial3D ?? cursor.GetActiveMaterial(0) as StandardMaterial3D; - float cursorOpacity = Math.Clamp(settings.CursorOpacity.Value / 100f, 0, 1); + float cursorOpacity = Math.Min(Math.Clamp(settings.CursorOpacity.Value / 100f, 0, 1), 0.998f); float cursorTransparency = 1f - cursorOpacity; cursor.Transparency = cursorTransparency; @@ -1040,7 +1072,7 @@ public override void _Process(double delta) { CurrentAttempt.Map.Notes[i].Hittable = true; - SoundManager.HitSound.Play(); + SoundManager.PlayHitSound(); } ToProcess++; @@ -1273,12 +1305,15 @@ public static void Play(Map map, double speed = 1, double startFrom = 0, Diction SceneManager.Root.GetViewport().GuiGetFocusOwner()?.ReleaseFocus(); + SoundManager.MenuMusic?.Stop(); + if (Playing) { Stop(); } CurrentAttempt = new(map, speed, startFrom, mods ?? [], players, replays); + SoundManager.BeginGameplayScope(CurrentAttempt.Map); Playing = true; stopQueued = false; Started = Time.GetTicksUsec(); diff --git a/scripts/scenes/MainMenu.cs b/scripts/scenes/MainMenu.cs index c83515e..f29daaa 100644 --- a/scripts/scenes/MainMenu.cs +++ b/scripts/scenes/MainMenu.cs @@ -99,8 +99,9 @@ public override void Load() SceneManager.Space?.UpdateMap(map); } - // Resume jukebox only if song has ended (not if it's still playing from results fade) - if (!SoundManager.Song.Playing && SoundManager.Map != null) + SoundManager.RefreshMenuMusicPlayback(); + + if (SettingsManager.Instance.Settings.AutoplayJukebox.Value && !SoundManager.Song.Playing && SoundManager.Map != null) { SoundManager.PlayJukebox(SoundManager.JukeboxIndex); } @@ -134,5 +135,7 @@ public void Transition(Panel menu, bool instant = false) Tween inTween = CreateTween().SetTrans(Tween.TransitionType.Quad); inTween.TweenProperty(CurrentMenu, "modulate", Color.Color8(255, 255, 255), tweenTime); + + SoundManager.RefreshMenuMusicPlayback(); } } diff --git a/scripts/scenes/Results.cs b/scripts/scenes/Results.cs index a2ee0a3..77c8057 100644 --- a/scripts/scenes/Results.cs +++ b/scripts/scenes/Results.cs @@ -24,6 +24,9 @@ public override void _Ready() holder = GetNode("Holder"); cover = GetNode("Cover"); + // stops menu music after going to results scene + SoundManager.MenuMusic?.Stop(); + Input.MouseMode = settings.UseCursorInMenus ? Input.MouseModeEnum.Hidden : Input.MouseModeEnum.Visible; MenuCursor.Instance.Visible = settings.UseCursorInMenus; @@ -62,7 +65,7 @@ public override void _Ready() } } - if (LegacyRunner.CurrentAttempt.Map.AudioBuffer != null) + if (SettingsManager.Instance.Settings.AutoplayJukebox.Value && LegacyRunner.CurrentAttempt.Map.AudioBuffer != null) { if (!SoundManager.Song.Playing) { @@ -172,6 +175,11 @@ public void Replay() public void Stop() { + if (!SettingsManager.Instance.Settings.AutoplayJukebox.Value) + { + SoundManager.StopScopedSession(); + } + SoundManager.Song.PitchScale = (float)Lobby.Speed; SoundManager.UpdateVolume(); SceneManager.Load("res://scenes/main_menu.tscn"); diff --git a/scripts/skinning/SkinManager.cs b/scripts/skinning/SkinManager.cs index c39d77b..4e5f346 100644 --- a/scripts/skinning/SkinManager.cs +++ b/scripts/skinning/SkinManager.cs @@ -130,7 +130,9 @@ public static void Load() // Sounds skin.HitSoundBuffer = loadSound("hit.mp3"); + skin.MissSoundBuffer = loadSound("miss.mp3"); skin.FailSoundBuffer = loadSound("fail.mp3"); + skin.MenuMusicBuffer = loadSound("menu.mp3"); // Meshes diff --git a/scripts/skinning/SkinProfile.cs b/scripts/skinning/SkinProfile.cs index 971b821..94233ec 100644 --- a/scripts/skinning/SkinProfile.cs +++ b/scripts/skinning/SkinProfile.cs @@ -117,8 +117,12 @@ public partial class SkinProfile : GodotObject public byte[] HitSoundBuffer { get; set; } = []; + public byte[] MissSoundBuffer { get; set; } = []; + public byte[] FailSoundBuffer { get; set; } = []; + public byte[] MenuMusicBuffer { get; set; } = []; + public Color[] NoteColors { get; set; } = [new(0xff0059), new(0xffd8e6)]; public ArrayMesh NoteMesh { get; set; } = new(); diff --git a/scripts/ui/menu/JukeboxPanel.cs b/scripts/ui/menu/JukeboxPanel.cs index 24d90ef..a05f234 100644 --- a/scripts/ui/menu/JukeboxPanel.cs +++ b/scripts/ui/menu/JukeboxPanel.cs @@ -126,12 +126,22 @@ private void pause() private void skip() { + if (!SettingsManager.Instance.Settings.AutoplayJukebox.Value) + { + return; + } + SoundManager.JukeboxIndex++; SoundManager.PlayJukebox(SoundManager.JukeboxIndex); } private void rewind() { + if (!SettingsManager.Instance.Settings.AutoplayJukebox.Value) + { + return; + } + if (SoundManager.Song.GetPlaybackPosition() < 2) { SoundManager.JukeboxIndex--; diff --git a/scripts/ui/menu/play/MapInfoContainer.cs b/scripts/ui/menu/play/MapInfoContainer.cs index d2e9ffb..7aaa034 100644 --- a/scripts/ui/menu/play/MapInfoContainer.cs +++ b/scripts/ui/menu/play/MapInfoContainer.cs @@ -174,9 +174,9 @@ void applySpeed() Lobby.SetSpeed(value); - if (SoundManager.Map.Name != Map.Name) + if (SoundManager.Map?.Name == Map.Name && SoundManager.Song.Playing) { - SoundManager.PlayJukebox(Map); + SoundManager.Song.PitchScale = (float)Lobby.Speed; } } @@ -234,14 +234,9 @@ void applyStartFrom(string input = null, bool seek = true) Lobby.SetStartFrom(value); - if (SoundManager.Map.Name != Map.Name) + if (seek && SoundManager.Map?.Name == Map.Name && SoundManager.Song.Playing) { - SoundManager.PlayJukebox(Map); - } - - if (seek) - { - SoundManager.Song.Play((float)Lobby.StartFrom / 1000); + SoundManager.Song.Seek((float)Lobby.StartFrom / 1000); } } diff --git a/scripts/ui/menu/play/MapList.cs b/scripts/ui/menu/play/MapList.cs index 0dec9c8..493d3a4 100644 --- a/scripts/ui/menu/play/MapList.cs +++ b/scripts/ui/menu/play/MapList.cs @@ -460,6 +460,7 @@ private MapButton setupButton(MapButton button) if (dragDistance < 500) { Select(button.Map); + SoundManager.StartMapSelectionPlayback(button.Map); button.Select(); button.UpdateOutline(1.0f); diff --git a/user/skins/default/menu.mp3 b/user/skins/default/menu.mp3 new file mode 100644 index 0000000..4037223 Binary files /dev/null and b/user/skins/default/menu.mp3 differ diff --git a/user/skins/default/menu.mp3.import b/user/skins/default/menu.mp3.import new file mode 100644 index 0000000..0945c7f --- /dev/null +++ b/user/skins/default/menu.mp3.import @@ -0,0 +1,19 @@ +[remap] + +importer="mp3" +type="AudioStreamMP3" +uid="uid://dmcsqenc85jnh" +path="res://.godot/imported/menu.mp3-6464f7e421fc1b163d703d2d678f5f82.mp3str" + +[deps] + +source_file="res://user/skins/default/menu.mp3" +dest_files=["res://.godot/imported/menu.mp3-6464f7e421fc1b163d703d2d678f5f82.mp3str"] + +[params] + +loop=false +loop_offset=0 +bpm=0 +beat_count=0 +bar_beats=4 diff --git a/user/skins/default/miss.mp3 b/user/skins/default/miss.mp3 new file mode 100644 index 0000000..558b27a Binary files /dev/null and b/user/skins/default/miss.mp3 differ diff --git a/user/skins/default/miss.mp3.import b/user/skins/default/miss.mp3.import new file mode 100644 index 0000000..0842ebb --- /dev/null +++ b/user/skins/default/miss.mp3.import @@ -0,0 +1,19 @@ +[remap] + +importer="mp3" +type="AudioStreamMP3" +uid="uid://bhtrqahx56g0j" +path="res://.godot/imported/miss.mp3-235545ab9419b9c9c15664ce4032a32a.mp3str" + +[deps] + +source_file="res://user/skins/default/miss.mp3" +dest_files=["res://.godot/imported/miss.mp3-235545ab9419b9c9c15664ce4032a32a.mp3str"] + +[params] + +loop=false +loop_offset=0 +bpm=0 +beat_count=0 +bar_beats=4