Funkin/source/funkin/save/migrator/SaveDataMigrator.hx

318 lines
10 KiB
Haxe
Raw Normal View History

package funkin.save.migrator;
import funkin.save.Save;
import funkin.save.migrator.RawSaveData_v1_0_0;
import thx.semver.Version;
import funkin.util.VersionUtil;
@:nullSafety
class SaveDataMigrator
{
/**
* Migrate from one 2.x version to another.
*/
public static function migrate(inputData:Dynamic):Save
{
var version:Null<thx.semver.Version> = VersionUtil.parseVersion(inputData?.version ?? null);
if (version == null)
{
trace('[SAVE] No version found in save data! Returning blank data.');
trace(inputData);
return new Save(Save.getDefault());
}
else
{
2024-05-21 02:23:21 -04:00
// Sometimes the Haxe serializer has issues with the version so we fix it here.
version = VersionUtil.repairVersion(version);
if (VersionUtil.validateVersion(version, Save.SAVE_DATA_VERSION_RULE))
{
// Import the structured data.
2024-05-21 04:02:53 -04:00
var saveDataWithDefaults:RawSaveData = cast thx.Objects.deepCombine(Save.getDefault(), inputData);
var save:Save = new Save(saveDataWithDefaults);
return save;
}
else
{
2024-05-21 02:23:21 -04:00
var message:String = 'Error migrating save data, expected ${Save.SAVE_DATA_VERSION}.';
lime.app.Application.current.window.alert(message, "Save Data Failure");
trace('[SAVE] ' + message);
return new Save(Save.getDefault());
}
}
}
/**
* Migrate from 1.x to the latest version.
*/
public static function migrateFromLegacy(inputData:Dynamic):Save
{
var inputSaveData:RawSaveData_v1_0_0 = cast inputData;
var result:Save = new Save(Save.getDefault());
result.volume = inputSaveData.volume;
result.mute = inputSaveData.mute;
result.ngSessionId = inputSaveData.sessionId;
// TODO: Port over the save data from the legacy save data format.
migrateLegacyScores(result, inputSaveData);
migrateLegacyControls(result, inputSaveData);
return result;
}
static function migrateLegacyScores(result:Save, inputSaveData:RawSaveData_v1_0_0):Void
{
if (inputSaveData.songCompletion == null)
{
inputSaveData.songCompletion = [];
}
if (inputSaveData.songScores == null)
{
inputSaveData.songScores = [];
}
migrateLegacyLevelScore(result, inputSaveData, 'week0');
migrateLegacyLevelScore(result, inputSaveData, 'week1');
migrateLegacyLevelScore(result, inputSaveData, 'week2');
migrateLegacyLevelScore(result, inputSaveData, 'week3');
migrateLegacyLevelScore(result, inputSaveData, 'week4');
migrateLegacyLevelScore(result, inputSaveData, 'week5');
migrateLegacyLevelScore(result, inputSaveData, 'week6');
migrateLegacyLevelScore(result, inputSaveData, 'week7');
migrateLegacySongScore(result, inputSaveData, ['tutorial', 'Tutorial']);
migrateLegacySongScore(result, inputSaveData, ['bopeebo', 'Bopeebo']);
migrateLegacySongScore(result, inputSaveData, ['fresh', 'Fresh']);
migrateLegacySongScore(result, inputSaveData, ['dadbattle', 'Dadbattle']);
migrateLegacySongScore(result, inputSaveData, ['monster', 'Monster']);
migrateLegacySongScore(result, inputSaveData, ['south', 'South']);
migrateLegacySongScore(result, inputSaveData, ['spookeez', 'Spookeez']);
migrateLegacySongScore(result, inputSaveData, ['pico', 'Pico']);
migrateLegacySongScore(result, inputSaveData, ['philly-nice', 'Philly', 'philly', 'Philly-Nice']);
migrateLegacySongScore(result, inputSaveData, ['blammed', 'Blammed']);
migrateLegacySongScore(result, inputSaveData, ['satin-panties', 'Satin-Panties']);
migrateLegacySongScore(result, inputSaveData, ['high', 'High']);
migrateLegacySongScore(result, inputSaveData, ['milf', 'Milf', 'MILF']);
migrateLegacySongScore(result, inputSaveData, ['cocoa', 'Cocoa']);
migrateLegacySongScore(result, inputSaveData, ['eggnog', 'Eggnog']);
migrateLegacySongScore(result, inputSaveData, ['winter-horrorland', 'Winter-Horrorland']);
migrateLegacySongScore(result, inputSaveData, ['senpai', 'Senpai']);
migrateLegacySongScore(result, inputSaveData, ['roses', 'Roses']);
migrateLegacySongScore(result, inputSaveData, ['thorns', 'Thorns']);
migrateLegacySongScore(result, inputSaveData, ['ugh', 'Ugh']);
migrateLegacySongScore(result, inputSaveData, ['guns', 'Guns']);
migrateLegacySongScore(result, inputSaveData, ['stress', 'Stress']);
}
static function migrateLegacyLevelScore(result:Save, inputSaveData:RawSaveData_v1_0_0, levelId:String):Void
{
var scoreDataEasy:SaveScoreData =
{
score: inputSaveData.songScores.get('${levelId}-easy') ?? 0,
accuracy: inputSaveData.songCompletion.get('${levelId}-easy') ?? 0.0,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
};
result.setLevelScore(levelId, 'easy', scoreDataEasy);
var scoreDataNormal:SaveScoreData =
{
score: inputSaveData.songScores.get('${levelId}') ?? 0,
accuracy: inputSaveData.songCompletion.get('${levelId}') ?? 0.0,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
};
result.setLevelScore(levelId, 'normal', scoreDataNormal);
var scoreDataHard:SaveScoreData =
{
score: inputSaveData.songScores.get('${levelId}-hard') ?? 0,
accuracy: inputSaveData.songCompletion.get('${levelId}-hard') ?? 0.0,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
};
result.setLevelScore(levelId, 'hard', scoreDataHard);
}
static function migrateLegacySongScore(result:Save, inputSaveData:RawSaveData_v1_0_0, songIds:Array<String>):Void
{
var scoreDataEasy:SaveScoreData =
{
score: 0,
accuracy: 0,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
};
for (songId in songIds)
{
scoreDataEasy.score = Std.int(Math.max(scoreDataEasy.score, inputSaveData.songScores.get('${songId}-easy') ?? 0));
scoreDataEasy.accuracy = Math.max(scoreDataEasy.accuracy, inputSaveData.songCompletion.get('${songId}-easy') ?? 0.0);
}
result.setSongScore(songIds[0], 'easy', scoreDataEasy);
var scoreDataNormal:SaveScoreData =
{
score: 0,
accuracy: 0,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
};
for (songId in songIds)
{
scoreDataNormal.score = Std.int(Math.max(scoreDataNormal.score, inputSaveData.songScores.get('${songId}') ?? 0));
scoreDataNormal.accuracy = Math.max(scoreDataNormal.accuracy, inputSaveData.songCompletion.get('${songId}') ?? 0.0);
}
result.setSongScore(songIds[0], 'normal', scoreDataNormal);
var scoreDataHard:SaveScoreData =
{
score: 0,
accuracy: 0,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
};
for (songId in songIds)
{
scoreDataHard.score = Std.int(Math.max(scoreDataHard.score, inputSaveData.songScores.get('${songId}-hard') ?? 0));
scoreDataHard.accuracy = Math.max(scoreDataHard.accuracy, inputSaveData.songCompletion.get('${songId}-hard') ?? 0.0);
}
result.setSongScore(songIds[0], 'hard', scoreDataHard);
}
static function migrateLegacyControls(result:Save, inputSaveData:RawSaveData_v1_0_0):Void
{
var p1Data = inputSaveData?.controls?.p1;
if (p1Data != null)
{
migrateLegacyPlayerControls(result, 1, p1Data);
}
var p2Data = inputSaveData?.controls?.p2;
if (p2Data != null)
{
migrateLegacyPlayerControls(result, 2, p2Data);
}
}
static function migrateLegacyPlayerControls(result:Save, playerId:Int, controlsData:SavePlayerControlsData_v1_0_0):Void
{
var outputKeyControls:SaveControlsData =
{
ACCEPT: controlsData?.keys?.ACCEPT ?? null,
BACK: controlsData?.keys?.BACK ?? null,
CUTSCENE_ADVANCE: controlsData?.keys?.CUTSCENE_ADVANCE ?? null,
NOTE_DOWN: controlsData?.keys?.NOTE_DOWN ?? null,
NOTE_LEFT: controlsData?.keys?.NOTE_LEFT ?? null,
NOTE_RIGHT: controlsData?.keys?.NOTE_RIGHT ?? null,
NOTE_UP: controlsData?.keys?.NOTE_UP ?? null,
PAUSE: controlsData?.keys?.PAUSE ?? null,
RESET: controlsData?.keys?.RESET ?? null,
UI_DOWN: controlsData?.keys?.UI_DOWN ?? null,
UI_LEFT: controlsData?.keys?.UI_LEFT ?? null,
UI_RIGHT: controlsData?.keys?.UI_RIGHT ?? null,
UI_UP: controlsData?.keys?.UI_UP ?? null,
VOLUME_DOWN: controlsData?.keys?.VOLUME_DOWN ?? null,
VOLUME_MUTE: controlsData?.keys?.VOLUME_MUTE ?? null,
VOLUME_UP: controlsData?.keys?.VOLUME_UP ?? null,
};
var outputPadControls:SaveControlsData =
{
ACCEPT: controlsData?.pad?.ACCEPT ?? null,
BACK: controlsData?.pad?.BACK ?? null,
CUTSCENE_ADVANCE: controlsData?.pad?.CUTSCENE_ADVANCE ?? null,
NOTE_DOWN: controlsData?.pad?.NOTE_DOWN ?? null,
NOTE_LEFT: controlsData?.pad?.NOTE_LEFT ?? null,
NOTE_RIGHT: controlsData?.pad?.NOTE_RIGHT ?? null,
NOTE_UP: controlsData?.pad?.NOTE_UP ?? null,
PAUSE: controlsData?.pad?.PAUSE ?? null,
RESET: controlsData?.pad?.RESET ?? null,
UI_DOWN: controlsData?.pad?.UI_DOWN ?? null,
UI_LEFT: controlsData?.pad?.UI_LEFT ?? null,
UI_RIGHT: controlsData?.pad?.UI_RIGHT ?? null,
UI_UP: controlsData?.pad?.UI_UP ?? null,
VOLUME_DOWN: controlsData?.pad?.VOLUME_DOWN ?? null,
VOLUME_MUTE: controlsData?.pad?.VOLUME_MUTE ?? null,
VOLUME_UP: controlsData?.pad?.VOLUME_UP ?? null,
};
result.setControls(playerId, Keys, outputKeyControls);
result.setControls(playerId, Gamepad(0), outputPadControls);
}
}