Further work on getting MSIL Injection in. Next step is to overwrite the constructor for Game1 and redirect it to SGame

This commit is contained in:
ClxS 2016-03-09 22:11:57 +00:00
parent 608a5cb257
commit 792cfcd796
5 changed files with 63 additions and 28 deletions

View File

@ -48,13 +48,12 @@ namespace StardewModdingAPI.Helpers
public CecilContext(CecilContextType contextType)
{
ContextType = contextType;
if (ContextType == CecilContextType.SMAPI)
_assemblyDefinition = AssemblyDefinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);
else
_assemblyDefinition = AssemblyDefinition.ReadAssembly(Constants.StardewExePath);
}
public ILProcessor GetMethodILProcessor(string type, string method)
{
if (_assemblyDefinition == null)
@ -64,7 +63,7 @@ namespace StardewModdingAPI.Helpers
throw new ArgumentNullException("Both type and method must be set");
Mono.Cecil.Cil.ILProcessor ilProcessor = null;
TypeDefinition typeDef = _assemblyDefinition.MainModule.Types.FirstOrDefault(n => n.FullName == type);
TypeDefinition typeDef = GetTypeDefinition(type);
if (typeDef != null)
{
MethodDefinition methodDef = typeDef.Methods.FirstOrDefault(m => m.Name == method);
@ -77,6 +76,31 @@ namespace StardewModdingAPI.Helpers
return ilProcessor;
}
public TypeDefinition GetTypeDefinition(string type)
{
if (_assemblyDefinition == null)
throw new Exception("ERROR Assembly not properly read. Cannot parse");
if (string.IsNullOrWhiteSpace(type))
throw new ArgumentNullException("Both type and method must be set");
TypeDefinition typeDef = _assemblyDefinition.MainModule.Types.FirstOrDefault(n => n.FullName == type);
return typeDef;
}
public MethodDefinition GetMethodDefinition(string type, string method)
{
MethodDefinition methodDef = null;
TypeDefinition typeDef = GetTypeDefinition(type);
if (typeDef != null)
{
methodDef = typeDef.Methods.FirstOrDefault(m => m.Name == method);
}
return methodDef;
}
public MethodInfo GetSMAPIMethodReference(string type, string method)
{
if (_assemblyDefinition == null)

View File

@ -11,7 +11,8 @@ namespace StardewModdingAPI.Helpers
{
public static class CecilHelper
{
//System.Void StardewValley.Game1::.ctor()
private static void InjectMethod(ILProcessor ilProcessor, Instruction target, MethodReference method)
{
Instruction callEnterInstruction = ilProcessor.Create(OpCodes.Call, method);
@ -26,6 +27,13 @@ namespace StardewModdingAPI.Helpers
}
}
// public void ReplaceInstruction(ILProcessor processor, OpCode opcode, string oldOperand, string newOperand)
//{
//var instructions = processor.Body.Instructions.Where(i => i.OpCode == opcode && i.Operand == oldOperand);
// processor.Create()
//}
public static void InjectEntryMethod(CecilContext stardewContext, CecilContext smapiContext, string injecteeType, string injecteeMethod,
string injectedType, string injectedMethod)
{

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StardewModdingAPI.Helpers
{
public static class ReflectionHelper
{
}
}

View File

@ -72,7 +72,11 @@ namespace StardewModdingAPI
private static void ConfigureMethodInjection()
{
StardewContext = new CecilContext(CecilContextType.Stardew);
//SmapiContext = new CecilContext(CecilContextType.SMAPI);
SmapiContext = new CecilContext(CecilContextType.SMAPI);
//StardewContext.ReplaceMethodInstruction(OpCodes.Newobj, "System.Void StardewValley.Game1::.ctor()")
var test = StardewContext.GetMethodILProcessor("StardewValley.Program", "Main");
StardewContext.GetTypeDefinition("StardewValley.Game1");
}
private static void WeaveOnEnterMethod(Mono.Cecil.Cil.ILProcessor ilProcessor, Instruction target, MethodReference callback)
@ -143,11 +147,11 @@ namespace StardewModdingAPI
StardewModdingAPI.Log.Info("Initializing SDV Assembly...");
// Load in the assembly - ignores security
//StardewAssembly = Assembly.UnsafeLoadFrom(Constants.ExecutionPath + "\\Stardew Valley.exe");
StardewAssembly = Assembly.Load(StardewContext.ModifiedAssembly.GetBuffer());
StardewAssembly = Assembly.UnsafeLoadFrom(Constants.ExecutionPath + "\\Stardew Valley.exe");
//StardewAssembly = Assembly.Load(StardewContext.ModifiedAssembly.GetBuffer());
StardewProgramType = StardewAssembly.GetType("StardewValley.Program", true);
StardewGameInfo = StardewProgramType.GetField("gamePtr");
// Change the game's version
StardewModdingAPI.Log.Verbose("Injecting New SDV Version...");
Game1.version += string.Format("-Z_MODDED | SMAPI {0}", Constants.VersionString);
@ -252,26 +256,11 @@ namespace StardewModdingAPI
StardewForm = Control.FromHandle(Program.gamePtr.Window.Handle).FindForm();
StardewForm.Closing += StardewForm_Closing;
ready = true;
StardewGameInfo.SetValue(StardewProgramType, gamePtr);
gamePtr.Run();
#region deprecated
if (false)
{
//Nope, I can't get it to work. I depend on Game1 being an SGame, and can't cast a parent to a child
//I'm leaving this here in case the community is interested
//StardewInjectorMod.Entry(true);
Type gt = StardewAssembly.GetType("StardewValley.Game1", true);
gamePtr = (SGame)Activator.CreateInstance(gt);
ready = true;
StardewGameInfo.SetValue(StardewProgramType, gamePtr);
gamePtr.Run();
}
#endregion
ready = true;
StardewAssembly.EntryPoint.Invoke(null, new object[] { new string[] { } });
//StardewGameInfo.SetValue(StardewProgramType, gamePtr);
gamePtr.Run();
}
catch (Exception ex)
{

View File

@ -145,6 +145,7 @@
<Compile Include="Extensions.cs" />
<Compile Include="Helpers\CecilContext.cs" />
<Compile Include="Helpers\CecilHelper.cs" />
<Compile Include="Helpers\ReflectionHelper.cs" />
<Compile Include="Inheritance\ItemStackChange.cs" />
<Compile Include="Inheritance\Menus\SBobberBar.cs" />
<Compile Include="Inheritance\Menus\SGameMenu.cs" />