Compare commits
9 Commits
develop
...
archived/c
Author | SHA1 | Date |
---|---|---|
ClxS | 65f1e5bec4 | |
ClxS | 1ec0570ed9 | |
ClxS | e1bfd54894 | |
ClxS | 792cfcd796 | |
ClxS | 608a5cb257 | |
ClxS | 8201b96034 | |
ClxS | c8e09331d2 | |
ClxS | 27bc612a46 | |
ClxS | 318f5feada |
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.API
|
||||||
|
{
|
||||||
|
class Game
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,11 @@ namespace StardewModdingAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string ExecutionPath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
public static string ExecutionPath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execution path to execute the code.
|
||||||
|
/// </summary>
|
||||||
|
public static string StardewExePath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\Stardew Valley.exe";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Title for the API console
|
/// Title for the API console
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public class FarmAnimal
|
||||||
|
{
|
||||||
|
public void eatGrass_OnEnter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ namespace StardewModdingAPI.Events
|
||||||
{
|
{
|
||||||
GameLoaded.Invoke(null, EventArgs.Empty);
|
GameLoaded.Invoke(null, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InvokeInitialize()
|
public static void InvokeInitialize()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -46,6 +46,8 @@ namespace StardewModdingAPI.Events
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Program.IsGameReferenceDirty = true;
|
||||||
|
var test = Program.gamePtr;
|
||||||
UpdateTick.Invoke(null, EventArgs.Empty);
|
UpdateTick.Invoke(null, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.ExtensionMethods
|
||||||
|
{
|
||||||
|
public static class ArrayExtensions
|
||||||
|
{
|
||||||
|
public static void ForEach(this Array array, Action<Array, int[]> action)
|
||||||
|
{
|
||||||
|
if (array.LongLength == 0) return;
|
||||||
|
ArrayTraverse walker = new ArrayTraverse(array);
|
||||||
|
do action(array, walker.Position);
|
||||||
|
while (walker.Step());
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static void ForEach(Array array, Action<Array, int[]> action)
|
||||||
|
//{
|
||||||
|
// if (array.LongLength == 0) return;
|
||||||
|
// ArrayTraverse walker = new ArrayTraverse(array);
|
||||||
|
// do action(array, walker.Position);
|
||||||
|
// while (walker.Step());
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ArrayTraverse
|
||||||
|
{
|
||||||
|
public int[] Position;
|
||||||
|
private int[] maxLengths;
|
||||||
|
|
||||||
|
public ArrayTraverse(Array array)
|
||||||
|
{
|
||||||
|
maxLengths = new int[array.Rank];
|
||||||
|
for (int i = 0; i < array.Rank; ++i)
|
||||||
|
{
|
||||||
|
maxLengths[i] = array.GetLength(i) - 1;
|
||||||
|
}
|
||||||
|
Position = new int[array.Rank];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Step()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Position.Length; ++i)
|
||||||
|
{
|
||||||
|
if (Position[i] < maxLengths[i])
|
||||||
|
{
|
||||||
|
Position[i]++;
|
||||||
|
for (int j = 0; j < i; j++)
|
||||||
|
{
|
||||||
|
Position[j] = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.ExtensionMethods
|
||||||
|
{
|
||||||
|
//From https://github.com/jpmikkers/net-object-deep-copy/blob/master/ObjectExtensions.cs
|
||||||
|
public static class ObjectExtensions
|
||||||
|
{
|
||||||
|
public static T Copy<T>(this object original)
|
||||||
|
{
|
||||||
|
return (T)new DeepCopyContext().InternalCopy(original, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DeepCopyContext
|
||||||
|
{
|
||||||
|
private static readonly Func<object, object> CloneMethod;
|
||||||
|
private readonly Dictionary<Object, Object> m_Visited;
|
||||||
|
private readonly Dictionary<Type, FieldInfo[]> m_NonShallowFieldCache;
|
||||||
|
|
||||||
|
static DeepCopyContext()
|
||||||
|
{
|
||||||
|
MethodInfo cloneMethod = typeof(Object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
var p1 = Expression.Parameter(typeof(object));
|
||||||
|
var body = Expression.Call(p1, cloneMethod);
|
||||||
|
CloneMethod = Expression.Lambda<Func<object, object>>(body, p1).Compile();
|
||||||
|
//Console.WriteLine("typeof(object) contains {0} nonshallow fields", NonShallowFields(typeof(object)).Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeepCopyContext()
|
||||||
|
{
|
||||||
|
m_Visited = new Dictionary<object, object>(new ReferenceEqualityComparer());
|
||||||
|
m_NonShallowFieldCache = new Dictionary<Type, FieldInfo[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPrimitive(Type type)
|
||||||
|
{
|
||||||
|
if (type.IsValueType && type.IsPrimitive) return true;
|
||||||
|
if (type == typeof(String)) return true;
|
||||||
|
if (type == typeof(Decimal)) return true;
|
||||||
|
if (type == typeof(DateTime)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object InternalCopy(Object originalObject, bool includeInObjectGraph)
|
||||||
|
{
|
||||||
|
if (originalObject == null) return null;
|
||||||
|
var typeToReflect = originalObject.GetType();
|
||||||
|
if (IsPrimitive(typeToReflect)) return originalObject;
|
||||||
|
|
||||||
|
if (typeof(XElement).IsAssignableFrom(typeToReflect)) return new XElement(originalObject as XElement);
|
||||||
|
if (typeof(Delegate).IsAssignableFrom(typeToReflect)) return null;
|
||||||
|
|
||||||
|
if (includeInObjectGraph)
|
||||||
|
{
|
||||||
|
object result;
|
||||||
|
if (m_Visited.TryGetValue(originalObject, out result)) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cloneObject = CloneMethod(originalObject);
|
||||||
|
|
||||||
|
if (includeInObjectGraph)
|
||||||
|
{
|
||||||
|
m_Visited.Add(originalObject, cloneObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeToReflect.IsArray)
|
||||||
|
{
|
||||||
|
var arrayElementType = typeToReflect.GetElementType();
|
||||||
|
|
||||||
|
if (IsPrimitive(arrayElementType))
|
||||||
|
{
|
||||||
|
// for an array of primitives, do nothing. The shallow clone is enough.
|
||||||
|
}
|
||||||
|
else if (arrayElementType.IsValueType)
|
||||||
|
{
|
||||||
|
// if its an array of structs, there's no need to check and add the individual elements to 'visited', because in .NET it's impossible to create
|
||||||
|
// references to individual array elements.
|
||||||
|
Array clonedArray = (Array)cloneObject;
|
||||||
|
clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), false), indices));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// it's an array of ref types
|
||||||
|
Array clonedArray = (Array)cloneObject;
|
||||||
|
clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), true), indices));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var fieldInfo in CachedNonShallowFields(typeToReflect))
|
||||||
|
{
|
||||||
|
var originalFieldValue = fieldInfo.GetValue(originalObject);
|
||||||
|
// a valuetype field can never have a reference pointing to it, so don't check the object graph in that case
|
||||||
|
|
||||||
|
Log.Error("Replace this with a recurse-less version");
|
||||||
|
var clonedFieldValue = InternalCopy(originalFieldValue, !fieldInfo.FieldType.IsValueType);
|
||||||
|
fieldInfo.SetValue(cloneObject, clonedFieldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloneObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldInfo[] CachedNonShallowFields(Type typeToReflect)
|
||||||
|
{
|
||||||
|
FieldInfo[] result;
|
||||||
|
|
||||||
|
if (!m_NonShallowFieldCache.TryGetValue(typeToReflect, out result))
|
||||||
|
{
|
||||||
|
result = NonShallowFields(typeToReflect).ToArray();
|
||||||
|
m_NonShallowFieldCache[typeToReflect] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// From the given type hierarchy (i.e. including all base types), return all fields that should be deep-copied
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeToReflect"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static IEnumerable<FieldInfo> NonShallowFields(Type typeToReflect)
|
||||||
|
{
|
||||||
|
while (typeToReflect != typeof(object))
|
||||||
|
{
|
||||||
|
foreach (var fieldInfo in typeToReflect.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly))
|
||||||
|
{
|
||||||
|
if (IsPrimitive(fieldInfo.FieldType)) continue; // this is 5% faster than a where clause..
|
||||||
|
yield return fieldInfo;
|
||||||
|
}
|
||||||
|
typeToReflect = typeToReflect.BaseType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReferenceEqualityComparer : EqualityComparer<Object>
|
||||||
|
{
|
||||||
|
public override bool Equals(object x, object y)
|
||||||
|
{
|
||||||
|
return ReferenceEquals(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode(object obj)
|
||||||
|
{
|
||||||
|
if (obj == null) return 0;
|
||||||
|
// The RuntimeHelpers.GetHashCode method always calls the Object.GetHashCode method non-virtually,
|
||||||
|
// even if the object's type has overridden the Object.GetHashCode method.
|
||||||
|
return RuntimeHelpers.GetHashCode(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Helpers
|
||||||
|
{
|
||||||
|
public enum CecilContextType
|
||||||
|
{
|
||||||
|
SMAPI,
|
||||||
|
Stardew
|
||||||
|
}
|
||||||
|
public class CecilContext
|
||||||
|
{
|
||||||
|
public CecilContextType ContextType { get; private set;}
|
||||||
|
|
||||||
|
private AssemblyDefinition _assemblyDefinition { get; set; }
|
||||||
|
private bool _isMemoryStreamDirty { get; set; }
|
||||||
|
|
||||||
|
private MemoryStream _modifiedAssembly;
|
||||||
|
public MemoryStream ModifiedAssembly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_modifiedAssembly == null)
|
||||||
|
{
|
||||||
|
_modifiedAssembly = new MemoryStream();
|
||||||
|
_assemblyDefinition.Write(_modifiedAssembly);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_isMemoryStreamDirty)
|
||||||
|
{
|
||||||
|
_modifiedAssembly.Dispose();
|
||||||
|
_modifiedAssembly = new MemoryStream();
|
||||||
|
_assemblyDefinition.Write(_modifiedAssembly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _modifiedAssembly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(type) || string.IsNullOrWhiteSpace(method))
|
||||||
|
throw new ArgumentNullException("Both type and method must be set");
|
||||||
|
|
||||||
|
Mono.Cecil.Cil.ILProcessor ilProcessor = null;
|
||||||
|
TypeDefinition typeDef = GetTypeDefinition(type);
|
||||||
|
if (typeDef != null)
|
||||||
|
{
|
||||||
|
MethodDefinition methodDef = typeDef.Methods.FirstOrDefault(m => m.Name == method);
|
||||||
|
if (methodDef != null)
|
||||||
|
{
|
||||||
|
ilProcessor = methodDef.Body.GetILProcessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ConstructorInfo GetSMAPITypeContructor(string type)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (ContextType != CecilContextType.SMAPI)
|
||||||
|
throw new Exception("GetSMAPIMethodReference can only be called on the SMAPI context");
|
||||||
|
|
||||||
|
ConstructorInfo methodInfo = null;
|
||||||
|
|
||||||
|
var reflectionType = Assembly.GetExecutingAssembly().GetType(type);
|
||||||
|
if (reflectionType != null)
|
||||||
|
{
|
||||||
|
methodInfo = reflectionType.GetConstructor(Type.EmptyTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodInfo GetSMAPIMethodReference(string type, string method)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (ContextType != CecilContextType.SMAPI)
|
||||||
|
throw new Exception("GetSMAPIMethodReference can only be called on the SMAPI context");
|
||||||
|
|
||||||
|
MethodInfo methodInfo = null;
|
||||||
|
|
||||||
|
var reflectionType = Assembly.GetExecutingAssembly().GetType(type);
|
||||||
|
if (reflectionType != null)
|
||||||
|
{
|
||||||
|
methodInfo = reflectionType.GetMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodReference ImportSMAPIMethodInStardew(CecilContext destinationContext, MethodBase method)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (ContextType != CecilContextType.SMAPI)
|
||||||
|
throw new Exception("ImportSmapiMethodInStardew can only be called on the Stardew context");
|
||||||
|
|
||||||
|
MethodReference reference = null;
|
||||||
|
if (method != null)
|
||||||
|
{
|
||||||
|
reference = destinationContext._assemblyDefinition.MainModule.Import(method);
|
||||||
|
}
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteAssembly(string file)
|
||||||
|
{
|
||||||
|
_assemblyDefinition.Write(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using Mono.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if(method.HasThis)
|
||||||
|
{
|
||||||
|
Instruction loadObjInstruction = ilProcessor.Create(OpCodes.Ldarg_0);
|
||||||
|
ilProcessor.InsertBefore(target, loadObjInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.HasParameters)
|
||||||
|
{
|
||||||
|
Instruction loadObjInstruction = ilProcessor.Create(OpCodes.Ldarg_0);
|
||||||
|
ilProcessor.InsertBefore(target, loadObjInstruction);
|
||||||
|
ilProcessor.InsertAfter(loadObjInstruction, callEnterInstruction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ilProcessor.InsertBefore(target, callEnterInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InjectMethod(ILProcessor ilProcessor, IEnumerable<Instruction> targets, MethodReference method)
|
||||||
|
{
|
||||||
|
foreach(var target in targets.ToList())
|
||||||
|
{
|
||||||
|
InjectMethod(ilProcessor, target, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Instruction> GetMatchingInstructions(Collection<Instruction> instructions, OpCode opcode, object @object)
|
||||||
|
{
|
||||||
|
return instructions.Where(n => n.OpCode == opcode && n.Operand == @object).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RedirectConstructor(CecilContext stardewContext, CecilContext smapiContext,
|
||||||
|
string typeToAlter, string methodToAlter,
|
||||||
|
string injecteeType, string injecteeMethod,
|
||||||
|
string injectedType, string injectedMethod)
|
||||||
|
{
|
||||||
|
var ilProcessor = stardewContext.GetMethodILProcessor(typeToAlter, methodToAlter);
|
||||||
|
var methodDefinition = stardewContext.GetMethodDefinition(injecteeType, injecteeMethod);
|
||||||
|
|
||||||
|
var methodInfo = smapiContext.GetSMAPITypeContructor(injectedType);
|
||||||
|
var reference = smapiContext.ImportSMAPIMethodInStardew(stardewContext, methodInfo);
|
||||||
|
|
||||||
|
var instructionsToAlter = GetMatchingInstructions(ilProcessor.Body.Instructions, OpCodes.Newobj, methodDefinition);
|
||||||
|
|
||||||
|
var newInstruction = ilProcessor.Create(OpCodes.Newobj, reference);
|
||||||
|
foreach(var instruction in instructionsToAlter)
|
||||||
|
{
|
||||||
|
ilProcessor.Replace(instruction, newInstruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
var methodInfo = smapiContext.GetSMAPIMethodReference(injectedType, injectedMethod);
|
||||||
|
var reference = smapiContext.ImportSMAPIMethodInStardew(stardewContext, methodInfo);
|
||||||
|
var ilProcessor = stardewContext.GetMethodILProcessor(injecteeType, injecteeMethod);
|
||||||
|
InjectMethod(ilProcessor, ilProcessor.Body.Instructions.First(), reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InjectExitMethod(CecilContext stardewContext, CecilContext smapiContext, string injecteeType, string injecteeMethod,
|
||||||
|
string injectedType, string injectedMethod)
|
||||||
|
{
|
||||||
|
var methodInfo = smapiContext.GetSMAPIMethodReference(injectedType, injectedMethod);
|
||||||
|
var reference = smapiContext.ImportSMAPIMethodInStardew(stardewContext, methodInfo);
|
||||||
|
var ilProcessor = stardewContext.GetMethodILProcessor(injecteeType, injecteeMethod);
|
||||||
|
InjectMethod(ilProcessor, ilProcessor.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret), reference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Helpers
|
||||||
|
{
|
||||||
|
public static class ReflectionHelper
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Helpers
|
||||||
|
{
|
||||||
|
public static class StardewAssembly
|
||||||
|
{
|
||||||
|
private static Assembly ModifiedGameAssembly { get; set; }
|
||||||
|
private static CecilContext StardewContext { get; set; }
|
||||||
|
private static CecilContext SmapiContext { get; set; }
|
||||||
|
|
||||||
|
public static void ModifyStardewAssembly()
|
||||||
|
{
|
||||||
|
StardewContext = new CecilContext(CecilContextType.Stardew);
|
||||||
|
SmapiContext = new CecilContext(CecilContextType.SMAPI);
|
||||||
|
|
||||||
|
CecilHelper.InjectEntryMethod(StardewContext, SmapiContext, "StardewValley.Game1", ".ctor", "StardewModdingAPI.Program", "Test");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "Initialize", "StardewModdingAPI.Events.GameEvents", "InvokeInitialize");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "LoadContent", "StardewModdingAPI.Events.GameEvents", "InvokeLoadContent");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "Update", "StardewModdingAPI.Events.GameEvents", "InvokeUpdateTick");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "Draw", "StardewModdingAPI.Events.GraphicsEvents", "InvokeDrawTick");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LoadStardewAssembly()
|
||||||
|
{
|
||||||
|
ModifiedGameAssembly = Assembly.Load(StardewContext.ModifiedAssembly.GetBuffer());
|
||||||
|
//ModifiedGameAssembly = Assembly.UnsafeLoadFrom(Constants.ExecutionPath + "\\Stardew Valley.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Launch()
|
||||||
|
{
|
||||||
|
ModifiedGameAssembly.EntryPoint.Invoke(null, new object[] { new string[] { } });
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteModifiedExe()
|
||||||
|
{
|
||||||
|
StardewContext.WriteAssembly("StardewValley-Modified.exe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -179,42 +179,9 @@ namespace StardewModdingAPI.Inheritance
|
||||||
public Farmer CurrentFarmer { get { return player; } }
|
public Farmer CurrentFarmer { get { return player; } }
|
||||||
|
|
||||||
public SGame()
|
public SGame()
|
||||||
{
|
{
|
||||||
instance = this;
|
instance = this;
|
||||||
|
graphics.GraphicsProfile = GraphicsProfile.HiDef;
|
||||||
#if DEBUG
|
|
||||||
SaveGame.serializer = new XmlSerializer(typeof (SaveGame), new Type[28]
|
|
||||||
{
|
|
||||||
typeof (Tool),
|
|
||||||
typeof (GameLocation),
|
|
||||||
typeof (Crow),
|
|
||||||
typeof (Duggy),
|
|
||||||
typeof (Bug),
|
|
||||||
typeof (BigSlime),
|
|
||||||
typeof (Fireball),
|
|
||||||
typeof (Ghost),
|
|
||||||
typeof (Child),
|
|
||||||
typeof (Pet),
|
|
||||||
typeof (Dog),
|
|
||||||
typeof (StardewValley.Characters.Cat),
|
|
||||||
typeof (Horse),
|
|
||||||
typeof (GreenSlime),
|
|
||||||
typeof (LavaCrab),
|
|
||||||
typeof (RockCrab),
|
|
||||||
typeof (ShadowGuy),
|
|
||||||
typeof (SkeletonMage),
|
|
||||||
typeof (SquidKid),
|
|
||||||
typeof (Grub),
|
|
||||||
typeof (Fly),
|
|
||||||
typeof (DustSpirit),
|
|
||||||
typeof (Quest),
|
|
||||||
typeof (MetalHead),
|
|
||||||
typeof (ShadowGirl),
|
|
||||||
typeof (Monster),
|
|
||||||
typeof (TerrainFeature),
|
|
||||||
typeof (SObject)
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Initialize()
|
protected override void Initialize()
|
||||||
|
|
|
@ -78,6 +78,16 @@ namespace StardewModdingAPI
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <param name="values"></param>
|
/// <param name="values"></param>
|
||||||
public static void Comment(object message, params object[] values)
|
public static void Comment(object message, params object[] values)
|
||||||
|
{
|
||||||
|
Log.PrintLog(message?.ToString(), false, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Additional comment to display to console and logging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Warning(object message, params object[] values)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
Log.PrintLog(message?.ToString(), false, values);
|
Log.PrintLog(message?.ToString(), false, values);
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
using StardewModdingAPI.Events;
|
using StardewModdingAPI.Events;
|
||||||
|
using StardewModdingAPI.ExtensionMethods;
|
||||||
|
using StardewModdingAPI.Helpers;
|
||||||
using StardewModdingAPI.Inheritance;
|
using StardewModdingAPI.Inheritance;
|
||||||
using StardewModdingAPI.Inheritance.Menus;
|
using StardewModdingAPI.Inheritance.Menus;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
|
@ -23,19 +27,31 @@ namespace StardewModdingAPI
|
||||||
|
|
||||||
public static Texture2D DebugPixel { get; private set; }
|
public static Texture2D DebugPixel { get; private set; }
|
||||||
|
|
||||||
public static SGame gamePtr;
|
public static bool IsGameReferenceDirty { get; set; }
|
||||||
public static bool ready;
|
|
||||||
|
public static object gameInst;
|
||||||
|
|
||||||
public static Assembly StardewAssembly;
|
public static Game1 _gamePtr;
|
||||||
public static Type StardewProgramType;
|
public static Game1 gamePtr
|
||||||
public static FieldInfo StardewGameInfo;
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(IsGameReferenceDirty && gameInst != null)
|
||||||
|
{
|
||||||
|
_gamePtr = gameInst.Copy<Game1>();
|
||||||
|
}
|
||||||
|
return _gamePtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ready;
|
||||||
|
|
||||||
public static Form StardewForm;
|
public static Form StardewForm;
|
||||||
|
|
||||||
public static Thread gameThread;
|
public static Thread gameThread;
|
||||||
public static Thread consoleInputThread;
|
public static Thread consoleInputThread;
|
||||||
|
|
||||||
public static bool StardewInjectorLoaded { get; private set; }
|
|
||||||
public static Mod StardewInjectorMod { get; private set; }
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -49,9 +65,8 @@ namespace StardewModdingAPI
|
||||||
{
|
{
|
||||||
ConfigureUI();
|
ConfigureUI();
|
||||||
ConfigurePaths();
|
ConfigurePaths();
|
||||||
ConfigureInjector();
|
ConfigureMethodInjection();
|
||||||
ConfigureSDV();
|
ConfigureSDV();
|
||||||
|
|
||||||
GameRunInvoker();
|
GameRunInvoker();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -63,7 +78,26 @@ namespace StardewModdingAPI
|
||||||
StardewModdingAPI.Log.Comment("The API will now terminate. Press any key to continue...");
|
StardewModdingAPI.Log.Comment("The API will now terminate. Press any key to continue...");
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures Mono.Cecil injections
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureMethodInjection()
|
||||||
|
{
|
||||||
|
StardewAssembly.ModifyStardewAssembly();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
StardewAssembly.WriteModifiedExe();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void Test(object instance)
|
||||||
|
{
|
||||||
|
gameInst = instance;
|
||||||
|
IsGameReferenceDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set up the console properties
|
/// Set up the console properties
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -86,6 +120,7 @@ namespace StardewModdingAPI
|
||||||
_modPaths = new List<string>();
|
_modPaths = new List<string>();
|
||||||
_modContentPaths = new List<string>();
|
_modContentPaths = new List<string>();
|
||||||
|
|
||||||
|
|
||||||
//TODO: Have an app.config and put the paths inside it so users can define locations to load mods from
|
//TODO: Have an app.config and put the paths inside it so users can define locations to load mods from
|
||||||
_modPaths.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "Mods"));
|
_modPaths.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "Mods"));
|
||||||
_modPaths.Add(Path.Combine(Constants.ExecutionPath, "Mods"));
|
_modPaths.Add(Path.Combine(Constants.ExecutionPath, "Mods"));
|
||||||
|
@ -101,100 +136,39 @@ namespace StardewModdingAPI
|
||||||
|
|
||||||
if (!File.Exists(Constants.ExecutionPath + "\\Stardew Valley.exe"))
|
if (!File.Exists(Constants.ExecutionPath + "\\Stardew Valley.exe"))
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException(string.Format("Could not found: {0}\\Stardew Valley.exe", Constants.ExecutionPath));
|
StardewModdingAPI.Log.Error("Replace this");
|
||||||
|
//throw new FileNotFoundException(string.Format("Could not found: {0}\\Stardew Valley.exe", Constants.ExecutionPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Load the injector.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This will load the injector before anything else if it sees it
|
|
||||||
/// It doesn't matter though
|
|
||||||
/// I'll leave it as a feature in case anyone in the community wants to tinker with it
|
|
||||||
/// All you need is a DLL that inherits from mod and is called StardewInjector.dll with an Entry() method
|
|
||||||
/// </remarks>
|
|
||||||
private static void ConfigureInjector()
|
|
||||||
{
|
|
||||||
foreach (string ModPath in _modPaths)
|
|
||||||
{
|
|
||||||
foreach (String s in Directory.GetFiles(ModPath, "StardewInjector.dll"))
|
|
||||||
{
|
|
||||||
StardewModdingAPI.Log.Success(ConsoleColor.Green, "Found Stardew Injector DLL: " + s);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Assembly mod = Assembly.UnsafeLoadFrom(s); //to combat internet-downloaded DLLs
|
|
||||||
|
|
||||||
if (mod.DefinedTypes.Count(x => x.BaseType == typeof(Mod)) > 0)
|
|
||||||
{
|
|
||||||
StardewModdingAPI.Log.Success("Loading Injector DLL...");
|
|
||||||
TypeInfo tar = mod.DefinedTypes.First(x => x.BaseType == typeof(Mod));
|
|
||||||
Mod m = (Mod)mod.CreateInstance(tar.ToString());
|
|
||||||
Console.WriteLine("LOADED: {0} by {1} - Version {2} | Description: {3}", m.Name, m.Authour, m.Version, m.Description);
|
|
||||||
m.Entry(false);
|
|
||||||
StardewInjectorLoaded = true;
|
|
||||||
StardewInjectorMod = m;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StardewModdingAPI.Log.Error("Invalid Mod DLL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
StardewModdingAPI.Log.Error("Failed to load mod '{0}'. Exception details:\n" + ex, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load Stardev Valley and control features
|
/// Load Stardev Valley and control features
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void ConfigureSDV()
|
private static void ConfigureSDV()
|
||||||
{
|
{
|
||||||
StardewModdingAPI.Log.Info("Initializing SDV Assembly...");
|
StardewModdingAPI.Log.Info("Initializing SDV Assembly...");
|
||||||
|
|
||||||
// Load in the assembly - ignores security
|
// Load in the assembly - ignores security
|
||||||
StardewAssembly = Assembly.UnsafeLoadFrom(Constants.ExecutionPath + "\\Stardew Valley.exe");
|
StardewAssembly.LoadStardewAssembly();
|
||||||
StardewProgramType = StardewAssembly.GetType("StardewValley.Program", true);
|
StardewModdingAPI.Log.Comment("SDV Loaded Into Memory");
|
||||||
StardewGameInfo = StardewProgramType.GetField("gamePtr");
|
|
||||||
|
|
||||||
// Change the game's version
|
// Change the game's version
|
||||||
StardewModdingAPI.Log.Verbose("Injecting New SDV Version...");
|
StardewModdingAPI.Log.Verbose("Injecting New SDV Version...");
|
||||||
Game1.version += string.Format("-Z_MODDED | SMAPI {0}", Constants.VersionString);
|
Game1.version += string.Format("-Z_MODDED | SMAPI {0}", Constants.VersionString);
|
||||||
|
|
||||||
// Create the thread for the game to run in.
|
|
||||||
gameThread = new Thread(RunGame);
|
|
||||||
StardewModdingAPI.Log.Info("Starting SDV...");
|
|
||||||
gameThread.Start();
|
|
||||||
|
|
||||||
// Wait for the game to load up
|
// Create the thread for the game to run in.
|
||||||
while (!ready) ;
|
Application.ThreadException += StardewModdingAPI.Log.Application_ThreadException;
|
||||||
|
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||||
//SDV is running
|
AppDomain.CurrentDomain.UnhandledException += StardewModdingAPI.Log.CurrentDomain_UnhandledException;
|
||||||
StardewModdingAPI.Log.Comment("SDV Loaded Into Memory");
|
|
||||||
|
|
||||||
//Create definition to listen for input
|
//Create definition to listen for input
|
||||||
StardewModdingAPI.Log.Verbose("Initializing Console Input Thread...");
|
StardewModdingAPI.Log.Verbose("Initializing Console Input Thread...");
|
||||||
consoleInputThread = new Thread(ConsoleInputThread);
|
consoleInputThread = new Thread(ConsoleInputThread);
|
||||||
|
|
||||||
|
Command.RegisterCommand("help", "Lists all commands | 'help <cmd>' returns command description").CommandFired += help_CommandFired;
|
||||||
|
|
||||||
// The only command in the API (at least it should be, for now)
|
StardewAssembly.Launch();
|
||||||
Command.RegisterCommand("help", "Lists all commands | 'help <cmd>' returns command description").CommandFired += help_CommandFired;
|
|
||||||
//Command.RegisterCommand("crash", "crashes sdv").CommandFired += delegate { Game1.player.draw(null); };
|
|
||||||
|
|
||||||
//Subscribe to events
|
|
||||||
Events.ControlEvents.KeyPressed += Events_KeyPressed;
|
|
||||||
Events.GameEvents.LoadContent += Events_LoadContent;
|
|
||||||
//Events.MenuChanged += Events_MenuChanged; //Idk right now
|
|
||||||
|
|
||||||
StardewModdingAPI.Log.Verbose("Applying Final SDV Tweaks...");
|
|
||||||
StardewInvoke(() =>
|
|
||||||
{
|
|
||||||
gamePtr.IsMouseVisible = false;
|
|
||||||
gamePtr.Window.Title = "Stardew Valley - Version " + Game1.version;
|
|
||||||
StardewForm.Resize += Events.GraphicsEvents.InvokeResize;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -248,48 +222,6 @@ namespace StardewModdingAPI
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public static void RunGame()
|
|
||||||
{
|
|
||||||
Application.ThreadException += StardewModdingAPI.Log.Application_ThreadException;
|
|
||||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += StardewModdingAPI.Log.CurrentDomain_UnhandledException;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
gamePtr = new SGame();
|
|
||||||
StardewModdingAPI.Log.Verbose("Patching SDV Graphics Profile...");
|
|
||||||
Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef;
|
|
||||||
LoadMods();
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
StardewModdingAPI.Log.Error("Game failed to start: " + ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void StardewForm_Closing(object sender, CancelEventArgs e)
|
static void StardewForm_Closing(object sender, CancelEventArgs e)
|
||||||
{
|
{
|
||||||
|
@ -351,73 +283,7 @@ namespace StardewModdingAPI
|
||||||
Command.CallCommand(Console.ReadLine());
|
Command.CallCommand(Console.ReadLine());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Events_LoadContent(object o, EventArgs e)
|
|
||||||
{
|
|
||||||
StardewModdingAPI.Log.Info("Initializing Debug Assets...");
|
|
||||||
DebugPixel = new Texture2D(Game1.graphics.GraphicsDevice, 1, 1);
|
|
||||||
DebugPixel.SetData(new Color[] { Color.White });
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
StardewModdingAPI.Log.Verbose("REGISTERING BASE CUSTOM ITEM");
|
|
||||||
SObject so = new SObject();
|
|
||||||
so.Name = "Mario Block";
|
|
||||||
so.CategoryName = "SMAPI Test Mod";
|
|
||||||
so.Description = "It's a block from Mario!\nLoaded in realtime by SMAPI.";
|
|
||||||
so.Texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, new FileStream(_modContentPaths[0] + "\\Test.png", FileMode.Open));
|
|
||||||
so.IsPassable = true;
|
|
||||||
so.IsPlaceable = true;
|
|
||||||
StardewModdingAPI.Log.Verbose("REGISTERED WITH ID OF: " + SGame.RegisterModItem(so));
|
|
||||||
|
|
||||||
//StardewModdingAPI.Log.Verbose("REGISTERING SECOND CUSTOM ITEM");
|
|
||||||
//SObject so2 = new SObject();
|
|
||||||
//so2.Name = "Mario Painting";
|
|
||||||
//so2.CategoryName = "SMAPI Test Mod";
|
|
||||||
//so2.Description = "It's a painting of a creature from Mario!\nLoaded in realtime by SMAPI.";
|
|
||||||
//so2.Texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, new FileStream(_modContentPaths[0] + "\\PaintingTest.png", FileMode.Open));
|
|
||||||
//so2.IsPassable = true;
|
|
||||||
//so2.IsPlaceable = true;
|
|
||||||
//StardewModdingAPI.Log.Verbose("REGISTERED WITH ID OF: " + SGame.RegisterModItem(so2));
|
|
||||||
|
|
||||||
Command.CallCommand("load");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Events_KeyPressed(object o, EventArgsKeyPressed e)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Events_MenuChanged(IClickableMenu newMenu)
|
|
||||||
{
|
|
||||||
StardewModdingAPI.Log.Verbose("NEW MENU: " + newMenu.GetType());
|
|
||||||
if (newMenu is GameMenu)
|
|
||||||
{
|
|
||||||
Game1.activeClickableMenu = SGameMenu.ConstructFromBaseClass(Game1.activeClickableMenu as GameMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void Events_LocationsChanged(List<GameLocation> newLocations)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
SGame.ModLocations = SGameLocation.ConstructFromBaseClasses(Game1.locations);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Events_CurrentLocationChanged(GameLocation newLocation)
|
|
||||||
{
|
|
||||||
//SGame.CurrentLocation = null;
|
|
||||||
//System.Threading.Thread.Sleep(10);
|
|
||||||
#if DEBUG
|
|
||||||
Console.WriteLine(newLocation.name);
|
|
||||||
SGame.CurrentLocation = SGame.LoadOrCreateSGameLocationFromName(newLocation.name);
|
|
||||||
#endif
|
|
||||||
//Game1.currentLocation = SGame.CurrentLocation;
|
|
||||||
//Log.LogComment(((SGameLocation) newLocation).name);
|
|
||||||
//Log.LogComment("LOC CHANGED: " + SGame.currentLocation.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void StardewInvoke(Action a)
|
public static void StardewInvoke(Action a)
|
||||||
{
|
{
|
||||||
StardewForm.Invoke(a);
|
StardewForm.Invoke(a);
|
||||||
|
|
|
@ -37,16 +37,16 @@
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Choose>
|
<Choose>
|
||||||
<When Condition="'$(SteamInstallPath)' != ''">
|
<When Condition="'$(SteamInstallPath)' != ''">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SteamPath>$(SteamInstallPath)</SteamPath>
|
<SteamPath>$(SteamInstallPath)</SteamPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</When>
|
</When>
|
||||||
<Otherwise>
|
<Otherwise>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SteamPath>..\..\..\..\Games\SteamLibrary</SteamPath>
|
<SteamPath>..\..\..\..\Games\SteamLibrary</SteamPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Otherwise>
|
</Otherwise>
|
||||||
</Choose>
|
</Choose>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
@ -73,8 +73,7 @@
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<DefineConstants>
|
<DefineConstants>DEBUG</DefineConstants>
|
||||||
</DefineConstants>
|
|
||||||
<UseVSHostingProcess>true</UseVSHostingProcess>
|
<UseVSHostingProcess>true</UseVSHostingProcess>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
@ -90,9 +89,25 @@
|
||||||
<Reference Include="Microsoft.Xna.Framework.Game, 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="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
<Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
<Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
<Reference Include="Stardew Valley, Version=1.0.5905.5747, Culture=neutral, processorArchitecture=x86">
|
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Stardew Valley, Version=1.0.5912.41135, Culture=neutral, processorArchitecture=x86">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>$(SteamPath)\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
@ -103,12 +118,12 @@
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="xTile, Version=2.0.4.0, Culture=neutral, processorArchitecture=x86">
|
<Reference Include="xTile">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\xTile.dll</HintPath>
|
||||||
<HintPath>$(SteamPath)\steamapps\common\Stardew Valley\xTile.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="API\Game.cs" />
|
||||||
<Compile Include="Command.cs" />
|
<Compile Include="Command.cs" />
|
||||||
<Compile Include="Constants.cs" />
|
<Compile Include="Constants.cs" />
|
||||||
<Compile Include="Entities\SCharacter.cs" />
|
<Compile Include="Entities\SCharacter.cs" />
|
||||||
|
@ -118,6 +133,7 @@
|
||||||
<Compile Include="Entities\SPlayer.cs" />
|
<Compile Include="Entities\SPlayer.cs" />
|
||||||
<Compile Include="Events\Controls.cs" />
|
<Compile Include="Events\Controls.cs" />
|
||||||
<Compile Include="Events\EventArgs.cs" />
|
<Compile Include="Events\EventArgs.cs" />
|
||||||
|
<Compile Include="Events\FarmAnimal.cs" />
|
||||||
<Compile Include="Events\Game.cs" />
|
<Compile Include="Events\Game.cs" />
|
||||||
<Compile Include="Events\Graphics.cs" />
|
<Compile Include="Events\Graphics.cs" />
|
||||||
<Compile Include="Events\Location.cs" />
|
<Compile Include="Events\Location.cs" />
|
||||||
|
@ -125,7 +141,13 @@
|
||||||
<Compile Include="Events\Mine.cs" />
|
<Compile Include="Events\Mine.cs" />
|
||||||
<Compile Include="Events\Player.cs" />
|
<Compile Include="Events\Player.cs" />
|
||||||
<Compile Include="Events\Time.cs" />
|
<Compile Include="Events\Time.cs" />
|
||||||
|
<Compile Include="ExtensionMethods\Array.cs" />
|
||||||
|
<Compile Include="ExtensionMethods\Object.cs" />
|
||||||
<Compile Include="Extensions.cs" />
|
<Compile Include="Extensions.cs" />
|
||||||
|
<Compile Include="Helpers\CecilContext.cs" />
|
||||||
|
<Compile Include="Helpers\CecilHelper.cs" />
|
||||||
|
<Compile Include="Helpers\ReflectionHelper.cs" />
|
||||||
|
<Compile Include="Helpers\StardewAssembly.cs" />
|
||||||
<Compile Include="Inheritance\ItemStackChange.cs" />
|
<Compile Include="Inheritance\ItemStackChange.cs" />
|
||||||
<Compile Include="Inheritance\Menus\SBobberBar.cs" />
|
<Compile Include="Inheritance\Menus\SBobberBar.cs" />
|
||||||
<Compile Include="Inheritance\Menus\SGameMenu.cs" />
|
<Compile Include="Inheritance\Menus\SGameMenu.cs" />
|
||||||
|
@ -142,6 +164,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="icon.ico" />
|
<Content Include="icon.ico" />
|
||||||
|
@ -159,6 +182,7 @@
|
||||||
<Install>false</Install>
|
<Install>false</Install>
|
||||||
</BootstrapperPackage>
|
</BootstrapperPackage>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Mono.Cecil" version="0.9.6.1" targetFramework="net45" />
|
||||||
|
</packages>
|
|
@ -34,16 +34,16 @@
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Choose>
|
<Choose>
|
||||||
<When Condition="'$(SteamInstallPath)' != ''">
|
<When Condition="'$(SteamInstallPath)' != ''">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SteamPath>$(SteamInstallPath)</SteamPath>
|
<SteamPath>$(SteamInstallPath)</SteamPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</When>
|
</When>
|
||||||
<Otherwise>
|
<Otherwise>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SteamPath>..\..\..\..\Games\SteamLibrary</SteamPath>
|
<SteamPath>..\..\..\..\Games\SteamLibrary</SteamPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Otherwise>
|
</Otherwise>
|
||||||
</Choose>
|
</Choose>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
|
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
|
||||||
|
@ -53,8 +53,7 @@
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Stardew Valley">
|
<Reference Include="Stardew Valley">
|
||||||
<HintPath>$(SteamPath)\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
|
||||||
<Private>False</Private>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
@ -65,8 +64,7 @@
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="xTile">
|
<Reference Include="xTile">
|
||||||
<HintPath>$(SteamPath)\steamapps\common\Stardew Valley\xTile.dll</HintPath>
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\xTile.dll</HintPath>
|
||||||
<Private>False</Private>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in New Issue