summaryrefslogtreecommitdiff
path: root/StardewInjector
diff options
context:
space:
mode:
authorClxS <slxxls92@gmail.com>2016-03-03 20:17:40 +0000
committerClxS <slxxls92@gmail.com>2016-03-03 20:17:40 +0000
commitf77e922ad08078586b1c67f0d88f68b054364434 (patch)
tree176788af61d48b689e98a9a0fdc1facff1eab242 /StardewInjector
parentd3f0e00db9946d1b509f0ad72f9a51095c190f9f (diff)
parent9a1b910ea32f518b605c88315f192afc6fc40f28 (diff)
downloadSMAPI-f77e922ad08078586b1c67f0d88f68b054364434.tar.gz
SMAPI-f77e922ad08078586b1c67f0d88f68b054364434.tar.bz2
SMAPI-f77e922ad08078586b1c67f0d88f68b054364434.zip
Merged Zoryn4163/master into master
Diffstat (limited to 'StardewInjector')
-rw-r--r--StardewInjector/App.config15
-rw-r--r--StardewInjector/CecilUtils.cs173
-rw-r--r--StardewInjector/Config.cs72
-rw-r--r--StardewInjector/Program.cs30
-rw-r--r--StardewInjector/Properties/AssemblyInfo.cs36
-rw-r--r--StardewInjector/StardewHooker.cs190
-rw-r--r--StardewInjector/StardewInjector.cs55
-rw-r--r--StardewInjector/StardewInjector.csproj77
-rw-r--r--StardewInjector/bin/Debug/Lidgren.Network.dllbin0 -> 123904 bytes
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.dllbin0 -> 74752 bytes
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.xml625
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.Graphics.dllbin0 -> 427520 bytes
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.Graphics.xml3431
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.Xact.dllbin0 -> 75776 bytes
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.Xact.xml283
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.dllbin0 -> 679424 bytes
-rw-r--r--StardewInjector/bin/Debug/Microsoft.Xna.Framework.xml7375
-rw-r--r--StardewInjector/bin/Debug/Mono.Cecil.dllbin0 -> 280576 bytes
-rw-r--r--StardewInjector/bin/Debug/Stardew Valley.exebin0 -> 2185728 bytes
-rw-r--r--StardewInjector/bin/Debug/StardewInjector.dllbin0 -> 17408 bytes
-rw-r--r--StardewInjector/bin/Debug/StardewInjector.dll.config15
-rw-r--r--StardewInjector/bin/Debug/StardewInjector.pdbbin0 -> 38400 bytes
-rw-r--r--StardewInjector/bin/Debug/StardewModdingAPI.exebin0 -> 68096 bytes
-rw-r--r--StardewInjector/bin/Debug/StardewModdingAPI.pdbbin0 -> 153088 bytes
-rw-r--r--StardewInjector/bin/Debug/Steamworks.NET.dllbin0 -> 249856 bytes
-rw-r--r--StardewInjector/bin/Debug/steam_appid.txt1
-rw-r--r--StardewInjector/bin/Debug/xTile.dllbin0 -> 157696 bytes
-rw-r--r--StardewInjector/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cachebin0 -> 7182 bytes
-rw-r--r--StardewInjector/obj/Debug/StardewInjector.csproj.FileListAbsolute.txt37
-rw-r--r--StardewInjector/obj/Debug/StardewInjector.csprojResolveAssemblyReference.cachebin0 -> 59508 bytes
-rw-r--r--StardewInjector/obj/Debug/StardewInjector.dllbin0 -> 17408 bytes
-rw-r--r--StardewInjector/obj/Debug/StardewInjector.pdbbin0 -> 38400 bytes
-rw-r--r--StardewInjector/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs0
-rw-r--r--StardewInjector/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs0
-rw-r--r--StardewInjector/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs0
-rw-r--r--StardewInjector/packages.config4
36 files changed, 12419 insertions, 0 deletions
diff --git a/StardewInjector/App.config b/StardewInjector/App.config
new file mode 100644
index 00000000..f1914205
--- /dev/null
+++ b/StardewInjector/App.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <appSettings>
+ <add key="RunSpeed" value="0"/>
+ <add key="EnableTweakedDiagonalMovement" value="False"/>
+ <add key="EnableEasyFishing" value="False"/>
+ <add key="EnableAlwaysSpawnFishingBubble" value="False"/>
+ <add key="SecondsPerTenMinutes" value="7"/>
+ <add key="EnableDebugMode" value="False"/>
+
+ </appSettings>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
+ </startup>
+</configuration>
diff --git a/StardewInjector/CecilUtils.cs b/StardewInjector/CecilUtils.cs
new file mode 100644
index 00000000..acdf5198
--- /dev/null
+++ b/StardewInjector/CecilUtils.cs
@@ -0,0 +1,173 @@
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace StardewInjector
+{
+ public struct ScannerState
+ {
+ public ILProcessor ILProcessor;
+ public Instruction Instruction;
+
+ public ScannerState(ILProcessor ilProc, Instruction ins)
+ {
+ ILProcessor = ilProc;
+ Instruction = ins;
+ }
+
+ public ScannerState Previous(Func<Instruction, bool> until = null)
+ {
+ if (until != null)
+ {
+ Instruction cur = this.Instruction;
+ do
+ {
+ cur = cur.Previous;
+ } while (!until(cur));
+ return new ScannerState(this.ILProcessor, cur);
+ }
+ return new ScannerState(this.ILProcessor, Instruction.Previous);
+ }
+
+ public ScannerState Next(Func<Instruction, bool> until = null)
+ {
+ if (until != null)
+ {
+ Instruction cur = this.Instruction;
+ do
+ {
+ cur = cur.Next;
+ } while (!until(cur));
+ return new ScannerState(this.ILProcessor, cur);
+ }
+ return new ScannerState(this.ILProcessor, Instruction.Next);
+ }
+
+ public ScannerState Last()
+ {
+ var instructions = this.ILProcessor.Body.Instructions;
+ return new ScannerState(this.ILProcessor, instructions[instructions.Count - 1]);
+ }
+
+ public ScannerState First()
+ {
+ var instructions = this.ILProcessor.Body.Instructions;
+ return new ScannerState(this.ILProcessor, instructions[0]);
+ }
+
+ public ScannerState ReplaceCreate(OpCode opcode)
+ {
+ Instruction ins = this.ILProcessor.Create(opcode);
+ this.ILProcessor.Replace(this.Instruction, ins);
+ return new ScannerState(this.ILProcessor, ins);
+ }
+
+ public ScannerState ReplaceCreate(OpCode opcode, object arg)
+ {
+ Instruction ins = this.ILProcessor.Create(opcode, arg as dynamic);
+ this.ILProcessor.Replace(this.Instruction, ins);
+ return new ScannerState(this.ILProcessor, ins);
+ }
+
+ public ScannerState CreateBefore(OpCode opcode)
+ {
+ Instruction ins = this.ILProcessor.Create(opcode);
+ this.ILProcessor.InsertBefore(this.Instruction, ins);
+ return new ScannerState(this.ILProcessor, ins);
+ }
+
+ public ScannerState CreateBefore(OpCode opcode, object arg)
+ {
+ Instruction ins = this.ILProcessor.Create(opcode, arg as dynamic);
+ this.ILProcessor.InsertBefore(this.Instruction, ins);
+ return new ScannerState(this.ILProcessor, ins);
+ }
+
+ public ScannerState CreateAfter(OpCode opcode)
+ {
+ Instruction ins = this.ILProcessor.Create(opcode);
+ this.ILProcessor.InsertAfter(this.Instruction, ins);
+ return new ScannerState(this.ILProcessor, ins);
+ }
+
+ public ScannerState CreateAfter(OpCode opcode, object arg)
+ {
+ Instruction ins = this.ILProcessor.Create(opcode, arg as dynamic);
+ this.ILProcessor.InsertAfter(this.Instruction, ins);
+ return new ScannerState(this.ILProcessor, ins);
+ }
+ }
+
+ public static class CecilUtils
+ {
+ public static ScannerState Scanner(this MethodDefinition me)
+ {
+ return new ScannerState(me.Body.GetILProcessor(), me.Body.Instructions[0]);
+ }
+
+ public static ScannerState FindSetField(this MethodDefinition me, string fieldName)
+ {
+ var instruction = me.Body.Instructions
+ .FirstOrDefault(i => i.OpCode == OpCodes.Stsfld && (i.Operand as FieldDefinition).Name == fieldName);
+ return new ScannerState(me.Body.GetILProcessor(), instruction);
+ }
+
+ public static ScannerState FindLoadField(this MethodDefinition me, string fieldName)
+ {
+ var instruction = me.Body.Instructions
+ .FirstOrDefault(i => {
+ if (i.OpCode != OpCodes.Ldfld && i.OpCode != OpCodes.Ldsfld)
+ return false;
+ if (i.Operand is FieldDefinition && (i.Operand as FieldDefinition).Name == fieldName)
+ return true;
+ if (i.Operand is FieldReference && (i.Operand as FieldReference).Name == fieldName)
+ return true;
+ return false;
+ });
+ return new ScannerState(me.Body.GetILProcessor(), instruction);
+ }
+
+ public static ScannerState FindLoadConstant(this MethodDefinition me, int val)
+ {
+ var instruction = me.Body.Instructions
+ .FirstOrDefault(i => i.OpCode == OpCodes.Ldc_I4 && (int)i.Operand == val);
+ return new ScannerState(me.Body.GetILProcessor(), instruction);
+ }
+
+ public static ScannerState FindLoadConstant(this MethodDefinition me, float val)
+ {
+ var instruction = me.Body.Instructions
+ .FirstOrDefault(i => i.OpCode == OpCodes.Ldc_R4 && (float)i.Operand == val);
+ return new ScannerState(me.Body.GetILProcessor(), instruction);
+ }
+
+ public static MethodDefinition FindMethod(this ModuleDefinition me, string name)
+ {
+ var nameSplit = name.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
+ if (nameSplit.Length < 2)
+ throw new ArgumentException("Invalid method full name", "name");
+
+ var currentType = me.Types.FirstOrDefault(t => t.FullName == nameSplit[0]);
+ if (currentType == null)
+ return null;
+
+ return currentType.Methods.FirstOrDefault(m => m.Name == nameSplit[1]);
+ }
+
+ public static FieldDefinition FindField(this ModuleDefinition me, string name)
+ {
+ var nameSplit = name.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
+ if (nameSplit.Length < 2)
+ throw new ArgumentException("Invalid field full name", "name");
+
+ var currentType = me.Types.FirstOrDefault(t => t.FullName == nameSplit[0]);
+ if (currentType == null)
+ return null;
+
+ return currentType.Fields.FirstOrDefault(m => m.Name == nameSplit[1]);
+ }
+ }
+}
diff --git a/StardewInjector/Config.cs b/StardewInjector/Config.cs
new file mode 100644
index 00000000..cea45e98
--- /dev/null
+++ b/StardewInjector/Config.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Text;
+
+namespace StardewInjector
+{
+ public static class Config
+ {
+ public static bool EnableDebugMode
+ {
+ get
+ {
+ bool val = false;
+ bool.TryParse(ConfigurationManager.AppSettings["EnableDebugMode"], out val);
+ return val;
+ }
+ }
+
+ public static bool EnableAlwaysSpawnFishingBubble
+ {
+ get
+ {
+ bool val = false;
+ bool.TryParse(ConfigurationManager.AppSettings["EnableAlwaysSpawnFishingBubble"], out val);
+ return val;
+ }
+ }
+
+ public static bool EnableEasyFishing
+ {
+ get
+ {
+ bool val = false;
+ bool.TryParse(ConfigurationManager.AppSettings["EnableEasyFishing"], out val);
+ return val;
+ }
+ }
+
+ public static int SecondsPerTenMinutes
+ {
+ get
+ {
+ int val = 7;
+ int.TryParse(ConfigurationManager.AppSettings["SecondsPerTenMinutes"], out val);
+ return val;
+ }
+ }
+
+ public static float RunSpeed
+ {
+ get
+ {
+ float val = 1f;
+ float.TryParse(ConfigurationManager.AppSettings["RunSpeed"], out val);
+ return val;
+ }
+ }
+
+ public static bool EnableTweakedDiagonalMovement
+ {
+ get
+ {
+ bool val = false;
+ bool.TryParse(ConfigurationManager.AppSettings["EnableTweakedDiagonalMovement"], out val);
+ return val;
+ }
+ }
+
+ }
+}
diff --git a/StardewInjector/Program.cs b/StardewInjector/Program.cs
new file mode 100644
index 00000000..41c72240
--- /dev/null
+++ b/StardewInjector/Program.cs
@@ -0,0 +1,30 @@
+/*
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Stardew_Injector
+{
+ class Program
+ {
+
+ private static Stardew_Hooker hooker = new Stardew_Hooker();
+
+ static void Main(string[] args)
+ {
+ hooker.Initialize();
+ hooker.ApplyHooks();
+ hooker.Finalize();
+
+ hooker.Run();
+ Console.ReadLine();
+ }
+
+ }
+}
+*/ \ No newline at end of file
diff --git a/StardewInjector/Properties/AssemblyInfo.cs b/StardewInjector/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..0ba4aafe
--- /dev/null
+++ b/StardewInjector/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("StardewInjector")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("StardewInjector")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("820406dc-ae78-461f-8c7f-6329f34f986c")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/StardewInjector/StardewHooker.cs b/StardewInjector/StardewHooker.cs
new file mode 100644
index 00000000..a92b96c1
--- /dev/null
+++ b/StardewInjector/StardewHooker.cs
@@ -0,0 +1,190 @@
+using Microsoft.Xna.Framework;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using StardewModdingAPI;
+
+namespace StardewInjector
+{
+ public class Stardew_Hooker
+ {
+ private AssemblyDefinition m_vAsmDefinition = null;
+ private ModuleDefinition m_vModDefinition = null;
+ private Assembly m_vAssembly = null;
+
+ public bool Initialize()
+ {
+ Console.WriteLine("Initiating StarDew_Injector....");
+ try
+ {
+ this.m_vAsmDefinition = AssemblyDefinition.ReadAssembly(@"Stardew Valley.exe");
+ this.m_vModDefinition = this.m_vAsmDefinition.MainModule;
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Program.LogError(ex);
+ return false;
+ }
+ }
+
+ public bool Finalize()
+ {
+ Console.WriteLine("Finalizing StarDew_Injector....");
+ try
+ {
+ if (this.m_vAsmDefinition == null)
+ return false;
+
+ using (MemoryStream mStream = new MemoryStream())
+ {
+ // Write the edited data to the memory stream..
+ this.m_vAsmDefinition.Write(mStream);
+
+ // Load the new assembly from the memory stream buffer..
+ this.m_vAssembly = Assembly.Load(mStream.GetBuffer());
+
+ Program.StardewAssembly = m_vAssembly;
+
+ return true;
+ }
+ }
+ catch (Exception ex)
+ {
+ Program.LogError(ex);
+ return false;
+ }
+ }
+
+ public bool Run()
+ {
+ if (this.m_vAssembly == null)
+ return false;
+
+ Console.WriteLine("Starting Stardew Valley...");
+
+ m_vAssembly.EntryPoint.Invoke(null, new object[] {new string[0]});
+
+ return true;
+ }
+
+ public void ApplyHooks()
+ {
+ Console.WriteLine("Applying StarDew_Injector....");
+ try
+ {
+ InjectMovementSpeed();
+
+ if (Config.SecondsPerTenMinutes != 7)
+ InjectClockScale();
+
+ if (Config.EnableEasyFishing)
+ InjectEasyFishing();
+
+ if (Config.EnableAlwaysSpawnFishingBubble)
+ InjectMoreBubbles();
+
+ /*
+ if (Config.EnableDebugMode)
+ InjectDebugMode();
+ */
+ }
+ catch (Exception ex)
+ {
+ Program.LogError(ex);
+ }
+
+ }
+
+ private void InjectDebugMode()
+ {
+ this.m_vModDefinition.FindMethod("StardewValley.Program::.cctor")
+ .FindSetField("releaseBuild").Previous()
+ .ReplaceCreate(OpCodes.Ldc_I4_0);
+
+ Console.WriteLine("Enabled debug mode.");
+ }
+
+ private void InjectMoreBubbles()
+ {
+ this.m_vModDefinition.FindMethod("StardewValley.GameLocation::performTenMinuteUpdate")
+ .FindLoadField("currentLocation").Next(i => i.ToString().Contains("NextDouble")).Next()
+ .ReplaceCreate(OpCodes.Ldc_R8, 1.1);
+
+ Console.WriteLine("Forced each area to always spawn a fishing bubble.");
+ }
+
+ private void InjectEasyFishing()
+ {
+ this.m_vModDefinition.FindMethod("StardewValley.Menus.BobberBar::update")
+ .FindLoadConstant(694)
+ .Next(i => i.OpCode == OpCodes.Ldc_R4)
+ .ReplaceCreate(OpCodes.Ldc_R4, 0.001f)
+ .Next(i => i.OpCode == OpCodes.Ldc_R4)
+ .ReplaceCreate(OpCodes.Ldc_R4, 0.001f);
+
+ Console.WriteLine("Replaced fish escape constants for all bobbers & bobber id 694 with 0.001, slowing it down.");
+ }
+
+ private void InjectClockScale()
+ {
+ int timeScale = Config.SecondsPerTenMinutes;
+ timeScale *= 1000;
+
+ this.m_vModDefinition.FindMethod("StardewValley.Game1::UpdateGameClock")
+ .FindLoadConstant(7000f)
+ .ReplaceCreate(OpCodes.Ldc_R4, timeScale*1.0f)
+ .Next(i => i.OpCode == OpCodes.Ldc_R4 && (float) i.Operand == 7000f)
+ .ReplaceCreate(OpCodes.Ldc_R4, timeScale*1.0f)
+ .Next(i => i.OpCode == OpCodes.Ldc_I4 && (int) i.Operand == 7000)
+ .ReplaceCreate(OpCodes.Ldc_I4, timeScale);
+
+ Console.WriteLine("Updated lighting for new timescale ({0}).", timeScale);
+ }
+
+ private void InjectMovementSpeed()
+ {
+
+
+ if (Config.EnableTweakedDiagonalMovement)
+ {
+ this.m_vModDefinition.FindMethod("StardewValley.Farmer::getMovementSpeed")
+ .FindLoadField("movementDirections").Next(i => i.OpCode == OpCodes.Ldc_I4_1)
+ .ReplaceCreate(OpCodes.Ldc_I4_4);
+
+ Console.WriteLine("Removed diagonal movement check.");
+ }
+
+ if (Config.RunSpeed > 0)
+ {
+ this.m_vModDefinition.FindMethod("StardewValley.Farmer::getMovementSpeed")
+ .FindLoadField("movementDirections").Last().CreateBefore(OpCodes.Ldc_R4, (float) Config.RunSpeed).CreateAfter(OpCodes.Add);
+
+ Console.WriteLine("Added run speed: " + Config.RunSpeed);
+ }
+
+
+ }
+
+
+
+ private void DumpInstructionsToFile(MethodDefinition methodDefinition)
+ {
+ var fileName = string.Format("{0}.{1}.txt", methodDefinition.DeclaringType.Name, methodDefinition.Name);
+
+ using (var stream = File.OpenWrite(Path.Combine(".", fileName)))
+ using (var writer = new StreamWriter(stream))
+ {
+ var ilProcessor = methodDefinition.Body.GetILProcessor();
+ for (int i = 0; i < ilProcessor.Body.Instructions.Count; i++)
+ writer.WriteLine((i) + ":" + ilProcessor.Body.Instructions[i]);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/StardewInjector/StardewInjector.cs b/StardewInjector/StardewInjector.cs
new file mode 100644
index 00000000..055a79f9
--- /dev/null
+++ b/StardewInjector/StardewInjector.cs
@@ -0,0 +1,55 @@
+using StardewModdingAPI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace StardewInjector
+{
+ public class StardewInjector : Mod
+ {
+ public override string Name
+ {
+ get { return "Stardew Injector"; }
+ }
+
+ public override string Authour
+ {
+ get { return "Zoryn Aaron"; }
+ }
+
+ public override string Version
+ {
+ get { return "1.0"; }
+ }
+
+ public override string Description
+ {
+ get { return "Pulled from https://github.com/kevinmurphy678/Stardew_Injector and converted to a mod."; }
+ }
+
+ public static Stardew_Hooker hooker { get; set; }
+ public override void Entry(params object[] objects)
+ {
+ if (objects.Length <= 0 || (objects.Length > 0 && objects[0].AsBool() == false))
+ {
+ hooker = new Stardew_Hooker();
+ hooker.Initialize();
+ hooker.ApplyHooks();
+ hooker.Finalize();
+
+ Program.LogInfo("INJECTOR ENTERED");
+ }
+ else if (objects.Length > 0 && objects[0].AsBool() == true)
+ {
+ Program.LogInfo("INJECTOR LAUNCHING");
+ hooker.Run();
+ }
+ else
+ {
+ Program.LogError("INVALID PARAMETERS FOR INJECTOR");
+ }
+ }
+ }
+}
diff --git a/StardewInjector/StardewInjector.csproj b/StardewInjector/StardewInjector.csproj
new file mode 100644
index 00000000..7987a7bd
--- /dev/null
+++ b/StardewInjector/StardewInjector.csproj
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{C9388F35-68D2-431C-88BB-E26286272256}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>StardewInjector</RootNamespace>
+ <AssemblyName>StardewInjector</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
+ <Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
+ <Reference Include="Mono.Cecil">
+ <HintPath>Z:\Games\Stardew Valley\Mono.Cecil.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Configuration" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="CecilUtils.cs" />
+ <Compile Include="Config.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="StardewHooker.cs" />
+ <Compile Include="StardewInjector.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\StardewModdingAPI\StardewModdingAPI.csproj">
+ <Project>{f1a573b0-f436-472c-ae29-0b91ea6b9f8f}</Project>
+ <Name>StardewModdingAPI</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PostBuildEvent>mkdir "$(SolutionDir)Release\Mods\"
+copy /y "$(SolutionDir)$(ProjectName)\$(OutDir)$(TargetFileName)" "$(SolutionDir)Release\Mods\"</PostBuildEvent>
+ </PropertyGroup>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/StardewInjector/bin/Debug/Lidgren.Network.dll b/StardewInjector/bin/Debug/Lidgren.Network.dll
new file mode 100644
index 00000000..2cd9d5b3
--- /dev/null
+++ b/StardewInjector/bin/Debug/Lidgren.Network.dll
Binary files differ
diff --git a/StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.dll b/StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.dll
new file mode 100644
index 00000000..9ba4aa23
--- /dev/null
+++ b/StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.dll
Binary files differ
diff --git a/StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.xml b/StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.xml
new file mode 100644
index 00000000..d0b7a111
--- /dev/null
+++ b/StardewInjector/bin/Debug/Microsoft.Xna.Framework.Game.xml
@@ -0,0 +1,625 @@
+<?xml version="1.0" encoding="utf-8"?>
+<doc>
+ <members>
+ <member name="T:Microsoft.Xna.Framework.DrawableGameComponent">
+ <summary>A game component that is notified when it needs to draw itself.</summary>
+ </member>
+ <member name="M:Microsoft.Xna.Framework.DrawableGameComponent.#ctor(Microsoft.Xna.Framework.Game)">
+ <summary>Creates a new instance of DrawableGameComponent.</summary>
+ <param name="game">The Game that the game component should be attached to.</param>
+ </member>
+ <member name="M:Microsoft.Xna.Framework.DrawableGameComponent.Dispose(System.Boolean)">
+ <summary>Releases the unmanaged resources used by the DrawableGameComponent and optionally releases the managed resources.</summary>
+ <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+ </member>
+ <member name="M:Microsoft.Xna.Framework.DrawableGameComponent.Draw(Microsoft.Xna.Framework.GameTime)">
+ <summary>Called when the DrawableGameComponent needs to be drawn. Override this method with component-specific drawing code. Reference page contains links to related conceptual articles.</summary>
+ <param name="gameTime">Time passed since the last call to Draw.</param>
+ </member>
+ <member name="P:Microsoft.Xna.Framework.DrawableGameComponent.DrawOrder">
+ <summary>Order in which the component should be drawn, relative to other components that are in the same GameComponentCollection. Reference page contains code sample.</summary>
+ </member>
+ <member name="E:Microsoft.Xna.Framework.DrawableGameComponent.DrawOrderChanged">
+ <summary>Raised when the DrawOrder property changes.</summary>
+ <param name="" />
+ </member>
+ <member name="P:Microsoft.Xna.Framework.DrawableGameComponent.GraphicsDevice">
+ <summary&