Finish save data repair (you should be able to transfer your save now)

This commit is contained in:
EliteMasterEric 2024-06-04 19:44:00 -04:00
parent c056c72762
commit ae950c7382
5 changed files with 33 additions and 12 deletions

View file

@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Senpai (increased the note speed) - Senpai (increased the note speed)
- Thorns (increased the note speed slightly) - Thorns (increased the note speed slightly)
- Favorite songs marked in Freeplay are now stored between sessions. - Favorite songs marked in Freeplay are now stored between sessions.
- In the event that the game cannot load your save data, it will now perform a backup before clearing it, so that we can try to repair it in the future.
- Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!) - Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!)
- Improved logic for NoteHitScriptEvents, allowing you to view the hit diff and modify whether a note hit is a combo break (thanks nebulazorua!) - Improved logic for NoteHitScriptEvents, allowing you to view the hit diff and modify whether a note hit is a combo break (thanks nebulazorua!)
- Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!) - Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!)

View file

@ -16,7 +16,7 @@ import thx.semver.Version;
@:nullSafety @:nullSafety
class Save class Save
{ {
public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.4"; public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.5";
public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x"; 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. // We load this version's saves from a new save path, to maintain SOME level of backwards compatibility.
@ -56,6 +56,9 @@ class Save
if (data == null) this.data = Save.getDefault(); if (data == null) this.data = Save.getDefault();
else else
this.data = data; this.data = data;
// Make sure the verison number is up to date before we flush.
this.data.version = Save.SAVE_DATA_VERSION;
} }
public static function getDefault():RawSaveData public static function getDefault():RawSaveData
@ -713,7 +716,6 @@ class Save
{ {
trace('[SAVE] Found legacy save data, converting...'); trace('[SAVE] Found legacy save data, converting...');
var gameSave = SaveDataMigrator.migrateFromLegacy(legacySaveData); var gameSave = SaveDataMigrator.migrateFromLegacy(legacySaveData);
@:privateAccess
FlxG.save.mergeData(gameSave.data, true); FlxG.save.mergeData(gameSave.data, true);
} }
else else
@ -725,20 +727,19 @@ class Save
} }
else else
{ {
trace('[SAVE] Loaded save data.'); trace('[SAVE] Found existing save data.');
@:privateAccess
var gameSave = SaveDataMigrator.migrate(FlxG.save.data); var gameSave = SaveDataMigrator.migrate(FlxG.save.data);
FlxG.save.mergeData(gameSave.data, true); FlxG.save.mergeData(gameSave.data, true);
} }
} }
public static function archiveBadSaveData(data:Dynamic):Void public static function archiveBadSaveData(data:Dynamic):Int
{ {
// We want to save this somewhere so we can try to recover it for the user in the future! // We want to save this somewhere so we can try to recover it for the user in the future!
final RECOVERY_SLOT_START = 1000; final RECOVERY_SLOT_START = 1000;
writeToAvailableSlot(RECOVERY_SLOT_START, data); return writeToAvailableSlot(RECOVERY_SLOT_START, data);
} }
public static function debug_queryBadSaveData():Void public static function debug_queryBadSaveData():Void
@ -763,7 +764,7 @@ class Save
return targetSaveData.data; return targetSaveData.data;
} }
static function writeToAvailableSlot(slot:Int, data:Dynamic):Void static function writeToAvailableSlot(slot:Int, data:Dynamic):Int
{ {
trace('[SAVE] Finding slot to write data to (starting with ${slot})...'); trace('[SAVE] Finding slot to write data to (starting with ${slot})...');
@ -781,6 +782,7 @@ class Save
targetSaveData.mergeData(data, true); targetSaveData.mergeData(data, true);
trace('[SAVE] Data written to slot ${slot}!'); trace('[SAVE] Data written to slot ${slot}!');
return slot;
} }
/** /**

View file

@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.0.5] - 2024-05-21
### Fixed
- Resolved an issue where HTML5 wouldn't store the semantic version properly, causing the game to fail to load the save.
## [2.0.4] - 2024-05-21 ## [2.0.4] - 2024-05-21
### Added ### Added
- `favoriteSongs:Array<String>` to `Save` - `favoriteSongs:Array<String>` to `Save`

View file

@ -35,9 +35,9 @@ class SaveDataMigrator
else else
{ {
var message:String = 'Error migrating save data, expected ${Save.SAVE_DATA_VERSION}.'; var message:String = 'Error migrating save data, expected ${Save.SAVE_DATA_VERSION}.';
lime.app.Application.current.window.alert(message, "Save Data Failure"); var slot:Int = Save.archiveBadSaveData(inputData);
Save.archiveBadSaveData(inputData); var fullMessage:String = 'An error occurred migrating your save data.\n${message}\nInvalid data has been moved to save slot ${slot}.';
trace('[SAVE] ' + message); lime.app.Application.current.window.alert(fullMessage, "Save Data Failure");
return new Save(Save.getDefault()); return new Save(Save.getDefault());
} }
} }

View file

@ -23,6 +23,8 @@ class VersionUtil
{ {
try try
{ {
var versionRaw:thx.semver.Version.SemVer = version;
trace('${versionRaw} satisfies (${versionRule})? ${version.satisfies(versionRule)}');
return version.satisfies(versionRule); return version.satisfies(versionRule);
} }
catch (e) catch (e)
@ -40,10 +42,22 @@ class VersionUtil
{ {
// This is bad! versionData.version should be an array! // This is bad! versionData.version should be an array!
trace('[SAVE] Version data repair required! (got ${versionData.version})'); trace('[SAVE] Version data repair required! (got ${versionData.version})');
var fixedVersionData = [versionData.version[0], versionData.version[1], versionData.version[2]]; // Turn the objects back into arrays.
versionData.version = fixedVersionData; // I'd use DynamicsT.values but IDK if it maintains order
versionData.version = [versionData.version[0], versionData.version[1], versionData.version[2]];
// This is so jank but it should work.
var buildData:Dynamic<String> = cast versionData.build;
var buildDataFixed:Array<thx.semver.Version.Identifier> = thx.Dynamics.DynamicsT.values(buildData)
.map(function(d:Dynamic) return StringId(d.toString()));
versionData.build = buildDataFixed;
var preData:Dynamic<String> = cast versionData.pre;
var preDataFixed:Array<thx.semver.Version.Identifier> = thx.Dynamics.DynamicsT.values(preData).map(function(d:Dynamic) return StringId(d.toString()));
versionData.pre = preDataFixed;
var fixedVersion:thx.semver.Version = versionData; var fixedVersion:thx.semver.Version = versionData;
trace('[SAVE] Fixed version: ${fixedVersion}');
return fixedVersion; return fixedVersion;
} }
else else