summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/MethodWithMissingOptionalParameterRewriter.cs40
1 files changed, 36 insertions, 4 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/MethodWithMissingOptionalParameterRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/MethodWithMissingOptionalParameterRewriter.cs
index 9db3c3fd..75182890 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/MethodWithMissingOptionalParameterRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/MethodWithMissingOptionalParameterRewriter.cs
@@ -68,14 +68,28 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
if (method == null)
return false;
- // add extra parameters
- foreach (ParameterDefinition parameter in method.Parameters.Skip(methodRef.Parameters.Count))
+ // get instructions to inject
+ var injectables = method.Parameters.Skip(methodRef.Parameters.Count)
+ .Select(p => new { Parameter = p, LoadValueInstruction = this.GetLoadValueInstruction(p.Constant) })
+ .ToArray();
+ if (injectables.Any(p => p.LoadValueInstruction == null))
+ return false; // SMAPI needs to load the value onto the stack before the method call, but the optional parameter type wasn't recognized
+
+ // inject new parameters
+ foreach (var entry in injectables)
{
- methodRef.Parameters.Add(new ParameterDefinition(
+ // load value onto stack
+ cil.InsertBefore(instruction, entry.LoadValueInstruction);
+
+ // add parameter
+ ParameterDefinition parameter = entry.Parameter;
+ var newParameter = new ParameterDefinition(
name: parameter.Name,
attributes: parameter.Attributes,
parameterType: module.ImportReference(parameter.ParameterType)
- ));
+ );
+ newParameter.Constant = parameter.Constant;
+ methodRef.Parameters.Add(newParameter);
}
this.Phrases.Add($"{methodRef.DeclaringType.Name}.{methodRef.Name} (added missing optional parameters)");
@@ -109,5 +123,23 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
return true;
}
+
+ /// <summary>Get the CIL instruction to load a value onto the stack.</summary>
+ /// <param name="rawValue">The constant value to inject.</param>
+ /// <returns>Returns the instruction, or <c>null</c> if the value type isn't supported.</returns>
+ private Instruction GetLoadValueInstruction(object rawValue)
+ {
+ return rawValue switch
+ {
+ null => Instruction.Create(OpCodes.Ldnull),
+ bool value => Instruction.Create(value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0),
+ int value => Instruction.Create(OpCodes.Ldc_I4, value), // int32
+ long value => Instruction.Create(OpCodes.Ldc_I8, value), // int64
+ float value => Instruction.Create(OpCodes.Ldc_R4, value), // float32
+ double value => Instruction.Create(OpCodes.Ldc_R8, value), // float64
+ string value => Instruction.Create(OpCodes.Ldstr, value),
+ _ => null
+ };
+ }
}
}