using Harmony; using KCM.LoadSaveOverrides; using System; using UnityEngine; namespace KCM { public static class LoadSaveLoadAtPathHook { public static byte[] saveData = new byte[1]; public static string lastLoadedPath = string.Empty; } public static class LoadSaveLoadHook { public static byte[] saveBytes = null; public static bool memoryStreamHook = false; public static MultiplayerSaveContainer saveContainer = null; } [HarmonyPatch(typeof(LoadSave), "LoadAtPath")] public class LoadSaveLoadAtPathCaptureHook { public static void Prefix(string path) { try { if (string.IsNullOrEmpty(path)) return; LoadSaveLoadAtPathHook.lastLoadedPath = path; if (!FileExists(path)) return; LoadSaveLoadAtPathHook.saveData = ReadAllBytes(path); Main.Log($"Captured save bytes from: {path} ({LoadSaveLoadAtPathHook.saveData.Length} bytes)"); } catch (Exception ex) { Main.Log("Failed capturing save bytes from LoadSave.LoadAtPath"); Main.Log(ex); } } private static bool FileExists(string path) { object result = InvokeSystemIoFile("Exists", new Type[] { typeof(string) }, new object[] { path }); return result is bool && (bool)result; } private static byte[] ReadAllBytes(string path) { object result = InvokeSystemIoFile("ReadAllBytes", new Type[] { typeof(string) }, new object[] { path }); return result as byte[]; } private static object InvokeSystemIoFile(string methodName, Type[] parameterTypes, object[] args) { // Avoid direct references to System.IO in IL (some mod loaders forbid it). const string typeName = "System.IO.File"; Type fileType = Type.GetType(typeName) ?? Type.GetType(typeName + ", mscorlib"); if (fileType == null) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length && fileType == null; i++) { try { fileType = assemblies[i].GetType(typeName, false); } catch { } } } if (fileType == null) return null; var method = fileType.GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static, null, parameterTypes, null); if (method == null) return null; return method.Invoke(null, args); } } }