diff --git a/scenes/main.tscn b/scenes/main.tscn index 4a9b0bf..317c889 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -130,7 +130,7 @@ handle_input_locally = false size = Vector2i(1280, 720) render_target_update_mode = 4 -[node name="Settings" type="ColorRect" parent="." unique_id=1393582030] +[node name="Settings" type="ColorRect" parent="." unique_id=1393582030 node_paths=PackedStringArray("ImportNightlyDialog")] visible = false z_index = 1 anchors_preset = 15 @@ -141,6 +141,7 @@ grow_vertical = 2 mouse_filter = 2 color = Color(0, 0, 0, 0.501961) script = ExtResource("2_o6xl0") +ImportNightlyDialog = NodePath("ImportNightlyDialog") [node name="Hide" type="Button" parent="Settings" unique_id=1153372742] self_modulate = Color(1, 1, 1, 0) @@ -429,6 +430,13 @@ grow_vertical = 2 mouse_filter = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_popqt") +[node name="ImportNightlyDialog" type="FileDialog" parent="Settings" unique_id=1831752407] +title = "Open a File" +file_mode = 0 +access = 2 +filters = PackedStringArray("*.json") +use_native_dialog = true + [node name="Volume" type="Panel" parent="." unique_id=1219254705] modulate = Color(1, 1, 1, 0) z_index = 1 diff --git a/scripts/Constants.cs b/scripts/Constants.cs index 580934f..7f0a19f 100644 --- a/scripts/Constants.cs +++ b/scripts/Constants.cs @@ -10,6 +10,8 @@ public partial class Constants : Node public static readonly string USER_FOLDER = OS.GetUserDataDir(); + public static readonly string NIGHTLY_FOLDER = $"{Path.GetDirectoryName(USER_FOLDER)}/SoundSpacePlus"; + public static readonly string DEFAULT_MAP_EXT = "phxm"; public static readonly bool TEMP_MAP_MODE = false;//OS.GetCmdlineArgs().Length > 0; diff --git a/scripts/SoundManager.cs b/scripts/SoundManager.cs index 9eb5913..e0fcea8 100644 --- a/scripts/SoundManager.cs +++ b/scripts/SoundManager.cs @@ -375,6 +375,12 @@ public static float ComputeVolumeDb(float volume, float master, float range) return (float)(-80 + range * Math.Pow(volume / 100, 0.1) * Math.Pow(master / 100, 0.1)); } + public static float ComputeVolumeFromDb(float db, float master, float range) + { + if (float.IsNegativeInfinity(db) || master <= 0) return 0; + return (float)Math.Clamp(100 * Math.Pow((db + 80) / (range * Math.Pow(master / 100, 0.1)), 10), 0, 100); + } + public static void UpdateVolume() { var settings = SettingsManager.Instance.Settings; diff --git a/scripts/database/settings/SettingsProfile.cs b/scripts/database/settings/SettingsProfile.cs index dd08503..5865924 100644 --- a/scripts/database/settings/SettingsProfile.cs +++ b/scripts/database/settings/SettingsProfile.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection.Metadata; +using System.Text.Json; using Godot; public partial class SettingsProfile @@ -342,11 +344,17 @@ public partial class SettingsProfile /// public SettingsItem DisplayFPS { get; private set; } - // [Order] + [Order] /// /// Import settings from previous (nightly) version /// - // public SettingsItem RhythiaImport { get; private set; } + public SettingsItem RhythiaImport { get; private set; } + + [Order] + /// + /// File dialog for the nightly import + /// + public SettingsItem ImportDialog { get; private set; } [Order] /// @@ -1030,18 +1038,37 @@ public SettingsProfile() #region Other - // RhythiaImport = new(default) - // { - // Id = "RhythiaImport", - // Title = "Import Nightly Settings", - // Description = "Imports settings from the nightly client", - // Section = SettingsSection.Other, - // Buttons = - // [ - // new() { Title = "Import", Description = "", OnPressed = () => { } } - // ], - // SaveToDisk = false, - // }; + RhythiaImport = new(default) + { + Id = "RhythiaImport", + Title = "Import Nightly Settings", + Description = "Imports settings from the nightly client", + Section = SettingsSection.Other, + Buttons = + [ + new() { Title = "Import", Description = "", OnPressed = () => { + + if (Directory.Exists(Constants.NIGHTLY_FOLDER)) { + ImportFromNightlySettings($"{Constants.NIGHTLY_FOLDER}/settings.json"); + } + } } + ], + SaveToDisk = false, + }; + + ImportDialog = new(default) + { + Id = "ImportDialog", + Title = "", + Description = "", + Section = SettingsSection.Other, + Buttons = + [ + new() { Title = "Choose file", Description = "", OnPressed = () => { + SettingsMenu.Instance.ImportNightlyDialog.PopupCentered(); + }} + ] + }; DisplayFPS = new(true) { @@ -1148,4 +1175,120 @@ private static List getAvailableMeshes() return meshes; } + + public static void ImportFromNightlySettings(string settingsPath) + { + string nightlySettings = File.Exists(settingsPath) ? File.ReadAllText(settingsPath) : null; + + if (nightlySettings == null) + { + ToastNotification.Notify("Nightly settings not found, choose the settings file manually."); + return; + } + + using JsonDocument json = JsonDocument.Parse(nightlySettings); + JsonElement root = json.RootElement; + + T? getSetting(string key) where T : struct + { + if (root.TryGetProperty(key, out JsonElement element)) + { + return element.Deserialize(); + } + + return null; + } + + // needs a separate helper for strings due to the struct constraint in getSetting() + string? getStringSetting(string key) + { + if (root.TryGetProperty(key, out JsonElement element)) + { + return element.GetString(); + } + return null; + } + + double importVolume(string nightlyKey, double range) + { + double? channelDb = getSetting(nightlyKey); + + if (channelDb == null) + { + return 50; + } + + double masterDb = getSetting("master_volume") ?? 20 * Math.Log10(0.5); + double totalDb = Math.Clamp(masterDb + channelDb.Value, -80, 0); + + return SoundManager.ComputeVolumeFromDb((float)totalDb, 100, (float)range); + } + + SettingsProfile nightlyProfile = new SettingsProfile(); + + // sensitivity scales with fov but in nightly it doesnt + nightlyProfile.Sensitivity.Value = getSetting("sensitivity") * 2.16 * (70 / (getSetting("fov") ?? 70)) ?? nightlyProfile.Sensitivity.Value; + nightlyProfile.AbsoluteSensitivity.Value = getSetting("absolute_scale") ?? nightlyProfile.AbsoluteSensitivity.Value; + nightlyProfile.AbsoluteInput.Value = getSetting("absolute_mode") ?? nightlyProfile.AbsoluteInput.Value; + nightlyProfile.CursorDrift.Value = getSetting("enable_drift_cursor") ?? nightlyProfile.CursorDrift.Value; + nightlyProfile.ApproachRate.Value = getSetting("approach_rate") ?? nightlyProfile.ApproachRate.Value; + nightlyProfile.ApproachDistance.Value = getSetting("spawn_distance") ?? nightlyProfile.ApproachDistance.Value; + nightlyProfile.Pushback.Value = getSetting("do_note_pushback") ?? nightlyProfile.Pushback.Value; + nightlyProfile.CameraParallax.Value = getSetting("parallax") * 0.025 ?? nightlyProfile.CameraParallax.Value; + nightlyProfile.HUDParallax.Value = getSetting("ui_parallax") * 0.025 ?? nightlyProfile.HUDParallax.Value; + nightlyProfile.FoV.Value = getSetting("fov") ?? nightlyProfile.FoV.Value; + nightlyProfile.NoteColors.Value = getStringSetting("selected_colorset") ?? nightlyProfile.NoteColors.Value; + nightlyProfile.NoteMesh.Value = getStringSetting("selected_mesh") ?? nightlyProfile.NoteMesh.Value; + nightlyProfile.NoteSize.Value = getSetting("note_size") * 0.875 ?? nightlyProfile.NoteSize.Value; + nightlyProfile.NoteOpacity.Value = getSetting("note_opacity") ?? nightlyProfile.NoteOpacity.Value; + nightlyProfile.CursorScale.Value = getSetting("cursor_scale") ?? nightlyProfile.CursorScale.Value; + nightlyProfile.CursorRotation.Value = getSetting("cursor_spin") ?? nightlyProfile.CursorRotation.Value; + nightlyProfile.CursorTrail.Value = getSetting("cursor_trail") ?? nightlyProfile.CursorTrail.Value; + nightlyProfile.TrailTime.Value = getSetting("trail_time") ?? nightlyProfile.TrailTime.Value; + nightlyProfile.TrailDetail.Value = getSetting("trail_detail") ?? nightlyProfile.TrailDetail.Value; + nightlyProfile.SimpleHUD.Value = getSetting("simple_hud") ?? nightlyProfile.SimpleHUD.Value; + nightlyProfile.HitPopups.Value = getSetting("score_popup") ?? nightlyProfile.HitPopups.Value; + nightlyProfile.MissPopups.Value = getSetting("show_miss_effect") ?? nightlyProfile.MissPopups.Value; + nightlyProfile.Fullscreen.Value = getSetting("window_fullscreen") ?? nightlyProfile.Fullscreen.Value; + nightlyProfile.FPS.Value = getSetting("target_fps") ?? nightlyProfile.FPS.Value; + nightlyProfile.VolumeMaster.Value = 100; + nightlyProfile.VolumeMusic.Value = importVolume("music_volume", 70); + nightlyProfile.VolumeHitSound.Value = importVolume("hit_volume", 80); + nightlyProfile.VolumeMissSound.Value = importVolume("miss_volume", 80); + nightlyProfile.VolumeSFX.Value = importVolume("fail_volume", 80); + nightlyProfile.EnableHitSound.Value = getSetting("play_hit_snd") ?? nightlyProfile.EnableHitSound.Value; + nightlyProfile.EnableMissSound.Value = getSetting("play_miss_snd") ?? nightlyProfile.EnableMissSound.Value; + nightlyProfile.EnableMenuMusic.Value = getSetting("play_menu_music") ?? nightlyProfile.EnableMenuMusic.Value; + nightlyProfile.AutoplayJukebox.Value = getSetting("auto_preview_song") ?? nightlyProfile.AutoplayJukebox.Value; + nightlyProfile.LocalOffset.Value = getSetting("music_offset") ?? nightlyProfile.LocalOffset.Value; + nightlyProfile.RecordReplays.Value = getSetting("record_replays") ?? nightlyProfile.RecordReplays.Value; + + // prevents overriding existing 'nightly' profile + string getProfileName(string baseName) + { + string profilesDir = $"{Constants.USER_FOLDER}/profiles"; + Directory.CreateDirectory(profilesDir); + + string name = baseName; + int suffix = 0; + + while (File.Exists($"{profilesDir}/{name}.json")) + { + suffix++; + name = $"{baseName}-{suffix}"; + } + + return name; + } + + string profileName = getProfileName("nightly"); + string profileJson = SettingsProfileConverter.Serialize(nightlyProfile); + File.WriteAllText($"{Constants.USER_FOLDER}/profiles/{profileName}.json", profileJson); + + SettingsManager.SetCurrentProfile(profileName); + SettingsManager.Load(); + SettingsMenu.Instance.UpdateProfileSelection(); + + ToastNotification.Notify($"Created profile '{profileName}'"); + } } diff --git a/scripts/ui/SettingsMenu.cs b/scripts/ui/SettingsMenu.cs index 1b89c2c..bbb718e 100644 --- a/scripts/ui/SettingsMenu.cs +++ b/scripts/ui/SettingsMenu.cs @@ -22,6 +22,8 @@ public partial class SettingsMenu : ColorRect private ScrollContainer selectedCategory; + [Export] public FileDialog ImportNightlyDialog; + public override void _Ready() { Instance = this; @@ -53,7 +55,7 @@ public override void _Ready() SettingsManager.SetCurrentProfile(profile); SettingsManager.Reload(); - updateProfileSelection(); + UpdateProfileSelection(); }; profilesButton.ItemSelected += (index) => @@ -67,7 +69,7 @@ public override void _Ready() SettingsManager.Load(); }; - updateProfileSelection(); + UpdateProfileSelection(); Panel settingTemplate = categoryTemplate.GetNode("Container").GetNode("SettingTemplate"); CheckButton checkButtonTemplate = settingTemplate.GetNode("CheckButton"); @@ -189,6 +191,7 @@ public override void _Ready() HideMenu(); hideButton.Pressed += HideMenu; + ImportNightlyDialog.FileSelected += SettingsProfile.ImportFromNightlySettings; } // Adding GetViewport().SetInputAsHandled() will prevent the Quit popup from appearing when clicking ESC in settings public override void _Input(InputEvent @event) @@ -248,7 +251,7 @@ public void SelectCategory(ScrollContainer category) sidebar.GetNode(new(selectedCategory.Name)).Color = Color.Color8(255, 255, 255, 8); } - private void updateProfileSelection() + public void UpdateProfileSelection() { // skip default for (int i = 1; i < profilesButton.ItemCount; i++)