1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2025-03-24 10:59:32 +00:00

Rewrite save data to fix scripted story levels. Add a "pre-transition death delay"

This commit is contained in:
EliteMasterEric 2024-03-04 16:37:42 -05:00
parent c36ea962dc
commit 73cf6b9fd2
14 changed files with 298 additions and 209 deletions

2
assets

@ -1 +1 @@
Subproject commit 2d694cdfd90b9cc516b3e41a552212dd9e6d037b Subproject commit 8b8086ac0ff072e23996828f19a05f064dafe5cf

View file

@ -84,9 +84,9 @@ class PlayerSettings
function addKeyboard():Void function addKeyboard():Void
{ {
var useDefault = true; 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)); trace("keyControlData: " + haxe.Json.stringify(keyControlData));
useDefault = false; useDefault = false;
controls.fromSaveData(keyControlData, Keys); controls.fromSaveData(keyControlData, Keys);
@ -112,9 +112,9 @@ class PlayerSettings
function addGamepad(gamepad:FlxGamepad) function addGamepad(gamepad:FlxGamepad)
{ {
var useDefault = true; 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)); trace("padControlData: " + haxe.Json.stringify(padControlData));
useDefault = false; useDefault = false;
controls.addGamepadWithSaveData(gamepad.id, padControlData); controls.addGamepadWithSaveData(gamepad.id, padControlData);
@ -141,7 +141,7 @@ class PlayerSettings
if (keyData != null) if (keyData != null)
{ {
trace("saving key data: " + haxe.Json.stringify(keyData)); 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) if (controls.gamepadsAdded.length > 0)
@ -150,7 +150,7 @@ class PlayerSettings
if (padData != null) if (padData != null)
{ {
trace("saving pad data: " + haxe.Json.stringify(padData)); 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);
} }
} }
} }

View file

