From 73cf6b9fd2ec287be794ddeeb1c09587db9ae32f Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 4 Mar 2024 16:37:42 -0500 Subject: [PATCH] Rewrite save data to fix scripted story levels. Add a "pre-transition death delay" --- assets | 2 +- source/funkin/PlayerSettings.hx | 12 +- source/funkin/Preferences.hx | 28 +- source/funkin/api/newgrounds/NGUtil.hx | 12 +- source/funkin/api/newgrounds/NGio.hx | 12 +- source/funkin/modding/PolymodHandler.hx | 4 +- source/funkin/play/PlayState.hx | 53 ++- source/funkin/play/character/BaseCharacter.hx | 5 + source/funkin/play/character/CharacterData.hx | 6 + source/funkin/save/Save.hx | 349 ++++++++++-------- .../funkin/save/migrator/SaveDataMigrator.hx | 10 +- .../ui/debug/charting/ChartEditorState.hx | 8 +- source/funkin/ui/freeplay/FreeplayState.hx | 4 +- source/funkin/ui/story/StoryMenuState.hx | 2 +- 14 files changed, 298 insertions(+), 209 deletions(-) diff --git a/assets b/assets index 2d694cdfd..8b8086ac0 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 2d694cdfd90b9cc516b3e41a552212dd9e6d037b +Subproject commit 8b8086ac0ff072e23996828f19a05f064dafe5cf diff --git a/source/funkin/PlayerSettings.hx b/source/funkin/PlayerSettings.hx index 2e3e0e425..5a9351bba 100644 --- a/source/funkin/PlayerSettings.hx +++ b/source/funkin/PlayerSettings.hx @@ -84,9 +84,9 @@ class PlayerSettings function addKeyboard():Void { var useDefault = true; - if (Save.get().hasControls(id, Keys)) + if (Save.instance.hasControls(id, Keys)) { - var keyControlData = Save.get().getControls(id, Keys); + var keyControlData = Save.instance.getControls(id, Keys); trace("keyControlData: " + haxe.Json.stringify(keyControlData)); useDefault = false; controls.fromSaveData(keyControlData, Keys); @@ -112,9 +112,9 @@ class PlayerSettings function addGamepad(gamepad:FlxGamepad) { var useDefault = true; - if (Save.get().hasControls(id, Gamepad(gamepad.id))) + if (Save.instance.hasControls(id, Gamepad(gamepad.id))) { - var padControlData = Save.get().getControls(id, Gamepad(gamepad.id)); + var padControlData = Save.instance.getControls(id, Gamepad(gamepad.id)); trace("padControlData: " + haxe.Json.stringify(padControlData)); useDefault = false; controls.addGamepadWithSaveData(gamepad.id, padControlData); @@ -141,7 +141,7 @@ class PlayerSettings if (keyData != null) { trace("saving key data: " + haxe.Json.stringify(keyData)); - Save.get().setControls(id, Keys, keyData); + Save.instance.setControls(id, Keys, keyData); } if (controls.gamepadsAdded.length > 0) @@ -150,7 +150,7 @@ class PlayerSettings if (padData != null) { trace("saving pad data: " + haxe.Json.stringify(padData)); - Save.get().setControls(id, Gamepad(controls.gamepadsAdded[0]), padData); + Save.instance.setControls(id, Gamepad(controls.gamepadsAdded[0]), padData); } } } diff --git a/source/funkin/Preferences.hx b/source/funkin/Preferences.hx index 039a4c285..60c7a996a 100644 --- a/source/funkin/Preferences.hx +++ b/source/funkin/Preferences.hx @@ -15,12 +15,12 @@ class Preferences static function get_naughtyness():Bool { - return Save.get().options.naughtyness; + return Save.instance.options.naughtyness; } static function set_naughtyness(value:Bool):Bool { - var save = Save.get(); + var save = Save.instance; save.options.naughtyness = value; save.flush(); return value; @@ -34,12 +34,12 @@ class Preferences static function get_downscroll():Bool { - return Save.get().options.downscroll; + return Save.instance.options.downscroll; } static function set_downscroll(value:Bool):Bool { - var save = Save.get(); + var save = Save.instance; save.options.downscroll = value; save.flush(); return value; @@ -53,12 +53,12 @@ class Preferences static function get_flashingLights():Bool { - return Save.get().options.flashingLights; + return Save.instance.options.flashingLights; } static function set_flashingLights(value:Bool):Bool { - var save = Save.get(); + var save = Save.instance; save.options.flashingLights = value; save.flush(); return value; @@ -72,12 +72,12 @@ class Preferences static function get_zoomCamera():Bool { - return Save.get().options.zoomCamera; + return Save.instance.options.zoomCamera; } static function set_zoomCamera(value:Bool):Bool { - var save = Save.get(); + var save = Save.instance; save.options.zoomCamera = value; save.flush(); return value; @@ -91,17 +91,17 @@ class Preferences static function get_debugDisplay():Bool { - return Save.get().options.debugDisplay; + return Save.instance.options.debugDisplay; } static function set_debugDisplay(value:Bool):Bool { - if (value != Save.get().options.debugDisplay) + if (value != Save.instance.options.debugDisplay) { toggleDebugDisplay(value); } - var save = Save.get(); + var save = Save.instance; save.options.debugDisplay = value; save.flush(); return value; @@ -115,14 +115,14 @@ class Preferences static function get_autoPause():Bool { - return Save.get().options.autoPause; + return Save.instance.options.autoPause; } static function set_autoPause(value:Bool):Bool { - if (value != Save.get().options.autoPause) FlxG.autoPause = value; + if (value != Save.instance.options.autoPause) FlxG.autoPause = value; - var save = Save.get(); + var save = Save.instance; save.options.autoPause = value; save.flush(); return value; diff --git a/source/funkin/api/newgrounds/NGUtil.hx b/source/funkin/api/newgrounds/NGUtil.hx index c8289fc46..e9902a798 100644 --- a/source/funkin/api/newgrounds/NGUtil.hx +++ b/source/funkin/api/newgrounds/NGUtil.hx @@ -86,10 +86,10 @@ class NGUtil #end var onSessionFail:Error->Void = null; - if (sessionId == null && Save.get().ngSessionId != null) + if (sessionId == null && Save.instance.ngSessionId != null) { trace("using stored session id"); - sessionId = Save.get().ngSessionId; + sessionId = Save.instance.ngSessionId; onSessionFail = function(error) savedSessionFailed = true; } #end @@ -159,8 +159,8 @@ class NGUtil static function onNGLogin():Void { trace('logged in! user:${NG.core.user.name}'); - Save.get().ngSessionId = NG.core.sessionId; - Save.get().flush(); + Save.instance.ngSessionId = NG.core.sessionId; + Save.instance.flush(); // Load medals then call onNGMedalFetch() NG.core.requestMedals(onNGMedalFetch); @@ -174,8 +174,8 @@ class NGUtil { NG.core.logOut(); - Save.get().ngSessionId = null; - Save.get().flush(); + Save.instance.ngSessionId = null; + Save.instance.flush(); } // --- MEDALS diff --git a/source/funkin/api/newgrounds/NGio.hx b/source/funkin/api/newgrounds/NGio.hx index e505bdedf..c1f8ad3ba 100644 --- a/source/funkin/api/newgrounds/NGio.hx +++ b/source/funkin/api/newgrounds/NGio.hx @@ -86,10 +86,10 @@ class NGio #end var onSessionFail:Error->Void = null; - if (sessionId == null && Save.get().ngSessionId != null) + if (sessionId == null && Save.instance.ngSessionId != null) { trace("using stored session id"); - sessionId = Save.get().ngSessionId; + sessionId = Save.instance.ngSessionId; onSessionFail = function(error) savedSessionFailed = true; } #end @@ -159,8 +159,8 @@ class NGio static function onNGLogin():Void { trace('logged in! user:${NG.core.user.name}'); - Save.get().ngSessionId = NG.core.sessionId; - Save.get().flush(); + Save.instance.ngSessionId = NG.core.sessionId; + Save.instance.flush(); // Load medals then call onNGMedalFetch() NG.core.requestMedals(onNGMedalFetch); @@ -174,8 +174,8 @@ class NGio { NG.core.logOut(); - Save.get().ngSessionId = null; - Save.get().flush(); + Save.instance.ngSessionId = null; + Save.instance.flush(); } // --- MEDALS diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index f1e82aee9..889f63073 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -61,7 +61,7 @@ class PolymodHandler createModRoot(); trace("Initializing Polymod (using configured mods)..."); - loadModsById(Save.get().enabledModIds); + loadModsById(Save.instance.enabledModIds); } /** @@ -236,7 +236,7 @@ class PolymodHandler public static function getEnabledMods():Array { - var modIds = Save.get().enabledModIds; + var modIds = Save.instance.enabledModIds; var modMetadata = getAllMods(); var enabledMods = []; for (item in modMetadata) diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 5cb2e20f3..5421f1d2d 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -282,6 +282,12 @@ class PlayState extends MusicBeatSubState */ public var isPracticeMode:Bool = false; + /** + * Whether the player has dropped below zero health, + * and we are just waiting for an animation to play out before transitioning. + */ + public var isPlayerDying:Bool = false; + /** * In Minimal Mode, the stage and characters are not loaded and a standard background is used. */ @@ -785,6 +791,7 @@ class PlayState extends MusicBeatSubState persistentDraw = true; startingSong = true; + isPlayerDying = false; inputSpitter = []; @@ -953,7 +960,7 @@ class PlayState extends MusicBeatSubState } #end - if (health <= Constants.HEALTH_MIN && !isPracticeMode) + if (health <= Constants.HEALTH_MIN && !isPracticeMode && !isPlayerDying) { vocals.pause(); FlxG.sound.music.pause(); @@ -979,20 +986,30 @@ class PlayState extends MusicBeatSubState } #end - var gameOverSubState = new GameOverSubState( - { - isChartingMode: isChartingMode, - transparent: persistentDraw + isPlayerDying = true; + + var deathPreTransitionDelay = currentStage?.getBoyfriend()?.getDeathPreTransitionDelay() ?? 0.0; + if (deathPreTransitionDelay > 0) + { + new FlxTimer().start(deathPreTransitionDelay, function(_) { + moveToGameOver(); }); - FlxTransitionableSubState.skipNextTransIn = true; - FlxTransitionableSubState.skipNextTransOut = true; - openSubState(gameOverSubState); + } + else + { + // Transition immediately. + moveToGameOver(); + } #if discord_rpc // Game Over doesn't get his own variable because it's only used here DiscordClient.changePresence('Game Over - ' + detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC); #end } + else if (isPlayerDying) + { + // Wait up. + } } processSongEvents(); @@ -1008,6 +1025,18 @@ class PlayState extends MusicBeatSubState justUnpaused = false; } + function moveToGameOver():Void + { + var gameOverSubState = new GameOverSubState( + { + isChartingMode: isChartingMode, + transparent: persistentDraw + }); + FlxTransitionableSubState.skipNextTransIn = true; + FlxTransitionableSubState.skipNextTransOut = true; + openSubState(gameOverSubState); + } + function processSongEvents():Void { // Query and activate song events. @@ -2592,9 +2621,9 @@ class PlayState extends MusicBeatSubState accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, }; - if (Save.get().isSongHighScore(currentSong.id, currentDifficulty, data)) + if (Save.instance.isSongHighScore(currentSong.id, currentDifficulty, data)) { - Save.get().setSongScore(currentSong.id, currentDifficulty, data); + Save.instance.setSongScore(currentSong.id, currentDifficulty, data); #if newgrounds NGio.postScore(score, currentSong.id); #end @@ -2642,9 +2671,9 @@ class PlayState extends MusicBeatSubState accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, }; - if (Save.get().isLevelHighScore(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignDifficulty, data)) + if (Save.instance.isLevelHighScore(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignDifficulty, data)) { - Save.get().setLevelScore(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignDifficulty, data); + Save.instance.setLevelScore(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignDifficulty, data); #if newgrounds NGio.postScore(score, 'Level ${PlayStatePlaylist.campaignId}'); #end diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index bfba3715a..cf5311bdc 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -198,6 +198,11 @@ class BaseCharacter extends Bopper return _data.death?.cameraZoom ?? 1.0; } + public function getDeathPreTransitionDelay():Float + { + return _data.death?.preTransitionDelay ?? 0.0; + } + /** * Gets the value of flipX from the character data. * `!getFlipX()` is the direction Boyfriend should face. diff --git a/source/funkin/play/character/CharacterData.hx b/source/funkin/play/character/CharacterData.hx index 23710274c..56d7b7793 100644 --- a/source/funkin/play/character/CharacterData.hx +++ b/source/funkin/play/character/CharacterData.hx @@ -751,4 +751,10 @@ typedef DeathData = * @default 1.0 */ var ?cameraZoom:Float; + + /** + * Impose a delay between when the character reaches `0` health and when the death animation plays. + * @default 0.0 + */ + var ?preTransitionDelay:Float; } diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 6246dcb58..73ba8efa0 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -11,8 +11,7 @@ import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme; import thx.semver.Version; @:nullSafety -@:forward(volume, mute) -abstract Save(RawSaveData) +class Save { // Version 2.0.2 adds attributes to `optionsChartEditor`, that should return default values if they are null. public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.2"; @@ -25,6 +24,20 @@ abstract Save(RawSaveData) static final SAVE_PATH_LEGACY:String = 'ninjamuffin99'; static final SAVE_NAME_LEGACY:String = 'funkin'; + public static var instance(get, never):Save; + static var _instance:Null = null; + + static function get_instance():Save + { + if (_instance == null) + { + _instance = new Save(FlxG.save.data); + } + return _instance; + } + + var data:RawSaveData; + public static function load():Void { trace("[SAVE] Loading save..."); @@ -33,84 +46,85 @@ abstract Save(RawSaveData) loadFromSlot(1); } - public static function get():Save - { - return FlxG.save.data; - } - /** * Constructing a new Save will load the default values. */ - public function new() + public function new(data:RawSaveData) { - this = - { - version: Save.SAVE_DATA_VERSION, + this.data = data; - volume: 1.0, - mute: false, + if (this.data == null) data = Save.getDefault(); + } - api: - { - newgrounds: - { - sessionId: null, - } - }, - scores: - { - // No saved scores. - levels: [], - songs: [], - }, - options: - { - // Reasonable defaults. - naughtyness: true, - downscroll: false, - flashingLights: true, - zoomCamera: true, - debugDisplay: false, - autoPause: true, + public static function getDefault():RawSaveData + { + return { + version: Save.SAVE_DATA_VERSION, - controls: - { - // Leave controls blank so defaults are loaded. - p1: - { - keyboard: {}, - gamepad: {}, - }, - p2: - { - keyboard: {}, - gamepad: {}, - }, - }, - }, + volume: 1.0, + mute: false, - mods: - { - // No mods enabled. - enabledMods: [], - modOptions: [], - }, + api: + { + newgrounds: + { + sessionId: null, + } + }, + scores: + { + // No saved scores. + levels: [], + songs: [], + }, + options: + { + // Reasonable defaults. + naughtyness: true, + downscroll: false, + flashingLights: true, + zoomCamera: true, + debugDisplay: false, + autoPause: true, - optionsChartEditor: - { - // Reasonable defaults. - previousFiles: [], - noteQuant: 3, - chartEditorLiveInputStyle: ChartEditorLiveInputStyle.None, - theme: ChartEditorTheme.Light, - playtestStartTime: false, - downscroll: false, - metronomeVolume: 1.0, - hitsoundVolumePlayer: 1.0, - hitsoundVolumeOpponent: 1.0, - themeMusic: true - }, - }; + controls: + { + // Leave controls blank so defaults are loaded. + p1: + { + keyboard: {}, + gamepad: {}, + }, + p2: + { + keyboard: {}, + gamepad: {}, + }, + }, + }, + + mods: + { + // No mods enabled. + enabledMods: [], + modOptions: [], + }, + + optionsChartEditor: + { + // Reasonable defaults. + previousFiles: [], + noteQuant: 3, + chartEditorLiveInputStyle: ChartEditorLiveInputStyle.None, + theme: ChartEditorTheme.Light, + playtestStartTime: false, + downscroll: false, + metronomeVolume: 1.0, + hitsoundVolumePlayer: 1.0, + hitsoundVolumeOpponent: 1.0, + themeMusic: true + }, + }; } /** @@ -120,7 +134,7 @@ abstract Save(RawSaveData) function get_options():SaveDataOptions { - return this.options; + return data.options; } /** @@ -130,7 +144,7 @@ abstract Save(RawSaveData) function get_modOptions():Map { - return this.mods.modOptions; + return data.mods.modOptions; } /** @@ -140,232 +154,232 @@ abstract Save(RawSaveData) function get_ngSessionId():Null { - return this.api.newgrounds.sessionId; + return data.api.newgrounds.sessionId; } function set_ngSessionId(value:Null):Null { - this.api.newgrounds.sessionId = value; + data.api.newgrounds.sessionId = value; flush(); - return this.api.newgrounds.sessionId; + return data.api.newgrounds.sessionId; } public var enabledModIds(get, set):Array; function get_enabledModIds():Array { - return this.mods.enabledMods; + return data.mods.enabledMods; } function set_enabledModIds(value:Array):Array { - this.mods.enabledMods = value; + data.mods.enabledMods = value; flush(); - return this.mods.enabledMods; + return data.mods.enabledMods; } public var chartEditorPreviousFiles(get, set):Array; function get_chartEditorPreviousFiles():Array { - if (this.optionsChartEditor.previousFiles == null) this.optionsChartEditor.previousFiles = []; + if (data.optionsChartEditor.previousFiles == null) data.optionsChartEditor.previousFiles = []; - return this.optionsChartEditor.previousFiles; + return data.optionsChartEditor.previousFiles; } function set_chartEditorPreviousFiles(value:Array):Array { // Set and apply. - this.optionsChartEditor.previousFiles = value; + data.optionsChartEditor.previousFiles = value; flush(); - return this.optionsChartEditor.previousFiles; + return data.optionsChartEditor.previousFiles; } public var chartEditorHasBackup(get, set):Bool; function get_chartEditorHasBackup():Bool { - if (this.optionsChartEditor.hasBackup == null) this.optionsChartEditor.hasBackup = false; + if (data.optionsChartEditor.hasBackup == null) data.optionsChartEditor.hasBackup = false; - return this.optionsChartEditor.hasBackup; + return data.optionsChartEditor.hasBackup; } function set_chartEditorHasBackup(value:Bool):Bool { // Set and apply. - this.optionsChartEditor.hasBackup = value; + data.optionsChartEditor.hasBackup = value; flush(); - return this.optionsChartEditor.hasBackup; + return data.optionsChartEditor.hasBackup; } public var chartEditorNoteQuant(get, set):Int; function get_chartEditorNoteQuant():Int { - if (this.optionsChartEditor.noteQuant == null) this.optionsChartEditor.noteQuant = 3; + if (data.optionsChartEditor.noteQuant == null) data.optionsChartEditor.noteQuant = 3; - return this.optionsChartEditor.noteQuant; + return data.optionsChartEditor.noteQuant; } function set_chartEditorNoteQuant(value:Int):Int { // Set and apply. - this.optionsChartEditor.noteQuant = value; + data.optionsChartEditor.noteQuant = value; flush(); - return this.optionsChartEditor.noteQuant; + return data.optionsChartEditor.noteQuant; } public var chartEditorLiveInputStyle(get, set):ChartEditorLiveInputStyle; function get_chartEditorLiveInputStyle():ChartEditorLiveInputStyle { - if (this.optionsChartEditor.chartEditorLiveInputStyle == null) this.optionsChartEditor.chartEditorLiveInputStyle = ChartEditorLiveInputStyle.None; + if (data.optionsChartEditor.chartEditorLiveInputStyle == null) data.optionsChartEditor.chartEditorLiveInputStyle = ChartEditorLiveInputStyle.None; - return this.optionsChartEditor.chartEditorLiveInputStyle; + return data.optionsChartEditor.chartEditorLiveInputStyle; } function set_chartEditorLiveInputStyle(value:ChartEditorLiveInputStyle):ChartEditorLiveInputStyle { // Set and apply. - this.optionsChartEditor.chartEditorLiveInputStyle = value; + data.optionsChartEditor.chartEditorLiveInputStyle = value; flush(); - return this.optionsChartEditor.chartEditorLiveInputStyle; + return data.optionsChartEditor.chartEditorLiveInputStyle; } public var chartEditorDownscroll(get, set):Bool; function get_chartEditorDownscroll():Bool { - if (this.optionsChartEditor.downscroll == null) this.optionsChartEditor.downscroll = false; + if (data.optionsChartEditor.downscroll == null) data.optionsChartEditor.downscroll = false; - return this.optionsChartEditor.downscroll; + return data.optionsChartEditor.downscroll; } function set_chartEditorDownscroll(value:Bool):Bool { // Set and apply. - this.optionsChartEditor.downscroll = value; + data.optionsChartEditor.downscroll = value; flush(); - return this.optionsChartEditor.downscroll; + return data.optionsChartEditor.downscroll; } public var chartEditorPlaytestStartTime(get, set):Bool; function get_chartEditorPlaytestStartTime():Bool { - if (this.optionsChartEditor.playtestStartTime == null) this.optionsChartEditor.playtestStartTime = false; + if (data.optionsChartEditor.playtestStartTime == null) data.optionsChartEditor.playtestStartTime = false; - return this.optionsChartEditor.playtestStartTime; + return data.optionsChartEditor.playtestStartTime; } function set_chartEditorPlaytestStartTime(value:Bool):Bool { // Set and apply. - this.optionsChartEditor.playtestStartTime = value; + data.optionsChartEditor.playtestStartTime = value; flush(); - return this.optionsChartEditor.playtestStartTime; + return data.optionsChartEditor.playtestStartTime; } public var chartEditorTheme(get, set):ChartEditorTheme; function get_chartEditorTheme():ChartEditorTheme { - if (this.optionsChartEditor.theme == null) this.optionsChartEditor.theme = ChartEditorTheme.Light; + if (data.optionsChartEditor.theme == null) data.optionsChartEditor.theme = ChartEditorTheme.Light; - return this.optionsChartEditor.theme; + return data.optionsChartEditor.theme; } function set_chartEditorTheme(value:ChartEditorTheme):ChartEditorTheme { // Set and apply. - this.optionsChartEditor.theme = value; + data.optionsChartEditor.theme = value; flush(); - return this.optionsChartEditor.theme; + return data.optionsChartEditor.theme; } public var chartEditorMetronomeVolume(get, set):Float; function get_chartEditorMetronomeVolume():Float { - if (this.optionsChartEditor.metronomeVolume == null) this.optionsChartEditor.metronomeVolume = 1.0; + if (data.optionsChartEditor.metronomeVolume == null) data.optionsChartEditor.metronomeVolume = 1.0; - return this.optionsChartEditor.metronomeVolume; + return data.optionsChartEditor.metronomeVolume; } function set_chartEditorMetronomeVolume(value:Float):Float { // Set and apply. - this.optionsChartEditor.metronomeVolume = value; + data.optionsChartEditor.metronomeVolume = value; flush(); - return this.optionsChartEditor.metronomeVolume; + return data.optionsChartEditor.metronomeVolume; } public var chartEditorHitsoundVolumePlayer(get, set):Float; function get_chartEditorHitsoundVolumePlayer():Float { - if (this.optionsChartEditor.hitsoundVolumePlayer == null) this.optionsChartEditor.hitsoundVolumePlayer = 1.0; + if (data.optionsChartEditor.hitsoundVolumePlayer == null) data.optionsChartEditor.hitsoundVolumePlayer = 1.0; - return this.optionsChartEditor.hitsoundVolumePlayer; + return data.optionsChartEditor.hitsoundVolumePlayer; } function set_chartEditorHitsoundVolumePlayer(value:Float):Float { // Set and apply. - this.optionsChartEditor.hitsoundVolumePlayer = value; + data.optionsChartEditor.hitsoundVolumePlayer = value; flush(); - return this.optionsChartEditor.hitsoundVolumePlayer; + return data.optionsChartEditor.hitsoundVolumePlayer; } public var chartEditorHitsoundVolumeOpponent(get, set):Float; function get_chartEditorHitsoundVolumeOpponent():Float { - if (this.optionsChartEditor.hitsoundVolumeOpponent == null) this.optionsChartEditor.hitsoundVolumeOpponent = 1.0; + if (data.optionsChartEditor.hitsoundVolumeOpponent == null) data.optionsChartEditor.hitsoundVolumeOpponent = 1.0; - return this.optionsChartEditor.hitsoundVolumeOpponent; + return data.optionsChartEditor.hitsoundVolumeOpponent; } function set_chartEditorHitsoundVolumeOpponent(value:Float):Float { // Set and apply. - this.optionsChartEditor.hitsoundVolumeOpponent = value; + data.optionsChartEditor.hitsoundVolumeOpponent = value; flush(); - return this.optionsChartEditor.hitsoundVolumeOpponent; + return data.optionsChartEditor.hitsoundVolumeOpponent; } public var chartEditorThemeMusic(get, set):Bool; function get_chartEditorThemeMusic():Bool { - if (this.optionsChartEditor.themeMusic == null) this.optionsChartEditor.themeMusic = true; + if (data.optionsChartEditor.themeMusic == null) data.optionsChartEditor.themeMusic = true; - return this.optionsChartEditor.themeMusic; + return data.optionsChartEditor.themeMusic; } function set_chartEditorThemeMusic(value:Bool):Bool { // Set and apply. - this.optionsChartEditor.themeMusic = value; + data.optionsChartEditor.themeMusic = value; flush(); - return this.optionsChartEditor.themeMusic; + return data.optionsChartEditor.themeMusic; } public var chartEditorPlaybackSpeed(get, set):Float; function get_chartEditorPlaybackSpeed():Float { - if (this.optionsChartEditor.playbackSpeed == null) this.optionsChartEditor.playbackSpeed = 1.0; + if (data.optionsChartEditor.playbackSpeed == null) data.optionsChartEditor.playbackSpeed = 1.0; - return this.optionsChartEditor.playbackSpeed; + return data.optionsChartEditor.playbackSpeed; } function set_chartEditorPlaybackSpeed(value:Float):Float { // Set and apply. - this.optionsChartEditor.playbackSpeed = value; + data.optionsChartEditor.playbackSpeed = value; flush(); - return this.optionsChartEditor.playbackSpeed; + return data.optionsChartEditor.playbackSpeed; } /** @@ -377,11 +391,11 @@ abstract Save(RawSaveData) */ public function getLevelScore(levelId:String, difficultyId:String = 'normal'):Null { - var level = this.scores.levels.get(levelId); + var level = data.scores.levels.get(levelId); if (level == null) { level = []; - this.scores.levels.set(levelId, level); + data.scores.levels.set(levelId, level); } return level.get(difficultyId); @@ -392,11 +406,11 @@ abstract Save(RawSaveData) */ public function setLevelScore(levelId:String, difficultyId:String, score:SaveScoreData):Void { - var level = this.scores.levels.get(levelId); + var level = data.scores.levels.get(levelId); if (level == null) { level = []; - this.scores.levels.set(levelId, level); + data.scores.levels.set(levelId, level); } level.set(difficultyId, score); @@ -405,11 +419,11 @@ abstract Save(RawSaveData) public function isLevelHighScore(levelId:String, difficultyId:String = 'normal', score:SaveScoreData):Bool { - var level = this.scores.levels.get(levelId); + var level = data.scores.levels.get(levelId); if (level == null) { level = []; - this.scores.levels.set(levelId, level); + data.scores.levels.set(levelId, level); } var currentScore = level.get(difficultyId); @@ -448,11 +462,11 @@ abstract Save(RawSaveData) */ public function getSongScore(songId:String, difficultyId:String = 'normal'):Null { - var song = this.scores.songs.get(songId); + var song = data.scores.songs.get(songId); if (song == null) { song = []; - this.scores.songs.set(songId, song); + data.scores.songs.set(songId, song); } return song.get(difficultyId); } @@ -462,11 +476,11 @@ abstract Save(RawSaveData) */ public function setSongScore(songId:String, difficultyId:String, score:SaveScoreData):Void { - var song = this.scores.songs.get(songId); + var song = data.scores.songs.get(songId); if (song == null) { song = []; - this.scores.songs.set(songId, song); + data.scores.songs.set(songId, song); } song.set(difficultyId, score); @@ -482,11 +496,11 @@ abstract Save(RawSaveData) */ public function isSongHighScore(songId:String, difficultyId:String = 'normal', score:SaveScoreData):Bool { - var song = this.scores.songs.get(songId); + var song = data.scores.songs.get(songId); if (song == null) { song = []; - this.scores.songs.set(songId, song); + data.scores.songs.set(songId, song); } var currentScore = song.get(difficultyId); @@ -527,9 +541,9 @@ abstract Save(RawSaveData) switch (inputType) { case Keys: - return (playerId == 0) ? this.options.controls.p1.keyboard : this.options.controls.p2.keyboard; + return (playerId == 0) ? data.options.controls.p1.keyboard : data.options.controls.p2.keyboard; case Gamepad(_): - return (playerId == 0) ? this.options.controls.p1.gamepad : this.options.controls.p2.gamepad; + return (playerId == 0) ? data.options.controls.p1.gamepad : data.options.controls.p2.gamepad; } } @@ -547,20 +561,20 @@ abstract Save(RawSaveData) case Keys: if (playerId == 0) { - this.options.controls.p1.keyboard = controls; + data.options.controls.p1.keyboard = controls; } else { - this.options.controls.p2.keyboard = controls; + data.options.controls.p2.keyboard = controls; } case Gamepad(_): if (playerId == 0) { - this.options.controls.p1.gamepad = controls; + data.options.controls.p1.gamepad = controls; } else { - this.options.controls.p2.gamepad = controls; + data.options.controls.p2.gamepad = controls; } } @@ -581,6 +595,36 @@ abstract Save(RawSaveData) } } + /** + * The user's current volume setting. + */ + public var volume(get, set):Float; + + function get_volume():Float + { + return data.volume; + } + + function set_volume(value:Float):Float + { + return data.volume = value; + } + + /** + * Whether the user's volume is currently muted. + */ + public var mute(get, set):Bool; + + function get_mute():Bool + { + return data.mute; + } + + function set_mute(value:Bool):Bool + { + return data.mute = value; + } + /** * Call this to make sure the save data is written to disk. */ @@ -606,17 +650,22 @@ abstract Save(RawSaveData) if (legacySaveData != null) { trace('[SAVE] Found legacy save data, converting...'); - FlxG.save.mergeData(SaveDataMigrator.migrateFromLegacy(legacySaveData)); + var gameSave = SaveDataMigrator.migrate(legacySaveData); + @:privateAccess + FlxG.save.mergeData(gameSave.data); + } + else + { + trace('[SAVE] No legacy save data found.'); } } else { trace('[SAVE] Loaded save data.'); - FlxG.save.mergeData(SaveDataMigrator.migrate(FlxG.save.data)); + @:privateAccess + var gameSave = SaveDataMigrator.migrate(FlxG.save.data); + FlxG.save.mergeData(gameSave.data); } - - trace('[SAVE] Done loading save data.'); - trace(FlxG.save.data); } static function fetchLegacySaveData():Null diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx index f995660f7..00637d52a 100644 --- a/source/funkin/save/migrator/SaveDataMigrator.hx +++ b/source/funkin/save/migrator/SaveDataMigrator.hx @@ -19,21 +19,21 @@ class SaveDataMigrator { trace('[SAVE] No version found in save data! Returning blank data.'); trace(inputData); - return new Save(); + return new Save(Save.getDefault()); } else { if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE)) { - // Simply cast the structured data. - var save:Save = inputData; + // Simply import the structured data. + var save:Save = new Save(inputData); return save; } else { trace('[SAVE] Invalid save data version! Returning blank data.'); trace(inputData); - return new Save(); + return new Save(Save.getDefault()); } } } @@ -45,7 +45,7 @@ class SaveDataMigrator { var inputSaveData:RawSaveData_v1_0_0 = cast inputData; - var result:Save = new Save(); + var result:Save = new Save(Save.getDefault()); result.volume = inputSaveData.volume; result.mute = inputSaveData.mute; diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index a662ce2bd..78e73bf27 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -920,12 +920,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function get_shouldShowBackupAvailableDialog():Bool { - return Save.get().chartEditorHasBackup; + return Save.instance.chartEditorHasBackup; } function set_shouldShowBackupAvailableDialog(value:Bool):Bool { - return Save.get().chartEditorHasBackup = value; + return Save.instance.chartEditorHasBackup = value; } /** @@ -2163,7 +2163,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState public function loadPreferences():Void { - var save:Save = Save.get(); + var save:Save = Save.instance; if (previousWorkingFilePaths[0] == null) { @@ -2191,7 +2191,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState public function writePreferences(hasBackup:Bool):Void { - var save:Save = Save.get(); + var save:Save = Save.instance; // Can't use filter() because of null safety checking! var filteredWorkingFilePaths:Array = []; diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index a1799481e..50f85571b 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1001,7 +1001,7 @@ class FreeplayState extends MusicBeatSubState var daSong = songs[curSelected]; if (daSong != null) { - var songScore:SaveScoreData = Save.get().getSongScore(songs[curSelected].songId, currentDifficulty); + var songScore:SaveScoreData = Save.instance.getSongScore(songs[curSelected].songId, currentDifficulty); intendedScore = songScore?.score ?? 0; intendedCompletion = songScore?.accuracy ?? 0.0; rememberedDifficulty = currentDifficulty; @@ -1189,7 +1189,7 @@ class FreeplayState extends MusicBeatSubState var daSongCapsule = grpCapsules.members[curSelected]; if (daSongCapsule.songData != null) { - var songScore:SaveScoreData = Save.get().getSongScore(daSongCapsule.songData.songId, currentDifficulty); + var songScore:SaveScoreData = Save.instance.getSongScore(daSongCapsule.songData.songId, currentDifficulty); intendedScore = songScore?.score ?? 0; intendedCompletion = songScore?.accuracy ?? 0.0; diffIdsCurrent = daSongCapsule.songData.songDifficulties; diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index 9012f3672..ba1d2ed21 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -649,7 +649,7 @@ class StoryMenuState extends MusicBeatState tracklistText.screenCenter(X); tracklistText.x -= FlxG.width * 0.35; - var levelScore:Null = Save.get().getLevelScore(currentLevelId, currentDifficultyId); + var levelScore:Null = Save.instance.getLevelScore(currentLevelId, currentDifficultyId); highScore = levelScore?.score ?? 0; // levelScore.accuracy }