Skip to content

Commit

Permalink
[KKS][ExtSave] Avoid error when saving more than 2 GB in the main game (
Browse files Browse the repository at this point in the history
#197)

Fixes failing to save the game when used character cards take up more than 2GB in total when serialized.
Discussion at IllusionMods/IllusionFixes#63
  • Loading branch information
takahiro0327 committed Apr 9, 2024
1 parent abee07b commit d091813
Showing 1 changed file with 54 additions and 31 deletions.
85 changes: 54 additions & 31 deletions src/KKS_ExtensibleSaveFormat/KKS.ExtendedSave.SaveData.Hooks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,67 @@ private static void SaveDataLoadHook(BinaryReader br, ref WorldData saveData)

#region Saving

// Nope, not patching the save lambda, not doing it, noooope
[HarmonyPostfix, HarmonyPatch(typeof(WorldData), nameof(WorldData.GetBytes), typeof(WorldData))]
private static void SaveDataSaveHook(WorldData saveData, ref byte[] __result)
[HarmonyPrefix, HarmonyPatch(typeof(SaveData.WorldData), nameof(SaveData.WorldData.Save), typeof(string), typeof(string))]
[HarmonyPriority(Priority.Last)]
private static bool WorldDataSaveOverride(SaveData.WorldData __instance, string path, string fileName)
{
try
Illusion.Utils.File.OpenWrite(path + fileName, false, (Action<FileStream>)(f =>
{
SaveDataWriteEvent(saveData);
try
{
using (BinaryWriter binaryWriter = new BinaryWriter((Stream)f))
{
var saveData = __instance;
Logger.Log(BepInEx.Logging.LogLevel.Debug, "SaveData hook!");
// Data to be written by WorldData.GetBytes
byte[] buffer = MessagePackSerializer.Serialize<WorldData>(saveData);
binaryWriter.Write(buffer.Length);
binaryWriter.Write(buffer);
byte[] bytes1 = SaveData.Player.GetBytes(saveData.player);
binaryWriter.Write(bytes1.Length);
binaryWriter.Write(bytes1);
int count = saveData.heroineList.Count;
binaryWriter.Write(count);
for (int index = 0; index < count; ++index)
{
byte[] bytes2 = Heroine.GetBytes(saveData.heroineList[index]);
binaryWriter.Write(bytes2.Length);
binaryWriter.Write(bytes2);
}
Dictionary<string, PluginData> extendedData = GetAllExtendedData(saveData);
if (extendedData == null)
return;
SaveDataWriteEvent(__instance);
Logger.Log(BepInEx.Logging.LogLevel.Debug, "SaveData hook!");
// Append the ext data
using (var ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
// Write the original data first
bw.Write(__result);

// Then write our data
bw.Write(Marker);
bw.Write(DataVersion);
byte[] data = MessagePackSerializer.Serialize(extendedData);
bw.Write(data.Length);
bw.Write(data);
}
// Append the ext data
Dictionary<string, PluginData> extendedData = GetAllExtendedData(saveData);
// Replace the result, not the most efficient way but save files shouldn't be big enough to matter since it's all done in memory
__result = ms.ToArray();
if (extendedData != null)
{
binaryWriter.Write(Marker);
binaryWriter.Write(DataVersion);
byte[] data = MessagePackSerializer.Serialize(extendedData);
binaryWriter.Write(data.Length);
binaryWriter.Write(data);
}
}
}
}
catch (Exception ex)
{
UnityEngine.Debug.LogException(ex);
}
catch (Exception ex)
{
Logger.Log(BepInEx.Logging.LogLevel.Message | BepInEx.Logging.LogLevel.Error, "Failed to save the game, the save file may be corrupted! Try saving again in an empty slot.\nError: " + ex.Message);
UnityEngine.Debug.LogException(ex);
}
}));

return false;
}


[HarmonyPostfix, HarmonyPatch(typeof(WorldData), nameof(WorldData.GetBytes), typeof(WorldData))]
private static void WorldDataGetBytesDisableHook(WorldData saveData, ref byte[] __result)
{
// This function should not be called.
// Originally called from SaveData.WorldData.Save(), but the original Save() is not called by the patch.
throw new System.NotSupportedException("Do not use this method, use WorldData.Save instead. More info: https://github.com/IllusionMods/BepisPlugins/pull/197");
}

#endregion
Expand Down

0 comments on commit d091813

Please sign in to comment.