@ -15,12 +15,12 @@ class Preferences
static function get_naughtyness():Bool static function get_naughtyness():Bool
{ {
return Save.get().options.naughtyness; return Save.instance.options.naughtyness;
} }
static function set_naughtyness(value:Bool):Bool static function set_naughtyness(value:Bool):Bool
{ {
var save = Save.get(); var save = Save.instance;
save.options.naughtyness = value; save.options.naughtyness = value;
save.flush(); save.flush();
return value; return value;
@ -34,12 +34,12 @@ class Preferences
static function get_downscroll():Bool static function get_downscroll():Bool
{ {
return Save.get().options.downscroll; return Save.instance.options.downscroll;
} }
static function set_downscroll(value:Bool):Bool static function set_downscroll(value:Bool):Bool
{ {
var save = Save.get(); var save = Save.instance;
save.options.downscroll = value; save.options.downscroll = value;
save.flush(); save.flush();
return value; return value;
@ -53,12 +53,12 @@ class Preferences
static function get_flashingLights():Bool static function get_flashingLights():Bool
{ {
return Save.get().options.flashingLights; return Save.instance.options.flashingLights;
} }
static function set_flashingLights(value:Bool):Bool static function set_flashingLights(value:Bool):Bool
{ {
var save = Save.get(); var save = Save.instance;
save.options.flashingLights = value; save.options.flashingLights = value;
save.flush(); save.flush();
return value; return value;
@ -72,12 +72,12 @@ class Preferences
static function get_zoomCamera():Bool static function get_zoomCamera():Bool
{ {
return Save.get().options.zoomCamera; return Save.instance.options.zoomCamera;
} }
static function set_zoomCamera(value:Bool):Bool static function set_zoomCamera(value:Bool):Bool
{ {
var save = Save.get(); var save = Save.instance;
save.options.zoomCamera = value; save.options.zoomCamera = value;
save.flush(); save.flush();
return value; return value;
@ -91,17 +91,17 @@ class Preferences
static function get_debugDisplay():Bool static function get_debugDisplay():Bool
{ {
return Save.get().options.debugDisplay; return Save.instance.options.debugDisplay;
} }
static function set_debugDisplay(value:Bool):Bool static function set_debugDisplay(value:Bool):Bool
{ {
if (value != Save.get().options.debugDisplay) if (value != Save.instance.options.debugDisplay)
{ {
toggleDebugDisplay(value); toggleDebugDisplay(value);
} }
var save = Save.get(); var save = Save.instance;
save.options.debugDisplay = value; save.options.debugDisplay = value;
save.flush(); save.flush();
return value; return value;
@ -115,14 +115,14 @@ class Preferences
static function get_autoPause():Bool static function get_autoPause():Bool
{ {
return Save.get().options.autoPause; return Save.instance.options.autoPause;
} }
static function set_autoPause(value:Bool):Bool 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.options.autoPause = value;
save.flush(); save.flush();
return value; return value;

View file

@ -86,10 +86,10 @@ class NGUtil
#end #end
var onSessionFail:Error->Void = null; var onSessionFail:Error->Void = null;
if (sessionId == null && Save.get().ngSessionId != null) if (sessionId == null && Save.instance.ngSessionId != null)
{ {
trace("using stored session id"); trace("using stored session id");
sessionId = Save.get().ngSessionId; sessionId = Save.instance.ngSessionId;
onSessionFail = function(error) savedSessionFailed = true; onSessionFail = function(error) savedSessionFailed = true;
} }
#end #end
@ -159,8 +159,8 @@ class NGUtil
static function onNGLogin():Void static function onNGLogin():Void
{ {
trace('logged in! user:${NG.core.user.name}'); trace('logged in! user:${NG.core.user.name}');
Save.get().ngSessionId = NG.core.sessionId; Save.instance.ngSessionId = NG.core.sessionId;
Save.get().flush(); Save.instance.flush();
// Load medals then call onNGMedalFetch() // Load medals then call onNGMedalFetch()
NG.core.requestMedals(onNGMedalFetch); NG.core.requestMedals(onNGMedalFetch);
@ -174,8 +174,8 @@ class NGUtil
{ {
NG.core.logOut(); NG.core.logOut();
Save.get().ngSessionId = null; Save.instance.ngSessionId = null;
Save.get().flush(); Save.instance.flush();
} }
// --- MEDALS // --- MEDALS

View file

@ -86,10 +86,10 @@ class NGio
#end #end
var onSessionFail:Error->Void = null; var onSessionFail:Error->Void = null;
if (sessionId == null && Save.get().ngSessionId != null) if (sessionId == null && Save.instance.ngSessionId != null)
{ {
trace("using stored session id"); trace("using stored session id");
sessionId = Save.get().ngSessionId; sessionId = Save.instance.ngSessionId;
onSessionFail = function(error) savedSessionFailed = true; onSessionFail = function(error) savedSessionFailed = true;
} }
#end #end
@ -159,8 +159,8 @@ class NGio
static function onNGLogin():Void static function onNGLogin():Void
{ {
trace('logged in! user:${NG.core.user.name}'); trace('logged in! user:${NG.core.user.name}');
Save.get().ngSessionId = NG.core.sessionId; Save.instance.ngSessionId = NG.core.sessionId;
Save.get().flush(); Save.instance.flush();
// Load medals then call onNGMedalFetch() // Load medals then call onNGMedalFetch()
NG.core.requestMedals(onNGMedalFetch); NG.core.requestMedals(onNGMedalFetch);
@ -174,8 +174,8 @@ class NGio
{ {
NG.core.logOut(); NG.core.logOut();
Save.get().ngSessionId = null; Save.instance.ngSessionId = null;
Save.get().flush(); Save.instance.flush();
} }
// --- MEDALS // --- MEDALS

View file

@ -61,7 +61,7 @@ class PolymodHandler
createModRoot(); createModRoot();
trace("Initializing Polymod (using configured mods)..."); 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<ModMetadata> public static function getEnabledMods():Array<ModMetadata>
{ {
var modIds = Save.get().enabledModIds; var modIds = Save.instance.enabledModIds;
var modMetadata = getAllMods(); var modMetadata = getAllMods();
var enabledMods = []; var enabledMods = [];
for (item in modMetadata) for (item in modMetadata)

View file

@ -282,6 +282,12 @@ class PlayState extends MusicBeatSubState
*/ */
public var isPracticeMode:Bool = false; 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. * 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; persistentDraw = true;
startingSong = true; startingSong = true;
isPlayerDying = false;
inputSpitter = []; inputSpitter = [];
@ -953,7 +960,7 @@ class PlayState extends MusicBeatSubState
} }
#end #end
if (health <= Constants.HEALTH_MIN && !isPracticeMode) if (health <= Constants.HEALTH_MIN && !isPracticeMode && !isPlayerDying)
{ {
vocals.pause(); vocals.pause();
FlxG.sound.music.pause(); FlxG.sound.music.pause();
@ -979,20 +986,30 @@ class PlayState extends MusicBeatSubState
} }
#end #end
var gameOverSubState = new GameOverSubState( isPlayerDying = true;
{
isChartingMode: isChartingMode, var deathPreTransitionDelay = currentStage?.getBoyfriend()?.getDeathPreTransitionDelay() ?? 0.0;
transparent: persistentDraw if (deathPreTransitionDelay > 0)
{
new FlxTimer().start(deathPreTransitionDelay, function(_) {
moveToGameOver();
}); });
FlxTransitionableSubState.skipNextTransIn = true; }
FlxTransitionableSubState.skipNextTransOut = true; else
openSubState(gameOverSubState); {
// Transition immediately.
moveToGameOver();
}
#if discord_rpc #if discord_rpc
// Game Over doesn't get his own variable because it's only used here // Game Over doesn't get his own variable because it's only used here
DiscordClient.changePresence('Game Over - ' + detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC); DiscordClient.changePresence('Game Over - ' + detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
#end #end
} }
else if (isPlayerDying)
{
// Wait up.
}
} }
processSongEvents(); processSongEvents();
@ -1008,6 +1025,18 @@ class PlayState extends MusicBeatSubState
justUnpaused = false; justUnpaused = false;
} }
function moveToGameOver():Void
{
var gameOverSubState = new GameOverSubState(
{
isChartingMode: isChartingMode,
transparent: persistentDraw
});
FlxTransitionableSubState.skipNextTransIn = true;
FlxTransitionableSubState.skipNextTransOut = true;
openSubState(gameOverSubState);
}
function processSongEvents():Void function processSongEvents():Void
{ {
// Query and activate song events. // Query and activate song events.
@ -2592,9 +2621,9 @@ class PlayState extends MusicBeatSubState
accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, 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 #if newgrounds
NGio.postScore(score, currentSong.id); NGio.postScore(score, currentSong.id);
#end #end
@ -2642,9 +2671,9 @@ class PlayState extends MusicBeatSubState
accuracy: Highscore.tallies.totalNotesHit / Highscore.tallies.totalNotes, 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 #if newgrounds
NGio.postScore(score, 'Level ${PlayStatePlaylist.campaignId}'); NGio.postScore(score, 'Level ${PlayStatePlaylist.campaignId}');
#end #end

View file

@ -198,6 +198,11 @@ class BaseCharacter extends Bopper
return _data.death?.cameraZoom ?? 1.0; 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. * Gets the value of flipX from the character data.
* `!getFlipX()` is the direction Boyfriend should face. * `!getFlipX()` is the direction Boyfriend should face.

View file

@ -751,4 +751,10 @@ typedef DeathData =
* @default 1.0 * @default 1.0
*/ */
var ?cameraZoom:Float; 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;
} }

View file

@ -11,8 +11,7 @@ import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme;
import thx.semver.Version; import thx.semver.Version;
@:nullSafety @:nullSafety
@:forward(volume, mute) class Save
abstract Save(RawSaveData)
{ {
// Version 2.0.2 adds attributes to `optionsChartEditor`, that should return default values if they are null. // 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"; 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_PATH_LEGACY:String = 'ninjamuffin99';
static final SAVE_NAME_LEGACY:String = 'funkin'; static final SAVE_NAME_LEGACY:String = 'funkin';
public static var instance(get, never):Save;
static var _instance:Null<Save> = 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 public static function load():Void
{ {
trace("[SAVE] Loading save..."); trace("[SAVE] Loading save...");
@ -33,84 +46,85 @@ abstract Save(RawSaveData)
loadFromSlot(1); loadFromSlot(1);
} }
public static function get():Save
{
return FlxG.save.data;
}
/** /**
* Constructing a new Save will load the default values. * Constructing a new Save will load the default values.
*/ */
public function new() public function new(data:RawSaveData)
{ {
this = this.data = data;
{
version: Save.SAVE_DATA_VERSION,
volume: 1.0, if (this.data == null) data = Save.getDefault();
mute: false, }
api: public static function getDefault():RawSaveData
{ {
newgrounds: return {
{ version: Save.SAVE_DATA_VERSION,
sessionId: null,
}
},
scores:
{
// No saved scores.
levels: [],
songs: [],
},
options:
{
// Reasonable defaults.
naughtyness: true,
downscroll: false,
flashingLights: true,
zoomCamera: true,
debugDisplay: false,
autoPause: true,
controls: volume: 1.0,
{ mute: false,
// Leave controls blank so defaults are loaded.
p1:
{
keyboard: {},
gamepad: {},
},
p2:
{
keyboard: {},
gamepad: {},
},
},
},
mods: api:
{ {
// No mods enabled. newgrounds:
enabledMods: [], {
modOptions: [], sessionId: null,
}, }
},
scores:
{
// No saved scores.
levels: [],
songs: [],
},
options:
{
// Reasonable defaults.
naughtyness: true,
downscroll: false,
flashingLights: true,
zoomCamera: true,
debugDisplay: false,
autoPause: true,
optionsChartEditor: controls:
{ {
// Reasonable defaults. // Leave controls blank so defaults are loaded.
previousFiles: [], p1:
noteQuant: 3, {
chartEditorLiveInputStyle: ChartEditorLiveInputStyle.None, keyboard: {},
theme: ChartEditorTheme.Light, gamepad: {},
playtestStartTime: false, },
downscroll: false, p2:
metronomeVolume: 1.0, {
hitsoundVolumePlayer: 1.0, keyboard: {},
hitsoundVolumeOpponent: 1.0, gamepad: {},
themeMusic: true },
}, },
}; },
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 function get_options():SaveDataOptions
{ {
return this.options; return data.options;
} }
/** /**
@ -130,7 +144,7 @@ abstract Save(RawSaveData)
function get_modOptions():Map<String, Dynamic> function get_modOptions():Map<String, Dynamic>
{ {
return this.mods.modOptions; return data.mods.modOptions;
} }
/** /**
@ -140,232 +154,232 @@ abstract Save(RawSaveData)
function get_ngSessionId():Null<String> function get_ngSessionId():Null<String>
{ {
return this.api.newgrounds.sessionId; return data.api.newgrounds.sessionId;
} }
function set_ngSessionId(value:Null<String>):Null<String> function set_ngSessionId(value:Null<String>):Null<String>
{ {
this.api.newgrounds.sessionId = value; data.api.newgrounds.sessionId = value;
flush(); flush();
return this.api.newgrounds.sessionId; return data.api.newgrounds.sessionId;
} }
public var enabledModIds(get, set):Array<String>; public var enabledModIds(get, set):Array<String>;
function get_enabledModIds():Array<String> function get_enabledModIds():Array<String>
{ {
return this.mods.enabledMods; return data.mods.enabledMods;
} }
function set_enabledModIds(value:Array<String>):Array<String> function set_enabledModIds(value:Array<String>):Array<String>
{ {
this.mods.enabledMods = value; data.mods.enabledMods = value;
flush(); flush();
return this.mods.enabledMods; return data.mods.enabledMods;
} }
public var chartEditorPreviousFiles(get, set):Array<String>; public var chartEditorPreviousFiles(get, set):Array<String>;
function get_chartEditorPreviousFiles():Array<String> function get_chartEditorPreviousFiles():Array<String>
{ {
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<String>):Array<String> function set_chartEditorPreviousFiles(value:Array<String>):Array<String>
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.previousFiles = value; data.optionsChartEditor.previousFiles = value;
flush(); flush();
return this.optionsChartEditor.previousFiles; return data.optionsChartEditor.previousFiles;
} }
public var chartEditorHasBackup(get, set):Bool; public var chartEditorHasBackup(get, set):Bool;
function get_chartEditorHasBackup():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 function set_chartEditorHasBackup(value:Bool):Bool
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.hasBackup = value; data.optionsChartEditor.hasBackup = value;
flush(); flush();
return this.optionsChartEditor.hasBackup; return data.optionsChartEditor.hasBackup;
} }
public var chartEditorNoteQuant(get, set):Int; public var chartEditorNoteQuant(get, set):Int;
function get_chartEditorNoteQuant():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 function set_chartEditorNoteQuant(value:Int):Int
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.noteQuant = value; data.optionsChartEditor.noteQuant = value;
flush(); flush();
return this.optionsChartEditor.noteQuant; return data.optionsChartEditor.noteQuant;
} }
public var chartEditorLiveInputStyle(get, set):ChartEditorLiveInputStyle; public var chartEditorLiveInputStyle(get, set):ChartEditorLiveInputStyle;
function get_chartEditorLiveInputStyle():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 function set_chartEditorLiveInputStyle(value:ChartEditorLiveInputStyle):ChartEditorLiveInputStyle
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.chartEditorLiveInputStyle = value; data.optionsChartEditor.chartEditorLiveInputStyle = value;
flush(); flush();
return this.optionsChartEditor.chartEditorLiveInputStyle; return data.optionsChartEditor.chartEditorLiveInputStyle;
} }
public var chartEditorDownscroll(get, set):Bool; public var chartEditorDownscroll(get, set):Bool;
function get_chartEditorDownscroll():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 function set_chartEditorDownscroll(value:Bool):Bool
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.downscroll = value; data.optionsChartEditor.downscroll = value;
flush(); flush();
return this.optionsChartEditor.downscroll; return data.optionsChartEditor.downscroll;
} }
public var chartEditorPlaytestStartTime(get, set):Bool; public var chartEditorPlaytestStartTime(get, set):Bool;
function get_chartEditorPlaytestStartTime():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 function set_chartEditorPlaytestStartTime(value:Bool):Bool
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.playtestStartTime = value; data.optionsChartEditor.playtestStartTime = value;
flush(); flush();
return this.optionsChartEditor.playtestStartTime; return data.optionsChartEditor.playtestStartTime;
} }
public var chartEditorTheme(get, set):ChartEditorTheme; public var chartEditorTheme(get, set):ChartEditorTheme;
function get_chartEditorTheme():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 function set_chartEditorTheme(value:ChartEditorTheme):ChartEditorTheme
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.theme = value; data.optionsChartEditor.theme = value;
flush(); flush();
return this.optionsChartEditor.theme; return data.optionsChartEditor.theme;
} }
public var chartEditorMetronomeVolume(get, set):Float; public var chartEditorMetronomeVolume(get, set):Float;
function get_chartEditorMetronomeVolume():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 function set_chartEditorMetronomeVolume(value:Float):Float
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.metronomeVolume = value; data.optionsChartEditor.metronomeVolume = value;
flush(); flush();
return this.optionsChartEditor.metronomeVolume; return data.optionsChartEditor.metronomeVolume;
} }
public var chartEditorHitsoundVolumePlayer(get, set):Float; public var chartEditorHitsoundVolumePlayer(get, set):Float;
function get_chartEditorHitsoundVolumePlayer():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 function set_chartEditorHitsoundVolumePlayer(value:Float):Float
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.hitsoundVolumePlayer = value; data.optionsChartEditor.hitsoundVolumePlayer = value;
flush(); flush();
return this.optionsChartEditor.hitsoundVolumePlayer; return data.optionsChartEditor.hitsoundVolumePlayer;
} }
public var chartEditorHitsoundVolumeOpponent(get, set):Float; public var chartEditorHitsoundVolumeOpponent(get, set):Float;
function get_chartEditorHitsoundVolumeOpponent():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 function set_chartEditorHitsoundVolumeOpponent(value:Float):Float
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.hitsoundVolumeOpponent = value; data.optionsChartEditor.hitsoundVolumeOpponent = value;
flush(); flush();
return this.optionsChartEditor.hitsoundVolumeOpponent; return data.optionsChartEditor.hitsoundVolumeOpponent;
} }
public var chartEditorThemeMusic(get, set):Bool; public var chartEditorThemeMusic(get, set):Bool;
function get_chartEditorThemeMusic():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 function set_chartEditorThemeMusic(value:Bool):Bool
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.themeMusic = value; data.optionsChartEditor.themeMusic = value;
flush(); flush();
return this.optionsChartEditor.themeMusic; return data.optionsChartEditor.themeMusic;
} }
public var chartEditorPlaybackSpeed(get, set):Float; public var chartEditorPlaybackSpeed(get, set):Float;
function get_chartEditorPlaybackSpeed():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 function set_chartEditorPlaybackSpeed(value:Float):Float
{ {
// Set and apply. // Set and apply.
this.optionsChartEditor.playbackSpeed = value; data.optionsChartEditor.playbackSpeed = value;
flush(); 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<SaveScoreData> public function getLevelScore(levelId:String, difficultyId:String = 'normal'):Null<SaveScoreData>
{ {
var level = this.scores.levels.get(levelId); var level = data.scores.levels.get(levelId);
if (level == null) if (level == null)
{ {
level = []; level = [];
this.scores.levels.set(levelId, level); data.scores.levels.set(levelId, level);
} }
return level.get(difficultyId); return level.get(difficultyId);
@ -392,11 +406,11 @@ abstract Save(RawSaveData)
*/ */
public function setLevelScore(levelId:String, difficultyId:String, score:SaveScoreData):Void 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) if (level == null)
{ {
level = []; level = [];
this.scores.levels.set(levelId, level); data.scores.levels.set(levelId, level);
} }
level.set(difficultyId, score); level.set(difficultyId, score);
@ -405,11 +419,11 @@ abstract Save(RawSaveData)
public function isLevelHighScore(levelId:String, difficultyId:String = 'normal', score:SaveScoreData):Bool 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) if (level == null)
{ {
level = []; level = [];
this.scores.levels.set(levelId, level); data.scores.levels.set(levelId, level);
} }
var currentScore = level.get(difficultyId); var currentScore = level.get(difficultyId);
@ -448,11 +462,11 @@ abstract Save(RawSaveData)
*/ */
public function getSongScore(songId:String, difficultyId:String = 'normal'):Null<SaveScoreData> public function getSongScore(songId:String, difficultyId:String = 'normal'):Null<SaveScoreData>
{ {
var song = this.scores.songs.get(songId); var song = data.scores.songs.get(songId);
if (song == null) if (song == null)
{ {
song = []; song = [];
this.scores.songs.set(songId, song); data.scores.songs.set(songId, song);
} }
return song.get(difficultyId); return song.get(difficultyId);
} }
@ -462,11 +476,11 @@ abstract Save(RawSaveData)
*/ */
public function setSongScore(songId:String, difficultyId:String, score:SaveScoreData):Void 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) if (song == null)
{ {
song = []; song = [];
this.scores.songs.set(songId, song); data.scores.songs.set(songId, song);
} }
song.set(difficultyId, score); song.set(difficultyId, score);
@ -482,11 +496,11 @@ abstract Save(RawSaveData)
*/ */
public function isSongHighScore(songId:String, difficultyId:String = 'normal', score:SaveScoreData):Bool 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) if (song == null)
{ {
song = []; song = [];
this.scores.songs.set(songId, song); data.scores.songs.set(songId, song);
} }
var currentScore = song.get(difficultyId); var currentScore = song.get(difficultyId);
@ -527,9 +541,9 @@ abstract Save(RawSaveData)
switch (inputType) switch (inputType)
{ {
case Keys: 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(_): 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: case Keys:
if (playerId == 0) if (playerId == 0)
{ {
this.options.controls.p1.keyboard = controls; data.options.controls.p1.keyboard = controls;
} }
else else
{ {
this.options.controls.p2.keyboard = controls; data.options.controls.p2.keyboard = controls;
} }
case Gamepad(_): case Gamepad(_):
if (playerId == 0) if (playerId == 0)
{ {
this.options.controls.p1.gamepad = controls; data.options.controls.p1.gamepad = controls;
} }
else 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. * Call this to make sure the save data is written to disk.
*/ */
@ -606,17 +650,22 @@ abstract Save(RawSaveData)
if (legacySaveData != null) if (legacySaveData != null)
{ {
trace('[SAVE] Found legacy save data, converting...'); 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 else
{ {
trace('[SAVE] Loaded save data.'); 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<RawSaveData_v1_0_0> static function fetchLegacySaveData():Null<RawSaveData_v1_0_0>

View file

@ -19,21 +19,21 @@ class SaveDataMigrator
{ {
trace('[SAVE] No version found in save data! Returning blank data.'); trace('[SAVE] No version found in save data! Returning blank data.');
trace(inputData); trace(inputData);
return new Save(); return new Save(Save.getDefault());
} }
else else
{ {
if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE)) if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE))
{ {
// Simply cast the structured data. // Simply import the structured data.
var save:Save = inputData; var save:Save = new Save(inputData);
return save; return save;
} }
else else
{ {
trace('[SAVE] Invalid save data version! Returning blank data.'); trace('[SAVE] Invalid save data version! Returning blank data.');
trace(inputData); 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 inputSaveData:RawSaveData_v1_0_0 = cast inputData;
var result:Save = new Save(); var result:Save = new Save(Save.getDefault());
result.volume = inputSaveData.volume; result.volume = inputSaveData.volume;
result.mute = inputSaveData.mute; result.mute = inputSaveData.mute;

View file

@ -920,12 +920,12 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
function get_shouldShowBackupAvailableDialog():Bool function get_shouldShowBackupAvailableDialog():Bool
{ {
return Save.get().chartEditorHasBackup; return Save.instance.chartEditorHasBackup;
} }
function set_shouldShowBackupAvailableDialog(value:Bool):Bool 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 public function loadPreferences():Void
{ {
var save:Save = Save.get(); var save:Save = Save.instance;
if (previousWorkingFilePaths[0] == null) if (previousWorkingFilePaths[0] == null)
{ {
@ -2191,7 +2191,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
public function writePreferences(hasBackup:Bool):Void 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! // Can't use filter() because of null safety checking!
var filteredWorkingFilePaths:Array<String> = []; var filteredWorkingFilePaths:Array<String> = [];

View file

@ -1001,7 +1001,7 @@ class FreeplayState extends MusicBeatSubState
var daSong = songs[curSelected]; var daSong = songs[curSelected];
if (daSong != null) 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; intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore?.accuracy ?? 0.0; intendedCompletion = songScore?.accuracy ?? 0.0;
rememberedDifficulty = currentDifficulty; rememberedDifficulty = currentDifficulty;
@ -1189,7 +1189,7 @@ class FreeplayState extends MusicBeatSubState
var daSongCapsule = grpCapsules.members[curSelected]; var daSongCapsule = grpCapsules.members[curSelected];
if (daSongCapsule.songData != null) 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; intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore?.accuracy ?? 0.0; intendedCompletion = songScore?.accuracy ?? 0.0;
diffIdsCurrent = daSongCapsule.songData.songDifficulties; diffIdsCurrent = daSongCapsule.songData.songDifficulties;

View file

@ -649,7 +649,7 @@ class StoryMenuState extends MusicBeatState
tracklistText.screenCenter(X); tracklistText.screenCenter(X);
tracklistText.x -= FlxG.width * 0.35; tracklistText.x -= FlxG.width * 0.35;
var levelScore:Null<SaveScoreData> = Save.get().getLevelScore(currentLevelId, currentDifficultyId); var levelScore:Null<SaveScoreData> = Save.instance.getLevelScore(currentLevelId, currentDifficultyId);
highScore = levelScore?.score ?? 0; highScore = levelScore?.score ?? 0;
// levelScore.accuracy // levelScore.accuracy
} }