Fix save load/save error
This commit is contained in:
parent
bf0903b173
commit
917eaf48c4
|
@ -65,8 +65,11 @@ namespace StardewModdingAPI
|
|||
internal static GameFramework GameFramework { get; } = GameFramework.MonoGame;
|
||||
|
||||
/// <summary>The game's assembly name.</summary>
|
||||
#if SMAPI_FOR_MOBILE
|
||||
internal static string GameAssemblyName { get; } = "StardewValley";
|
||||
#else
|
||||
internal static string GameAssemblyName { get; } = "Stardew Valley";
|
||||
|
||||
#endif
|
||||
/// <summary>The <see cref="Context.ScreenId"/> value which should appear in the SMAPI log, if any.</summary>
|
||||
internal static int? LogScreenId { get; set; }
|
||||
|
||||
|
@ -139,11 +142,7 @@ namespace StardewModdingAPI
|
|||
/// <summary>The directory path in which error logs should be stored.</summary>
|
||||
public static string LogDir { get; } = Path.Combine(Constants.DataPath, "ErrorLogs");
|
||||
/// <summary>The directory path where all saves are stored.</summary>
|
||||
#if SMAPI_FOR_MOBILE
|
||||
public static string SavesPath { get; } = Constants.DataPath;
|
||||
#else
|
||||
public static string SavesPath { get; } = Path.Combine(Constants.DataPath, "Saves");
|
||||
#endif
|
||||
|
||||
/// <summary>The name of the current save folder (if save info is available, regardless of whether the save file exists yet).</summary>
|
||||
public static string? SaveFolderName => Constants.GetSaveFolderName();
|
||||
|
|
|
@ -178,9 +178,16 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
using MemoryStream outSymbolStream = new();
|
||||
assembly.Definition.Write(outAssemblyStream, new WriterParameters { WriteSymbols = true, SymbolStream = outSymbolStream, SymbolWriterProvider = this.SymbolWriterProvider });
|
||||
byte[] bytes = outAssemblyStream.ToArray();
|
||||
if (assembly.File.Name != "MoonSharp.Interpreter.dll" && assembly.File.Name != "PyTK.dll" )
|
||||
{
|
||||
lastAssembly = Assembly.Load(bytes, outSymbolStream.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
lastAssembly = Assembly.Load(bytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!oneAssembly)
|
||||
this.Monitor.Log($" Loading {assembly.File.Name}...");
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades;
|
||||
|
||||
public static class EnumMethods
|
||||
{
|
||||
public static bool IsDefined<TEnum>(TEnum value) where TEnum : struct, Enum
|
||||
{
|
||||
Type enumType = typeof(TEnum);
|
||||
return Enum.IsDefined(enumType, value);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using HarmonyLib;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using MonoMod.Utils;
|
||||
using StardewModdingAPI.Framework.ModLoading.Framework;
|
||||
|
||||
namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
||||
|
@ -31,7 +33,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
|||
/// <param name="toType">The type with methods to map to.</param>
|
||||
/// <param name="onlyIfPlatformChanged">Whether to only rewrite references if loading the assembly on a different platform than it was compiled on.</param>
|
||||
public MethodToAnotherStaticMethodRewriter(Type fromType, Predicate<MethodReference> fromMethodSelector, Type toType, string toMethod)
|
||||
: base( $"{fromType.Name} methods")
|
||||
: base($"{fromType.Name} methods")
|
||||
{
|
||||
this.FromType = fromType;
|
||||
this.FromMethodSelector = fromMethodSelector;
|
||||
|
@ -49,7 +51,14 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
|||
if (!this.IsMatch(instruction))
|
||||
return false;
|
||||
|
||||
instruction.Operand = module.ImportReference(this.ToType.GetMethod(this.ToMethod));
|
||||
MethodReference newReference = module.ImportReference(this.ToType.GetMethod(this.ToMethod));
|
||||
if (instruction.Operand is GenericInstanceMethod instructionOperand)
|
||||
{
|
||||
GenericInstanceMethod genericInstance = new(newReference);
|
||||
genericInstance.GenericArguments.AddRange(instructionOperand.GenericArguments);
|
||||
newReference = genericInstance;
|
||||
}
|
||||
instruction.Operand = newReference;
|
||||
return this.MarkRewritten();
|
||||
}
|
||||
|
||||
|
|
|
@ -293,6 +293,7 @@ namespace StardewModdingAPI.Framework
|
|||
new StringPatcher(this.Reflection),
|
||||
new ThreadSilenceExitPatch(this.Monitor),
|
||||
new UIThreadPatch(this.Monitor),
|
||||
new SaveGamePatch(this.Translator, this.Monitor),
|
||||
#endif
|
||||
new TitleMenuPatcher(this.OnLoadStageChanged)
|
||||
);
|
||||
|
|
|
@ -98,6 +98,8 @@ namespace StardewModdingAPI.Metadata
|
|||
yield return new MethodToAnotherStaticMethodRewriter(typeof(ISoundBank), (method) => method.Name == nameof(SoundBankMethods.AddCue), typeof(SoundBankMethods), "AddCue");
|
||||
yield return new MethodToAnotherStaticMethodRewriter(typeof(ISoundBank), (method) => method.Name == nameof(SoundBankMethods.GetCueDefinition), typeof(SoundBankMethods), "GetCueDefinition");
|
||||
|
||||
yield return new MethodToAnotherStaticMethodRewriter(typeof(Enum), (method) => method.Name == nameof(EnumMethods.IsDefined) && method.Parameters.Count == 1, typeof(EnumMethods), "IsDefined");
|
||||
|
||||
//Constructor Rewrites
|
||||
yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods));
|
||||
yield return new MethodParentRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods));
|
||||
|
|
|
@ -3,10 +3,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml.Serialization;
|
||||
using HarmonyLib;
|
||||
// using Microsoft.AppCenter.Crashes;
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewModdingAPI.Framework;
|
||||
using StardewModdingAPI.Internal.Patching;
|
||||
using StardewValley;
|
||||
|
@ -45,13 +44,25 @@ namespace StardewModdingAPI.Patches
|
|||
/// <param name="harmony">The Harmony instance.</param>
|
||||
public override void Apply(Harmony harmony, IMonitor monitor)
|
||||
{
|
||||
// harmony.Patch(
|
||||
// original: AccessTools.Method(typeof(SaveGame), "HandleLoadError"),
|
||||
// prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.Prefix))
|
||||
// );
|
||||
// harmony.Patch(
|
||||
// original: AccessTools.Method(typeof(SaveGameMenu), "update"),
|
||||
// finalizer: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.SaveGameMenu_UpdateFinalizer))
|
||||
// );
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(SaveGame), "HandleLoadError"),
|
||||
prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.Prefix))
|
||||
original: AccessTools.Method(typeof(XmlSerializer).Assembly.GetType("System.Xml.Serialization.XmlSerializationReaderInterpreter"), "GetValueFromXmlString"),
|
||||
prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.XmlSerializationReaderInterpreter_PrefixGetValueFromXmlString))
|
||||
);
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(SaveGameMenu), "update"),
|
||||
finalizer: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.SaveGameMenu_UpdateFinalizer))
|
||||
original: AccessTools.Method(typeof(XmlSerializer).Assembly.GetType("System.Xml.Serialization.XmlSerializationReaderInterpreter"), "AddListValue"),
|
||||
prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.XmlSerializationReaderInterpreter_PrefixAddListValue))
|
||||
);
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(XmlSerializer).Assembly.GetType("System.Xml.Serialization.XmlSerializationWriterInterpreter"), "GetEnumXmlValue"),
|
||||
prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.XmlSerializationWriterInterpreter_PrefixGetEnumXmlValue))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -92,27 +103,20 @@ namespace StardewModdingAPI.Patches
|
|||
else if (SaveGame.newerBackUpExists(fileName) != null)
|
||||
SaveGame.Load(fileName, false, true);
|
||||
else if (SaveGame.oldBackUpExists(fileName) != null)
|
||||
{
|
||||
SaveGame.Load(fileName, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SaveGame.partialOldBackUpExists(fileName) == null)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IEnumerator<int> enumerator1 = SaveGame.getLoadEnumerator(fileName, false, true, true);
|
||||
while (enumerator1 != null)
|
||||
{
|
||||
if (!enumerator1.MoveNext())
|
||||
enumerator1 = null;
|
||||
}
|
||||
|
||||
IEnumerator<int> enumerator2 = SaveGame.Save();
|
||||
while (enumerator2 != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!enumerator2.MoveNext())
|
||||
|
@ -126,10 +130,8 @@ namespace StardewModdingAPI.Patches
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (failed)
|
||||
{
|
||||
SAlertDialogUtil.AlertMessage(
|
||||
SaveGamePatch.Translator.Get("warn.save-broken"),
|
||||
positive: SaveGamePatch.Translator.Get("btn.swap"),
|
||||
|
@ -138,33 +140,86 @@ namespace StardewModdingAPI.Patches
|
|||
{
|
||||
if (action == SAlertDialogUtil.ActionType.POSITIVE)
|
||||
{
|
||||
if (!SaveGame.swapForOldSave())
|
||||
{
|
||||
Game1.ExitToTitle();
|
||||
}
|
||||
if (!SaveGame.swapForOldSave()) Game1.ExitToTitle();
|
||||
}
|
||||
else
|
||||
{
|
||||
Game1.ExitToTitle();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>The method to call instead of <see cref="StardewValley.Menus.SaveGameMenu.update"/>.</summary>
|
||||
/// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
|
||||
private static Exception SaveGameMenu_UpdateFinalizer(SaveGameMenu __instance, Exception __exception)
|
||||
{
|
||||
if(__exception != null) {
|
||||
if (__exception != null)
|
||||
{
|
||||
SaveGamePatch.Monitor.Log($"Failed during SaveGameMenu.update method :\n{__exception.InnerException ?? __exception}", LogLevel.Error);
|
||||
__instance.complete();
|
||||
Game1.addHUDMessage(new HUDMessage("An error occurs during save the game.Check the error log for details.", HUDMessage.error_type));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool XmlSerializationReaderInterpreter_PrefixGetValueFromXmlString(string value, ref object __result)
|
||||
{
|
||||
if (value?.Length > 0) return true;
|
||||
__result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool XmlSerializationReaderInterpreter_PrefixAddListValue(object listType, ref object list, int index, object value, bool canCreateInstance)
|
||||
{
|
||||
Type type = (Type)AccessTools.Property(listType.GetType(), "Type").GetValue(listType);
|
||||
if (type.IsArray) return true;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
if (!canCreateInstance) throw new InvalidOperationException(string.Format("Could not serialize {0}. Default constructors are required for collections and enumerators.", type.FullName));
|
||||
|
||||
list = Activator.CreateInstance(type, true);
|
||||
}
|
||||
|
||||
Type listItemType = (Type)AccessTools.Property(listType.GetType(), "ListItemType").GetValue(listType);
|
||||
if (listItemType.IsEnum && value != null)
|
||||
type.GetMethod("Add", new[] { typeof(string) }).Invoke(list, new[] { value.ToString() });
|
||||
else
|
||||
type.GetMethod("Add", new[] { listItemType }).Invoke(list, new[] { value });
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool XmlSerializationWriterInterpreter_PrefixGetEnumXmlValue(XmlTypeMapping typeMap, object ob, ref string __result)
|
||||
{
|
||||
if (ob == null)
|
||||
{
|
||||
__result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
object objectMap = AccessTools.Property(typeMap.GetType(), "ObjectMap").GetValue(typeMap);
|
||||
if (ob is string enumString)
|
||||
{
|
||||
string[] enumNames = (string[])AccessTools.Property(objectMap.GetType(), "EnumNames").GetValue(objectMap);
|
||||
string[] xmlNames = (string[])AccessTools.Property(objectMap.GetType(), "XmlNames").GetValue(objectMap);
|
||||
for (int i = 0; i < enumNames.Length; i++)
|
||||
if (enumString == enumNames[i])
|
||||
{
|
||||
__result = xmlNames[i];
|
||||
return false;
|
||||
}
|
||||
|
||||
__result = null;
|
||||
}
|
||||
else
|
||||
__result = (string)AccessTools.Method(objectMap.GetType(), "GetXmlName").Invoke(objectMap, new[] { typeMap.TypeFullName, ob });
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue