From 8664aed4cc11b2059521039151b96fdc646dbc3e Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Sun, 22 Oct 2023 15:43:39 -0400 Subject: [PATCH 1/4] Implement "Open Recent" menu --- assets | 2 +- source/funkin/save/Save.hx | 308 +++++++++++++++++- .../charting/ChartEditorDialogHandler.hx | 48 +++ .../ui/debug/charting/ChartEditorState.hx | 205 +++++++++--- source/funkin/util/Constants.hx | 5 + source/funkin/util/FileUtil.hx | 21 +- 6 files changed, 527 insertions(+), 62 deletions(-) diff --git a/assets b/assets index 118b62295..c1cea2051 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 118b622953171aaf127cb160538e21bc468620e2 +Subproject commit c1cea20513dfa93e3e74a0db98498b2fd8da50fc diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 54b66605c..dcf7f9f0d 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -1,16 +1,19 @@ package funkin.save; import flixel.util.FlxSave; -import funkin.save.migrator.SaveDataMigrator; -import thx.semver.Version; import funkin.Controls.Device; import funkin.save.migrator.RawSaveData_v1_0_0; +import funkin.save.migrator.SaveDataMigrator; +import funkin.ui.debug.charting.ChartEditorState.LiveInputStyle; +import funkin.ui.debug.charting.ChartEditorThemeHandler.ChartEditorTheme; +import thx.semver.Version; @:nullSafety @:forward(volume, mute) abstract Save(RawSaveData) { - public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.0"; + // Version 2.0.1 adds attributes to `optionsChartEditor`, that should return default values if they are null. + public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.1"; public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x"; // We load this version's saves from a new save path, to maintain SOME level of backwards compatibility. @@ -94,6 +97,18 @@ abstract Save(RawSaveData) optionsChartEditor: { // Reasonable defaults. + previousFiles: [], + noteQuant: 3, + liveInputStyle: LiveInputStyle.None, + theme: ChartEditorTheme.Light, + playtestStartTime: false, + downscroll: false, + metronomeEnabled: true, + hitsoundsEnabledPlayer: true, + hitsoundsEnabledOpponent: true, + instVolume: 1.0, + voicesVolume: 1.0, + playbackSpeed: 1.0, }, }; } @@ -124,7 +139,9 @@ abstract Save(RawSaveData) function set_ngSessionId(value:Null):Null { - return this.api.newgrounds.sessionId = value; + this.api.newgrounds.sessionId = value; + flush(); + return this.api.newgrounds.sessionId; } public var enabledModIds(get, set):Array; @@ -136,7 +153,213 @@ abstract Save(RawSaveData) function set_enabledModIds(value:Array):Array { - return this.mods.enabledMods = value; + this.mods.enabledMods = value; + flush(); + return this.mods.enabledMods; + } + + public var chartEditorPreviousFiles(get, set):Array; + + function get_chartEditorPreviousFiles():Array + { + if (this.optionsChartEditor.previousFiles == null) this.optionsChartEditor.previousFiles = []; + + return this.optionsChartEditor.previousFiles; + } + + function set_chartEditorPreviousFiles(value:Array):Array + { + // Set and apply. + this.optionsChartEditor.previousFiles = value; + flush(); + return this.optionsChartEditor.previousFiles; + } + + public var chartEditorNoteQuant(get, set):Int; + + function get_chartEditorNoteQuant():Int + { + if (this.optionsChartEditor.noteQuant == null) this.optionsChartEditor.noteQuant = 3; + + return this.optionsChartEditor.noteQuant; + } + + function set_chartEditorNoteQuant(value:Int):Int + { + // Set and apply. + this.optionsChartEditor.noteQuant = value; + flush(); + return this.optionsChartEditor.noteQuant; + } + + public var chartEditorLiveInputStyle(get, set):LiveInputStyle; + + function get_chartEditorLiveInputStyle():LiveInputStyle + { + if (this.optionsChartEditor.liveInputStyle == null) this.optionsChartEditor.liveInputStyle = LiveInputStyle.None; + + return this.optionsChartEditor.liveInputStyle; + } + + function set_chartEditorLiveInputStyle(value:LiveInputStyle):LiveInputStyle + { + // Set and apply. + this.optionsChartEditor.liveInputStyle = value; + flush(); + return this.optionsChartEditor.liveInputStyle; + } + + public var chartEditorDownscroll(get, set):Bool; + + function get_chartEditorDownscroll():Bool + { + if (this.optionsChartEditor.downscroll == null) this.optionsChartEditor.downscroll = false; + + return this.optionsChartEditor.downscroll; + } + + function set_chartEditorDownscroll(value:Bool):Bool + { + // Set and apply. + this.optionsChartEditor.downscroll = value; + flush(); + return this.optionsChartEditor.downscroll; + } + + public var chartEditorPlaytestStartTime(get, set):Bool; + + function get_chartEditorPlaytestStartTime():Bool + { + if (this.optionsChartEditor.playtestStartTime == null) this.optionsChartEditor.playtestStartTime = false; + + return this.optionsChartEditor.playtestStartTime; + } + + function set_chartEditorPlaytestStartTime(value:Bool):Bool + { + // Set and apply. + this.optionsChartEditor.playtestStartTime = value; + flush(); + return this.optionsChartEditor.playtestStartTime; + } + + public var chartEditorTheme(get, set):ChartEditorTheme; + + function get_chartEditorTheme():ChartEditorTheme + { + if (this.optionsChartEditor.theme == null) this.optionsChartEditor.theme = ChartEditorTheme.Light; + + return this.optionsChartEditor.theme; + } + + function set_chartEditorTheme(value:ChartEditorTheme):ChartEditorTheme + { + // Set and apply. + this.optionsChartEditor.theme = value; + flush(); + return this.optionsChartEditor.theme; + } + + public var chartEditorMetronomeEnabled(get, set):Bool; + + function get_chartEditorMetronomeEnabled():Bool + { + if (this.optionsChartEditor.metronomeEnabled == null) this.optionsChartEditor.metronomeEnabled = true; + + return this.optionsChartEditor.metronomeEnabled; + } + + function set_chartEditorMetronomeEnabled(value:Bool):Bool + { + // Set and apply. + this.optionsChartEditor.metronomeEnabled = value; + flush(); + return this.optionsChartEditor.metronomeEnabled; + } + + public var chartEditorHitsoundsEnabledPlayer(get, set):Bool; + + function get_chartEditorHitsoundsEnabledPlayer():Bool + { + if (this.optionsChartEditor.hitsoundsEnabledPlayer == null) this.optionsChartEditor.hitsoundsEnabledPlayer = true; + + return this.optionsChartEditor.hitsoundsEnabledPlayer; + } + + function set_chartEditorHitsoundsEnabledPlayer(value:Bool):Bool + { + // Set and apply. + this.optionsChartEditor.hitsoundsEnabledPlayer = value; + flush(); + return this.optionsChartEditor.hitsoundsEnabledPlayer; + } + + public var chartEditorHitsoundsEnabledOpponent(get, set):Bool; + + function get_chartEditorHitsoundsEnabledOpponent():Bool + { + if (this.optionsChartEditor.hitsoundsEnabledOpponent == null) this.optionsChartEditor.hitsoundsEnabledOpponent = true; + + return this.optionsChartEditor.hitsoundsEnabledOpponent; + } + + function set_chartEditorHitsoundsEnabledOpponent(value:Bool):Bool + { + // Set and apply. + this.optionsChartEditor.hitsoundsEnabledOpponent = value; + flush(); + return this.optionsChartEditor.hitsoundsEnabledOpponent; + } + + public var chartEditorInstVolume(get, set):Float; + + function get_chartEditorInstVolume():Float + { + if (this.optionsChartEditor.instVolume == null) this.optionsChartEditor.instVolume = 1.0; + + return this.optionsChartEditor.instVolume; + } + + function set_chartEditorInstVolume(value:Float):Float + { + // Set and apply. + this.optionsChartEditor.instVolume = value; + flush(); + return this.optionsChartEditor.instVolume; + } + + public var chartEditorVoicesVolume(get, set):Float; + + function get_chartEditorVoicesVolume():Float + { + if (this.optionsChartEditor.voicesVolume == null) this.optionsChartEditor.voicesVolume = 1.0; + + return this.optionsChartEditor.voicesVolume; + } + + function set_chartEditorVoicesVolume(value:Float):Float + { + // Set and apply. + this.optionsChartEditor.voicesVolume = value; + flush(); + return this.optionsChartEditor.voicesVolume; + } + + public var chartEditorPlaybackSpeed(get, set):Float; + + function get_chartEditorPlaybackSpeed():Float + { + if (this.optionsChartEditor.playbackSpeed == null) this.optionsChartEditor.playbackSpeed = 1.0; + + return this.optionsChartEditor.playbackSpeed; + } + + function set_chartEditorPlaybackSpeed(value:Float):Float + { + // Set and apply. + this.optionsChartEditor.playbackSpeed = value; + flush(); + return this.optionsChartEditor.playbackSpeed; } /** @@ -699,4 +922,77 @@ typedef SaveControlsData = /** * An anonymous structure containing all the user's options and preferences, specific to the Chart Editor. */ -typedef SaveDataChartEditorOptions = {}; +typedef SaveDataChartEditorOptions = +{ + /** + * Previous files opened in the Chart Editor. + * @default `[]` + */ + var ?previousFiles:Array; + + /** + * Note snapping level in the Chart Editor. + * @default `3` + */ + var ?noteQuant:Int; + + /** + * Live input style in the Chart Editor. + * @default `LiveInputStyle.None` + */ + var ?liveInputStyle:LiveInputStyle; + + /** + * Theme in the Chart Editor. + * @default `ChartEditorTheme.Light` + */ + var ?theme:ChartEditorTheme; + + /** + * Downscroll in the Chart Editor. + * @default `false` + */ + var ?downscroll:Bool; + + /** + * Metronome sounds in the Chart Editor. + * @default `true` + */ + var ?metronomeEnabled:Bool; + + /** + * If true, playtest songs from the current position in the Chart Editor. + * @default `false` + */ + var ?playtestStartTime:Bool; + + /** + * Player note hit sounds in the Chart Editor. + * @default `true` + */ + var ?hitsoundsEnabledPlayer:Bool; + + /** + * Opponent note hit sounds in the Chart Editor. + * @default `true` + */ + var ?hitsoundsEnabledOpponent:Bool; + + /** + * Instrumental volume in the Chart Editor. + * @default `1.0` + */ + var ?instVolume:Float; + + /** + * Voices volume in the Chart Editor. + * @default `1.0` + */ + var ?voicesVolume:Float; + + /** + * Playback speed in the Chart Editor. + * @default `1.0` + */ + var ?playbackSpeed:Float; +}; diff --git a/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx b/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx index dd5ddb06c..dd874577a 100644 --- a/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx +++ b/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx @@ -84,11 +84,47 @@ class ChartEditorDialogHandler var dialog:Null = openDialog(state, CHART_EDITOR_DIALOG_WELCOME_LAYOUT, true, closable); if (dialog == null) throw 'Could not locate Welcome dialog'; + state.isHaxeUIDialogOpen = true; dialog.onDialogClosed = function(_event) { + state.isHaxeUIDialogOpen = false; // Called when the Welcome dialog is closed while it is closable. state.stopWelcomeMusic(); } + #if sys + var splashRecentContainer:Null = dialog.findComponent('splashRecentContainer', VBox); + if (splashRecentContainer == null) throw 'Could not locate splashRecentContainer in Welcome dialog'; + + for (chartPath in state.previousWorkingFilePaths) + { + var linkRecentChart:Link = new FunkinLink(); + linkRecentChart.text = chartPath; + linkRecentChart.onClick = function(_event) { + dialog.hideDialog(DialogButton.CANCEL); + state.stopWelcomeMusic(); + + // Load chart from file + ChartEditorImportExportHandler.loadFromFNFCPath(state, chartPath); + } + + if (!FileUtil.doesFileExist(chartPath)) + { + trace('Previously loaded chart file (${chartPath}) does not exist, disabling link...'); + linkRecentChart.disabled = true; + } + + splashRecentContainer.addComponent(linkRecentChart); + } + #else + var splashRecentContainer:Null = dialog.findComponent('splashRecentContainer', VBox); + if (splashRecentContainer == null) throw 'Could not locate splashRecentContainer in Welcome dialog'; + + var webLoadLabel:Label = new Label(); + webLoadLabel.text = 'Click the button below to load a chart file (.fnfc) from your computer.'; + + splashRecentContainer.add(webLoadLabel); + #end + // Create New Song "Easy/Normal/Hard" var linkCreateBasic:Null = dialog.findComponent('splashCreateFromSongBasic', Link); if (linkCreateBasic == null) throw 'Could not locate splashCreateFromSongBasic link in Welcome dialog'; @@ -180,6 +216,7 @@ class ChartEditorDialogHandler if (dialog == null) throw 'Could not locate Upload Chart dialog'; dialog.onDialogClosed = function(_event) { + state.isHaxeUIDialogOpen = false; if (_event.button == DialogButton.APPLY) { // Simply let the dialog close. @@ -194,6 +231,7 @@ class ChartEditorDialogHandler var buttonCancel:Null