Make patch logic more clearly
This commit is contained in:
parent
aac5f74f40
commit
4a29cceca7
|
@ -21,7 +21,7 @@ namespace StardewModdingAPI
|
|||
** Public
|
||||
****/
|
||||
/// <summary>SMAPI's current semantic version.</summary>
|
||||
public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.5.0.1", true);
|
||||
public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.6.0");
|
||||
|
||||
/// <summary>The minimum supported version of Stardew Valley.</summary>
|
||||
public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.4.5");
|
||||
|
|
|
@ -10,45 +10,16 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
|
|||
{
|
||||
public class Game1Methods : Game1
|
||||
{
|
||||
public static RainDrop[] rainDrops => (typeof(RainManager).GetField("_rainDropList", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(RainManager.Instance) as List<RainDrop>).ToArray();
|
||||
public static RainDrop[] RainDropsProp
|
||||
{
|
||||
get
|
||||
{
|
||||
return (typeof(RainManager).GetField("_rainDropList", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(RainManager.Instance) as List<RainDrop>).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static new IList<IClickableMenu> onScreenMenus => Game1.onScreenMenus;
|
||||
|
||||
public static bool IsRainingProp
|
||||
{
|
||||
get
|
||||
{
|
||||
return RainManager.Instance.isRaining;
|
||||
}
|
||||
set
|
||||
{
|
||||
RainManager.Instance.isRaining = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSnowingProp
|
||||
{
|
||||
get
|
||||
{
|
||||
return WeatherDebrisManager.Instance.isSnowing;
|
||||
}
|
||||
set
|
||||
{
|
||||
WeatherDebrisManager.Instance.isSnowing = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsDebrisWeatherProp
|
||||
{
|
||||
get
|
||||
{
|
||||
return WeatherDebrisManager.Instance.isDebrisWeather;
|
||||
}
|
||||
set
|
||||
{
|
||||
WeatherDebrisManager.Instance.isDebrisWeather = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateDebrisWeatherForMovement(List<WeatherDebris> debris)
|
||||
{
|
||||
WeatherDebrisManager.Instance.UpdateDebrisWeatherForMovement();
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
|
|||
{
|
||||
public class GameLocationMethods : GameLocation
|
||||
{
|
||||
|
||||
public void playSound(string audioName)
|
||||
{
|
||||
base.playSound(audioName, StardewValley.Network.NetAudio.SoundContext.Default);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using StardewModdingAPI.Framework.ModLoading.Finders;
|
||||
|
@ -10,52 +11,38 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
|||
/*********
|
||||
** Fields
|
||||
*********/
|
||||
/// <summary>The type whose field to which references should be rewritten.</summary>
|
||||
private readonly Type Type;
|
||||
|
||||
/// <summary>The type whose field to which references should be rewritten to.</summary>
|
||||
private readonly Type ToType;
|
||||
|
||||
/// <summary>The field name.</summary>
|
||||
private readonly string FieldName;
|
||||
|
||||
/// <summary>The property name.</summary>
|
||||
private readonly string PropertyName;
|
||||
private readonly string InstancePropertyName;
|
||||
|
||||
private readonly string TestName;
|
||||
|
||||
private readonly IMonitor Monitor;
|
||||
|
||||
private readonly bool UsingInstance;
|
||||
|
||||
private readonly bool RainDropFix;
|
||||
private readonly string TargetFieldName;
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="type">The type whose field to which references should be rewritten.</param>
|
||||
/// <param name="toType"></param>
|
||||
/// <param name="fieldName">The field name to rewrite.</param>
|
||||
/// <param name="propertyName">The property name (if different).</param>
|
||||
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, string propertyName, IMonitor monitor, string testName = null, bool usingInstance = true, bool rainDropFix = false)
|
||||
/// <param name="targetFieldName"></param>
|
||||
/// <param name="instancePropertyName">The property name (if different).</param>
|
||||
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, string targetFieldName = null, string instancePropertyName = null)
|
||||
: base(type.FullName, fieldName, InstructionHandleResult.None)
|
||||
{
|
||||
this.Monitor = monitor;
|
||||
this.Type = type;
|
||||
this.ToType = toType;
|
||||
this.FieldName = fieldName;
|
||||
this.PropertyName = propertyName;
|
||||
this.TestName = testName;
|
||||
this.UsingInstance = usingInstance;
|
||||
this.RainDropFix = rainDropFix;
|
||||
this.InstancePropertyName = instancePropertyName;
|
||||
if (targetFieldName == null)
|
||||
{
|
||||
this.TargetFieldName = fieldName;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.TargetFieldName = targetFieldName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="type">The type whose field to which references should be rewritten.</param>
|
||||
/// <param name="fieldName">The field name to rewrite.</param>
|
||||
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, IMonitor monitor, string testName = null, bool usingInstance = true, bool rainDropFix = false)
|
||||
: this(type, toType, fieldName, fieldName, monitor, testName, usingInstance, rainDropFix) { }
|
||||
|
||||
/// <summary>Perform the predefined logic for an instruction if applicable.</summary>
|
||||
/// <param name="module">The assembly module containing the instruction.</param>
|
||||
/// <param name="cil">The CIL processor.</param>
|
||||
|
@ -67,44 +54,90 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
|||
if (!this.IsMatch(instruction))
|
||||
return false;
|
||||
|
||||
try
|
||||
FieldInfo targetFieldInfo = this.ToType.GetField(this.TargetFieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
PropertyInfo targetPropertyInfo = null;
|
||||
if (targetFieldInfo == null)
|
||||
{
|
||||
if (this.TestName == null && !this.RainDropFix)
|
||||
targetPropertyInfo = this.ToType.GetProperty(this.TargetFieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
}
|
||||
if (this.InstancePropertyName != null)
|
||||
{
|
||||
MethodReference instanceMethod = module.ImportReference(this.ToType.GetMethod($"get_{this.InstancePropertyName}"));
|
||||
if (targetFieldInfo != null)
|
||||
{
|
||||
MethodReference method = module.ImportReference(this.ToType.GetMethod($"get_{this.PropertyName}"));
|
||||
FieldReference field = module.ImportReference(this.ToType.GetField(this.FieldName));
|
||||
|
||||
cil.InsertAfter(instruction, cil.Create(OpCodes.Ldfld, field));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, method));
|
||||
FieldReference targetField = module.ImportReference(targetFieldInfo);
|
||||
if (instruction.OpCode == OpCodes.Ldfld)
|
||||
{
|
||||
cil.Replace(instruction.Previous, cil.Create(OpCodes.Call, instanceMethod));
|
||||
replaceWith.Invoke(cil.Create(instruction.OpCode, targetField));
|
||||
}
|
||||
else if (instruction.OpCode == OpCodes.Stfld)
|
||||
{
|
||||
cil.Replace(instruction.Previous.Previous, cil.Create(OpCodes.Call, instanceMethod));
|
||||
replaceWith.Invoke(cil.Create(instruction.OpCode, targetField));
|
||||
}
|
||||
else if(instruction.OpCode == OpCodes.Ldsfld)
|
||||
{
|
||||
cil.InsertAfter(instruction, cil.Create(instruction.OpCode, targetField));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, instanceMethod));
|
||||
}
|
||||
else if (instruction.OpCode == OpCodes.Stsfld)
|
||||
{
|
||||
cil.InsertBefore(instruction.Previous, cil.Create(OpCodes.Call, instanceMethod));
|
||||
replaceWith.Invoke(cil.Create(instruction.OpCode, targetField));
|
||||
}
|
||||
}
|
||||
else if (this.TestName != null && this.UsingInstance && !this.RainDropFix)
|
||||
else if(targetPropertyInfo != null)
|
||||
{
|
||||
MethodReference method = module.ImportReference(this.ToType.GetMethod($"get_{this.PropertyName}"));
|
||||
MethodReference field = module.ImportReference(this.ToType.GetMethod($"get_{this.TestName}"));
|
||||
|
||||
cil.InsertAfter(instruction, cil.Create(OpCodes.Callvirt, field));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, method));
|
||||
}
|
||||
else if (this.RainDropFix && !this.UsingInstance)
|
||||
{
|
||||
MethodReference getter = module.ImportReference(this.ToType.GetMethod($"get_{this.FieldName}"));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, getter));
|
||||
if (instruction.OpCode == OpCodes.Ldfld)
|
||||
{
|
||||
cil.Replace(instruction.Previous, cil.Create(OpCodes.Call, instanceMethod));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, module.ImportReference(targetPropertyInfo.GetGetMethod())));
|
||||
}
|
||||
else if (instruction.OpCode == OpCodes.Stfld)
|
||||
{
|
||||
cil.Replace(instruction.Previous.Previous, cil.Create(OpCodes.Call, instanceMethod));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, module.ImportReference(targetPropertyInfo.GetSetMethod())));
|
||||
}
|
||||
else if(instruction.OpCode == OpCodes.Ldsfld)
|
||||
{
|
||||
cil.InsertAfter(instruction, cil.Create(OpCodes.Call, module.ImportReference(targetPropertyInfo.GetGetMethod())));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, instanceMethod));
|
||||
}
|
||||
else if (instruction.OpCode == OpCodes.Stsfld)
|
||||
{
|
||||
cil.InsertBefore(instruction.Previous, cil.Create(OpCodes.Call, instanceMethod));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, module.ImportReference(targetPropertyInfo.GetSetMethod())));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodReference method = module.ImportReference(this.Type.GetMethod($"get_{this.FieldName}"));
|
||||
MethodReference field = module.ImportReference(this.ToType.GetMethod($"get_{this.TestName}"));
|
||||
|
||||
cil.InsertAfter(instruction, cil.Create(OpCodes.Callvirt, field));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, method));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
this.Monitor.Log(e.Message);
|
||||
this.Monitor.Log(e.StackTrace);
|
||||
if (targetFieldInfo != null)
|
||||
{
|
||||
FieldReference targetField = module.ImportReference(targetFieldInfo);
|
||||
replaceWith.Invoke(cil.Create(instruction.OpCode, targetField));
|
||||
}
|
||||
else if (targetPropertyInfo != null)
|
||||
{
|
||||
if (instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Ldsfld)
|
||||
{
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, module.ImportReference(targetPropertyInfo.GetGetMethod())));
|
||||
}
|
||||
else
|
||||
{
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, module.ImportReference(targetPropertyInfo.GetSetMethod())));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.MarkRewritten();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
|||
/// <summary>The property name.</summary>
|
||||
private readonly string PropertyName;
|
||||
|
||||
/// <summary>The property name.</summary>
|
||||
private readonly string InstancePropertyName;
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
|
@ -23,11 +26,12 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
|||
/// <param name="type">The type whose field to which references should be rewritten.</param>
|
||||
/// <param name="fieldName">The field name to rewrite.</param>
|
||||
/// <param name="propertyName">The property name (if different).</param>
|
||||
public TypeFieldToAnotherTypePropertyRewriter(Type type, Type toType, string fieldName, string propertyName)
|
||||
public TypeFieldToAnotherTypePropertyRewriter(Type type, Type toType, string fieldName, string propertyName, string instancePropertyName = null)
|
||||
: base(type.FullName, fieldName, InstructionHandleResult.None)
|
||||
{
|
||||
this.ToType = toType;
|
||||
this.PropertyName = propertyName;
|
||||
this.InstancePropertyName = instancePropertyName;
|
||||
}
|
||||
|
||||
/// <summary>Perform the predefined logic for an instruction if applicable.</summary>
|
||||
|
@ -43,13 +47,33 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
|
|||
|
||||
if (instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Ldsfld)
|
||||
{
|
||||
MethodReference methodRef = module.ImportReference(this.ToType.GetProperty(this.PropertyName).GetGetMethod());
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, methodRef));
|
||||
if (this.InstancePropertyName == null)
|
||||
{
|
||||
MethodReference methodRef = module.ImportReference(this.ToType.GetProperty(this.PropertyName).GetGetMethod());
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, methodRef));
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodReference instanceMethodRef = module.ImportReference(this.ToType.GetProperty(this.InstancePropertyName).GetGetMethod());
|
||||
MethodReference methodRef = module.ImportReference(this.ToType.GetProperty(this.PropertyName).GetGetMethod());
|
||||
cil.InsertAfter(instruction, cil.Create(OpCodes.Call, methodRef));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, instanceMethodRef));
|
||||
}
|
||||
}
|
||||
else if (instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld)
|
||||
{
|
||||
MethodReference methodRef = module.ImportReference(this.ToType.GetProperty(this.PropertyName).GetSetMethod());
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, methodRef));
|
||||
if (this.InstancePropertyName == null)
|
||||
{
|
||||
MethodReference methodRef = module.ImportReference(this.ToType.GetProperty(this.PropertyName).GetSetMethod());
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, methodRef));
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodReference instanceMethodRef = module.ImportReference(this.ToType.GetProperty(this.InstancePropertyName).GetGetMethod());
|
||||
MethodReference methodRef = module.ImportReference(this.ToType.GetProperty(this.PropertyName).GetSetMethod());
|
||||
cil.InsertAfter(instruction, cil.Create(OpCodes.Call, methodRef));
|
||||
replaceWith.Invoke(cil.Create(OpCodes.Call, instanceMethodRef));
|
||||
}
|
||||
}
|
||||
return this.MarkRewritten();
|
||||
}
|
||||
|
|
|
@ -46,18 +46,14 @@ namespace StardewModdingAPI.Metadata
|
|||
if (platformChanged)
|
||||
yield return new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchFacade));
|
||||
|
||||
//isRaining and isDebrisWeather fix done.
|
||||
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isRaining", "IsRainingProp");
|
||||
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isSnowing", "IsSnowingProp");
|
||||
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isDebrisWeather", "IsDebrisWeatherProp");
|
||||
|
||||
// Cause of System.Security.VerificationException : Invalid instruction target
|
||||
//yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(RainManager), "isRaining", "Instance", this.Monitor);
|
||||
//yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(WeatherDebrisManager), "isDebrisWeather", "Instance", this.Monitor);
|
||||
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(GameLocation), typeof(DebrisManager), "debris", "Instance", this.Monitor, "debrisNetCollection", false);
|
||||
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(WeatherDebrisManager), "debrisWeather", "Instance", this.Monitor, "weatherDebrisList");
|
||||
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(Game1Methods), "rainDrops", "Instance", this.Monitor, null, false, true);
|
||||
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(Game1Methods), "onScreenMenus", "", this.Monitor, null, false, true);
|
||||
// Redirect reference
|
||||
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(RainManager), "isRaining", "isRaining", "Instance");
|
||||
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(WeatherDebrisManager), "isSnowing", "isSnowing", "Instance");
|
||||
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(WeatherDebrisManager), "isDebrisWeather", "isDebrisWeather", "Instance");
|
||||
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "rainDrops", "RainDropsProp");
|
||||
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(GameLocation), typeof(DebrisManager), "debris", "debrisNetCollection", "Instance");
|
||||
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(WeatherDebrisManager), "debrisWeather","weatherDebrisList", "Instance");
|
||||
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "onScreenMenus", "onScreenMenus");
|
||||
|
||||
yield return new PropertyToFieldRewriter(typeof(Game1), "toolSpriteSheet", "toolSpriteSheet");
|
||||
|
||||
|
|
|
@ -69,7 +69,6 @@ namespace StardewModdingAPI.Patches
|
|||
try
|
||||
{
|
||||
Netcode.NetGuid guid = new Netcode.NetGuid(Game1.getFarm().buildings.GuidOf(myHome));
|
||||
Netcode.INetSerializable netFields = guid.NetFields;
|
||||
AccessTools.Field(typeof(JunimoHarvester), "netHome").SetValue(__instance, guid);
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="TMXTile">
|
||||
<HintPath>..\..\..\..\..\..\..\SteamLibrary\steamapps\common\Stardew Valley\smapi-internal\TMXTile.dll</HintPath>
|
||||
<HintPath>..\Loader\libs\TMXTile.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xTile">
|
||||
<HintPath>..\..\..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\xTile.dll</HintPath>
|
||||
|
|
|
@ -42,6 +42,8 @@ namespace StardewModdingAPI
|
|||
|
||||
public static SMainActivity Instance;
|
||||
|
||||
private static bool ErrorDetected;
|
||||
|
||||
public new bool HasPermissions
|
||||
{
|
||||
get
|
||||
|
@ -102,7 +104,14 @@ namespace StardewModdingAPI
|
|||
try
|
||||
{
|
||||
File errorLog = this.FilesDir.ListFiles().FirstOrDefault(f => f.IsDirectory && f.Name == "error")?.ListFiles().FirstOrDefault(f => f.Name.EndsWith(".dat"));
|
||||
SAlertDialogUtil.AlertMessage(System.IO.File.ReadAllText(errorLog.AbsolutePath), "Crash Detected");
|
||||
if (errorLog != null)
|
||||
{
|
||||
SMainActivity.ErrorDetected = true;
|
||||
SAlertDialogUtil.AlertMessage(System.IO.File.ReadAllText(errorLog.AbsolutePath), "Crash Detected", callback: (type =>
|
||||
{
|
||||
SMainActivity.ErrorDetected = false;
|
||||
}));
|
||||
}
|
||||
Type[] services = {typeof(Microsoft.AppCenter.Analytics.Analytics), typeof(Microsoft.AppCenter.Crashes.Crashes)};
|
||||
AppCenter.Start(Constants.MicrosoftAppSecret, services);
|
||||
AppCenter.SetUserId(Constants.ApiVersion.ToString());
|
||||
|
@ -124,6 +133,16 @@ namespace StardewModdingAPI
|
|||
{
|
||||
game1.Exit();
|
||||
}
|
||||
|
||||
if (SMainActivity.ErrorDetected)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
SMainActivity.Instance.RunOnUiThread(() => this.OnCreatePartTwo());
|
||||
}).Start();
|
||||
return;
|
||||
}
|
||||
new SGameConsole();
|
||||
|
||||
Program.Main(null);
|
||||
|
|
Loading…
Reference in New Issue