diff options
Diffstat (limited to 'StardewModdingAPI')
-rw-r--r-- | StardewModdingAPI/Command.cs | 2 | ||||
-rw-r--r-- | StardewModdingAPI/Extensions.cs | 19 | ||||
-rw-r--r-- | StardewModdingAPI/Mod.cs | 2 | ||||
-rw-r--r-- | StardewModdingAPI/Program.cs | 1106 | ||||
-rw-r--r-- | StardewModdingAPI/StardewModdingAPI.csproj | 7 | ||||
-rw-r--r-- | StardewModdingAPI/obj/x86/Debug/StardewModdingAPI.csproj.FileListAbsolute.txt | 8 |
6 files changed, 620 insertions, 524 deletions
diff --git a/StardewModdingAPI/Command.cs b/StardewModdingAPI/Command.cs index f0162a4d..bb18a9a6 100644 --- a/StardewModdingAPI/Command.cs +++ b/StardewModdingAPI/Command.cs @@ -104,7 +104,7 @@ namespace StardewModdingAPI Program.LogError("Command failed to fire because it's fire event is null: " + CommandName); return; } - CommandFired.Invoke(this, null); + CommandFired.Invoke(this, new EventArgsCommand(this)); } } } diff --git a/StardewModdingAPI/Extensions.cs b/StardewModdingAPI/Extensions.cs index d2d8dce8..1bd589db 100644 --- a/StardewModdingAPI/Extensions.cs +++ b/StardewModdingAPI/Extensions.cs @@ -29,15 +29,26 @@ namespace StardewModdingAPI return result; } - public static bool IsInt32(this string s) + public static bool IsInt32(this object o) { int i; - return Int32.TryParse(s, out i); + return Int32.TryParse(o.ToString(), out i); } - public static Int32 AsInt32(this string s) + public static Int32 AsInt32(this object o) { - return Int32.Parse(s); + return Int32.Parse(o.ToString()); + } + + public static bool IsBool(this object o) + { + bool b; + return Boolean.TryParse(o.ToString(), out b); + } + + public static bool AsBool(this object o) + { + return Boolean.Parse(o.ToString()); } public static int GetHash(this IEnumerable enumerable) diff --git a/StardewModdingAPI/Mod.cs b/StardewModdingAPI/Mod.cs index 32021b4a..eabdc539 100644 --- a/StardewModdingAPI/Mod.cs +++ b/StardewModdingAPI/Mod.cs @@ -31,7 +31,7 @@ namespace StardewModdingAPI /// <summary> /// A basic method that is the entry-point of your mod. It will always be called once when the mod loads. /// </summary> - public virtual void Entry() + public virtual void Entry(params object[] objects) { } diff --git a/StardewModdingAPI/Program.cs b/StardewModdingAPI/Program.cs index 0903a9b9..a7065c69 100644 --- a/StardewModdingAPI/Program.cs +++ b/StardewModdingAPI/Program.cs @@ -1,513 +1,593 @@ -using System;
-using System.CodeDom.Compiler;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Microsoft.CSharp;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-using StardewModdingAPI.Inheritance;
-using StardewModdingAPI.Inheritance.Menus;
-using StardewValley;
-using StardewValley.Menus;
-using StardewValley.Minigames;
-using StardewValley.Network;
-using StardewValley.Tools;
-using Keys = Microsoft.Xna.Framework.Input.Keys;
-using Object = StardewValley.Object;
-
-namespace StardewModdingAPI
-{
- public class Program
- {
- public static string ExecutionPath { get; private set; }
- public static string DataPath = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley"));
- public static List<string> ModPaths = new List<string>();
- public static List<string> ModContentPaths = new List<string>();
- public static string LogPath = Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley")), "ErrorLogs");
- public static string CurrentLog { get; private set; }
- public static StreamWriter LogStream { get; private set; }
-
- public static Texture2D DebugPixel { get; private set; }
-
- public static SGame gamePtr;
- public static bool ready;
-
- public static Assembly StardewAssembly;
- public static Type StardewProgramType;
- public static FieldInfo StardewGameInfo;
- public static Form StardewForm;
-
- public static Thread gameThread;
- public static Thread consoleInputThread;
-
- public const string Version = "0.36 Alpha";
- public const bool debug = true;
- public static bool disableLogging { get; private set; }
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- [STAThread]
- private static void Main(string[] args)
- {
- Console.Title = "Stardew Modding API Console";
-
- Console.Title += " - Version " + Version;
- if (debug)
- Console.Title += " - DEBUG IS NOT FALSE, AUTHOUR NEEDS TO REUPLOAD THIS VERSION";
-
- //TODO: Have an app.config and put the paths inside it so users can define locations to load mods from
- ExecutionPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
- ModPaths.Add(Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley")), "Mods"));
- ModPaths.Add(Path.Combine(ExecutionPath, "Mods"));
- ModPaths.Add(Path.Combine(Path.Combine(ExecutionPath, "Mods"), "Content"));
- ModContentPaths.Add(Path.Combine(Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley")), "Mods"), "Content"));
-
- //Checks that all defined modpaths exist as directories
- foreach (string ModPath in ModPaths)
- {
- try
- {
- if (File.Exists(ModPath))
- File.Delete(ModPath);
- if (!Directory.Exists(ModPath))
- Directory.CreateDirectory(ModPath);
- }
- catch (Exception ex)
- {
-
- LogError("Could not create a missing ModPath: " + ModPath + "\n\n" + ex);
- }
- }
- //Same for content
- foreach (string ModContentPath in ModContentPaths)
- {
- try
- {
- if (!Directory.Exists(ModContentPath))
- Directory.CreateDirectory(ModContentPath);
- }
- catch (Exception ex)
- {
- LogError("Could not create a missing ModContentPath: " + ModContentPath + "\n\n" + ex);
- }
- }
- //And then make sure we have an errorlog dir
- try
- {
- if (!Directory.Exists(LogPath))
- Directory.CreateDirectory(LogPath);
- }
- catch (Exception ex)
- {
- LogError("Could not create the missing ErrorLogs path: " + LogPath + "\n\n" + ex);
- }
-
- //Define the path to the current log file
- CurrentLog = LogPath + "\\MODDED_ProgramLog_LATEST"/* + System.DateTime.Now.Ticks + */ + ".txt";
-
- Log(ExecutionPath, false);
-
- //Create a writer to the log file
- try
- {
- LogStream = new StreamWriter(CurrentLog, false);
- }
- catch (Exception ex)
- {
- disableLogging = true;
- LogError("Could not initialize LogStream - Logging is disabled");
- }
-
-
- LogInfo("Initializing SDV Assembly...");
- if (!File.Exists(ExecutionPath + "\\Stardew Valley.exe"))
- {
- //If the api isn't next to SDV.exe then terminate. Though it'll crash before we even get here w/o sdv.exe. Perplexing.
- LogError("Could not find: " + ExecutionPath + "\\Stardew Valley.exe");
- LogError("The API will now terminate.");
- Console.ReadKey();
- Environment.Exit(-4);
- }
-
- //Load in that assembly. Also, ignore security :D
- StardewAssembly = Assembly.UnsafeLoadFrom(ExecutionPath + "\\Stardew Valley.exe");
- StardewProgramType = StardewAssembly.GetType("StardewValley.Program", true);
- StardewGameInfo = StardewProgramType.GetField("gamePtr");
-
- //Change the game's version
- LogInfo("Injecting New SDV Version...");
- Game1.version += "-Z_MODDED | SMAPI " + Version;
-
- //Create the thread for the game to run in.
- gameThread = new Thread(RunGame);
- LogInfo("Starting SDV...");
- gameThread.Start();
-
- //I forget.
- SGame.GetStaticFields();
-
- while (!ready)
- {
- //Wait for the game to load up
- }
-
- //SDV is running
- Log("SDV Loaded Into Memory");
-
- //Create definition to listen for input
- LogInfo("Initializing Console Input Thread...");
- consoleInputThread = new Thread(ConsoleInputThread);
-
- //The only command in the API (at least it should be, for now)
- 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.KeyPressed += Events_KeyPressed;
- Events.LoadContent += Events_LoadContent;
- //Events.MenuChanged += Events_MenuChanged; //Idk right now
- if (debug)
- {
- //Experimental
- //Events.LocationsChanged += Events_LocationsChanged;
- //Events.CurrentLocationChanged += Events_CurrentLocationChanged;
- }
-
- //Do tweaks using winforms invoke because I'm lazy
- LogInfo("Applying Final SDV Tweaks...");
- StardewInvoke(() =>
- {
- gamePtr.IsMouseVisible = false;
- gamePtr.Window.Title = "Stardew Valley - Version " + Game1.version;
- StardewForm.Resize += Events.InvokeResize;
- });
-
- //Game's in memory now, send the event
- LogInfo("Game Loaded");
- Events.InvokeGameLoaded();
-
- LogColour(ConsoleColor.Cyan, "Type 'help' for help, or 'help <cmd>' for a command's usage");
- //Begin listening to input
- consoleInputThread.Start();
-
-
- while (ready)
- {
- //Check if the game is still running 10 times a second
- Thread.Sleep(1000 / 10);
- }
-
- //abort the thread, we're closing
- if (consoleInputThread != null && consoleInputThread.ThreadState == ThreadState.Running)
- consoleInputThread.Abort();
-
- LogInfo("Game Execution Finished");
- LogInfo("Shutting Down...");
- Thread.Sleep(100);
- /*
- int time = 0;
- int step = 100;
- int target = 1000;
- while (true)
- {
- time += step;
- Thread.Sleep(step);
-
- Console.Write(".");
-
- if (time >= target)
- break;
- }
- */
- Environment.Exit(0);
- }
-
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-
- public static void RunGame()
- {
- //Does this even do anything???
- Application.ThreadException += Application_ThreadException;
- Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- //I've yet to see it called :|
-
- try
- {
- gamePtr = new SGame();
- LogInfo("Patching SDV Graphics Profile...");
- Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef;
- LoadMods();
-
- StardewForm = Control.FromHandle(Program.gamePtr.Window.Handle).FindForm();
- StardewForm.Closing += StardewForm_Closing;
- StardewGameInfo.SetValue(StardewProgramType, gamePtr);
-
- ready = true;
-
- gamePtr.Run();
- }
- catch (Exception ex)
- {
- LogError("Game failed to start: " + ex);
- }
- }
-
- static void StardewForm_Closing(object sender, CancelEventArgs e)
- {
- e.Cancel = true;
- gamePtr.Exit();
- gamePtr.Dispose();
- StardewForm.Hide();
- ready = false;
- }
-
- public static void LoadMods()
- {
- LogColour(ConsoleColor.Green, "LOADING MODS");
- int loadedMods = 0;
- foreach (string ModPath in ModPaths)
- {
- foreach (String s in Directory.GetFiles(ModPath, "*.dll"))
- {
- LogColour(ConsoleColor.Green, "Found DLL: " + s);
- try
- {
- Assembly mod = Assembly.UnsafeLoadFrom(s); //to combat internet-downloaded DLLs
-
- if (mod.DefinedTypes.Count(x => x.BaseType == typeof (Mod)) > 0)
- {
- LogColour(ConsoleColor.Green, "Loading Mod DLL...");
- TypeInfo tar = mod.DefinedTypes.First(x => x.BaseType == typeof (Mod));
- Mod m = (Mod) mod.CreateInstance(tar.ToString());
- Console.WriteLine("LOADED MOD: {0} by {1} - Version {2} | Description: {3}", m.Name, m.Authour, m.Version, m.Description);
- loadedMods += 1;
- m.Entry();
- }
- else
- {
- LogError("Invalid Mod DLL");
- }
- }
- catch (Exception ex)
- {
- LogError("Failed to load mod '{0}'. Exception details:\n" + ex, s);
- }
- }
- }
- LogColour(ConsoleColor.Green, "LOADED {0} MODS", loadedMods);
- }
-
- public static void ConsoleInputThread()
- {
- string input = string.Empty;
-
- while (true)
- {
- Command.CallCommand(Console.ReadLine());
- }
- }
-
- static void Events_LoadContent(object sender, EventArgs e)
- {
- LogInfo("Initializing Debug Assets...");
- DebugPixel = new Texture2D(Game1.graphics.GraphicsDevice, 1, 1);
- DebugPixel.SetData(new Color[] { Color.White });
-
- if (debug)
- {
- LogColour(ConsoleColor.Magenta, "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;
- LogColour(ConsoleColor.Cyan, "REGISTERED WITH ID OF: " + SGame.RegisterModItem(so));
-
- LogColour(ConsoleColor.Magenta, "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;
- LogColour(ConsoleColor.Cyan, "REGISTERED WITH ID OF: " + SGame.RegisterModItem(so2));
- }
-
- if (debug)
- Command.CallCommand("load");
- }
-
- static void Events_KeyPressed(object key, EventArgs e)
- {
-
- }
-
- static void Events_MenuChanged(IClickableMenu newMenu)
- {
- LogInfo("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);
- }
- }
-
- 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);
- }
- //Game1.currentLocation = SGame.CurrentLocation;
- //LogInfo(((SGameLocation) newLocation).name);
- //LogInfo("LOC CHANGED: " + SGame.currentLocation.name);
- }
-
- public static void StardewInvoke(Action a)
- {
- StardewForm.Invoke(a);
- }
-
- static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- Console.WriteLine("An exception has been caught");
- File.WriteAllText(Program.LogPath + "\\MODDED_ErrorLog_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.ExceptionObject.ToString());
- }
-
- static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
- {
- Console.WriteLine("A thread exception has been caught");
- File.WriteAllText(Program.LogPath + "\\MODDED_ErrorLog_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.Exception.ToString());
- }
-
- static void help_CommandFired(object sender, EventArgs e)
- {
- Command cmd = sender as Command;
- if (cmd.CalledArgs.Length > 0)
- {
- Command fnd = Command.FindCommand(cmd.CalledArgs[0]);
- if (fnd == null)
- LogError("The command specified could not be found");
- else
- {
- if (fnd.CommandArgs.Length > 0)
- LogInfo("{0}: {1} - {2}", fnd.CommandName, fnd.CommandDesc, fnd.CommandArgs.ToSingular());
- else
- LogInfo("{0}: {1}", fnd.CommandName, fnd.CommandDesc);
- }
- }
- else
- LogInfo("Commands: " + Command.RegisteredCommands.Select(x => x.CommandName).ToSingular());
- }
-
- #region Logging
-
- public static void Log(object o, params object[] format)
- {
- if (format.Length > 0)
- {
- if (format[0] is bool)
- {
- if ((bool)format[0] == false)
- {
- //suppress logging to file
- Console.WriteLine("[{0}] {1}", System.DateTime.Now.ToLongTimeString(), String.Format(o.ToString(), format));
- return;
- }
- }
- }
- string toLog = string.Format("[{0}] {1}", System.DateTime.Now.ToLongTimeString(), String.Format(o.ToString(), format));
- Console.WriteLine(toLog);
-
- if (!disableLogging)
- {
- LogStream.WriteLine(toLog);
- LogStream.Flush();
- }
- }
-
- public static void LogColour(ConsoleColor c, object o, params object[] format)
- {
- Console.ForegroundColor = c;
- Log(o.ToString(), format);
- Console.ForegroundColor = ConsoleColor.Gray;
- }
-
- public static void LogInfo(object o, params object[] format)
- {
- Console.ForegroundColor = ConsoleColor.Yellow;
- Log(o.ToString(), format);
- Console.ForegroundColor = ConsoleColor.Gray;
- }
-
- public static void LogError(object o, params object[] format)
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Log(o.ToString(), format);
- Console.ForegroundColor = ConsoleColor.Gray;
- }
-
- public static void LogDebug(object o, params object[] format)
- {
- if (!debug)
- return;
- Console.ForegroundColor = ConsoleColor.DarkYellow;
- Log(o.ToString(), format);
- Console.ForegroundColor = ConsoleColor.Gray;
- }
-
- public static void LogValueNotSpecified()
- {
- LogError("<value> must be specified");
- }
-
- public static void LogObjectValueNotSpecified()
- {
- LogError("<object> and <value> must be specified");
- }
-
- public static void LogValueInvalid()
- {
- LogError("<value> is invalid");
- }
-
- public static void LogObjectInvalid()
- {
- LogError("<object> is invalid");
- }
-
- public static void LogValueNotInt32()
- {
- LogError("<value> must be a whole number (Int32)");
- }
-
- #endregion
- }
-}
+using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Microsoft.CSharp; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using StardewModdingAPI.Inheritance; +using StardewModdingAPI.Inheritance.Menus; +using StardewValley; +using StardewValley.Menus; +using StardewValley.Minigames; +using StardewValley.Network; +using StardewValley.Tools; +using Keys = Microsoft.Xna.Framework.Input.Keys; +using Object = StardewValley.Object; + +namespace StardewModdingAPI +{ + public class Program + { + public static string ExecutionPath { get; private set; } + public static string DataPath = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley")); + public static List<string> ModPaths = new List<string>(); + public static List<string> ModContentPaths = new List<string>(); + public static string LogPath = Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley")), "ErrorLogs"); + public static string CurrentLog { get; private set; } + public static StreamWriter LogStream { get; private set; } + + public static Texture2D DebugPixel { get; private set; } + + public static SGame gamePtr; + public static bool ready; + + public static Assembly StardewAssembly; + public static Type StardewProgramType; + public static FieldInfo StardewGameInfo; + public static Form StardewForm; + + public static Thread gameThread; + public static Thread consoleInputThread; + + public const string Version = "0.36 Alpha"; + public const bool debug = true; + public static bool disableLogging { get; private set; } + + public static bool StardewInjectorLoaded { get; private set; } + public static Mod StardewInjectorMod { get; private set; } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + private static void Main(string[] args) + { + Console.Title = "Stardew Modding API Console"; + + Console.Title += " - Version " + Version; + if (debug) + Console.Title += " - DEBUG IS NOT FALSE, AUTHOUR NEEDS TO REUPLOAD THIS VERSION"; + + //TODO: Have an app.config and put the paths inside it so users can define locations to load mods from + ExecutionPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + ModPaths.Add(Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley")), "Mods")); + ModPaths.Add(Path.Combine(ExecutionPath, "Mods")); + ModPaths.Add(Path.Combine(Path.Combine(ExecutionPath, "Mods"), "Content")); + ModContentPaths.Add(Path.Combine(Path.Combine(Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley")), "Mods"), "Content")); + + //Checks that all defined modpaths exist as directories + foreach (string ModPath in ModPaths) + { + try + { + if (File.Exists(ModPath)) + File.Delete(ModPath); + if (!Directory.Exists(ModPath)) + Directory.CreateDirectory(ModPath); + } + catch (Exception ex) + { + LogError("Could not create a missing ModPath: " + ModPath + "\n\n" + ex); + } + } + //Same for content + foreach (string ModContentPath in ModContentPaths) + { + try + { + if (!Directory.Exists(ModContentPath)) + Directory.CreateDirectory(ModContentPath); + } + catch (Exception ex) + { + LogError("Could not create a missing ModContentPath: " + ModContentPath + "\n\n" + ex); + } + } + //And then make sure we have an errorlog dir + try + { + if (!Directory.Exists(LogPath)) + Directory.CreateDirectory(LogPath); + } + catch (Exception ex) + { + LogError("Could not create the missing ErrorLogs path: " + LogPath + "\n\n" + ex); + } + + //Define the path to the current log file + CurrentLog = LogPath + "\\MODDED_ProgramLog_LATEST"/* + System.DateTime.Now.Ticks + */ + ".txt"; + + Log(ExecutionPath, false); + + //Create a writer to the log file + try + { + LogStream = new StreamWriter(CurrentLog, false); + } + catch (Exception ex) + { + disableLogging = true; + LogError("Could not initialize LogStream - Logging is disabled"); + } + + + LogInfo("Initializing SDV Assembly..."); + if (!File.Exists(ExecutionPath + "\\Stardew Valley.exe")) + { + //If the api isn't next to SDV.exe then terminate. Though it'll crash before we even get here w/o sdv.exe. Perplexing. + LogError("Could not find: " + ExecutionPath + "\\Stardew Valley.exe"); + LogError("The API will now terminate."); + Console.ReadKey(); + Environment.Exit(-4); + } + + //Load in that assembly. Also, ignore security :D + StardewAssembly = Assembly.UnsafeLoadFrom(ExecutionPath + "\\Stardew Valley.exe"); + + foreach (string ModPath in ModPaths) + { + foreach (String s in Directory.GetFiles(ModPath, "StardewInjector.dll")) + { + LogColour(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) + { + LogColour(ConsoleColor.Green, "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 + { + LogError("Invalid Mod DLL"); + } + } + catch (Exception ex) + { + LogError("Failed to load mod '{0}'. Exception details:\n" + ex, s); + } + } + } + + StardewProgramType = StardewAssembly.GetType("StardewValley.Program", true); + StardewGameInfo = StardewProgramType.GetField("gamePtr"); + + /* + if (File.Exists(ExecutionPath + "\\Stardew_Injector.exe")) + { + //Stardew_Injector Mode + StardewInjectorLoaded = true; + Program.LogInfo("STARDEW_INJECTOR DETECTED, LAUNCHING USING INJECTOR CALLS"); + Assembly inj = Assembly.UnsafeLoadFrom(ExecutionPath + "\\Stardew_Injector.exe"); + Type prog = inj.GetType("Stardew_Injector.Program", true); + FieldInfo hooker = prog.GetField("hooker", BindingFlags.NonPublic | BindingFlags.Static); + + //hook.GetMethod("Initialize").Invoke(hooker.GetValue(null), null); + //customize the initialize method for SGame instead of Game + Assembly cecil = Assembly.UnsafeLoadFrom(ExecutionPath + "\\Mono.Cecil.dll"); + Type assDef = cecil.GetType("Mono.Cecil.AssemblyDefinition"); + var aDefs = assDef.GetMethods(BindingFlags.Public | BindingFlags.Static); + var aDef = aDefs.First(x => x.ToString().Contains("ReadAssembly(System.String)")); + var theAssDef = aDef.Invoke(null, new object[] { Assembly.GetExecutingAssembly().Location }); + var modDef = assDef.GetProperty("MainModule", BindingFlags.Public | BindingFlags.Instance); + var theModDef = modDef.GetValue(theAssDef); + Console.WriteLine("MODDEF: " + theModDef); + Type hook = inj.GetType("Stardew_Injector.Stardew_Hooker", true); + hook.GetField("m_vAsmDefinition", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(hooker.GetValue(null), theAssDef); + hook.GetField("m_vModDefinition", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(hooker.GetValue(null), theModDef); + + //hook.GetMethod("Initialize").Invoke(hooker.GetValue(null), null); + hook.GetMethod("ApplyHooks").Invoke(hooker.GetValue(null), null); + //hook.GetMethod("Finalize").Invoke(hooker.GetValue(null), null); + //hook.GetMethod("Run").Invoke(hooker.GetValue(null), null); + + Console.ReadKey(); + //Now go back and load Stardew through SMAPI + } + */ + + //Change the game's version + LogInfo("Injecting New SDV Version..."); + Game1.version += "-Z_MODDED | SMAPI " + Version; + + //Create the thread for the game to run in. + gameThread = new Thread(RunGame); + LogInfo("Starting SDV..."); + gameThread.Start(); + + //I forget. + SGame.GetStaticFields(); + + while (!ready) + { + //Wait for the game to load up + } + + //SDV is running + Log("SDV Loaded Into Memory"); + + //Create definition to listen for input + LogInfo("Initializing Console Input Thread..."); + consoleInputThread = new Thread(ConsoleInputThread); + + //The only command in the API (at least it should be, for now)\ + + 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.KeyPressed += Events_KeyPressed; + Events.LoadContent += Events_LoadContent; + //Events.MenuChanged += Events_MenuChanged; //Idk right now + if (debug) + { + //Experimental + //Events.LocationsChanged += Events_LocationsChanged; + //Events.CurrentLocationChanged += Events_CurrentLocationChanged; + } + + //Do tweaks using winforms invoke because I'm lazy + LogInfo("Applying Final SDV Tweaks..."); + StardewInvoke(() => + { + gamePtr.IsMouseVisible = false; + gamePtr.Window.Title = "Stardew Valley - Version " + Game1.version; + StardewForm.Resize += Events.InvokeResize; + }); + + //Game's in memory now, send the event + LogInfo("Game Loaded"); + Events.InvokeGameLoaded(); + + LogColour(ConsoleColor.Cyan, "Type 'help' for help, or 'help <cmd>' for a command's usage"); + //Begin listening to input + consoleInputThread.Start(); + + + while (ready) + { + //Check if the game is still running 10 times a second + Thread.Sleep(1000 / 10); + } + + //abort the thread, we're closing + if (consoleInputThread != null && consoleInputThread.ThreadState == ThreadState.Running) + consoleInputThread.Abort(); + + LogInfo("Game Execution Finished"); + LogInfo("Shutting Down..."); + Thread.Sleep(100); + /* + int time = 0; + int step = 100; + int target = 1000; + while (true) + { + time += step; + Thread.Sleep(step); + + Console.Write("."); + + if (time >= target) + break; + } + */ + Environment.Exit(0); + } + + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + public static void RunGame() + { + //Does this even do anything??? + Application.ThreadException += Application_ThreadException; + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + //I've yet to see it called :| + + try + { + gamePtr = new SGame(); + LogInfo("Patching SDV Graphics Profile..."); + Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; + LoadMods(); + + StardewForm = Control.FromHandle(Program.gamePtr.Window.Handle).FindForm(); + StardewForm.Closing += StardewForm_Closing; + + ready = true; + + if (StardewInjectorLoaded) + { + //StardewInjectorMod.Entry(true); + StardewAssembly.EntryPoint.Invoke(null, new object[] {new string[0]}); + StardewGameInfo.SetValue(StardewProgramType, gamePtr); + } + else + { + StardewGameInfo.SetValue(StardewProgramType, gamePtr); + gamePtr.Run(); + } + } + catch (Exception ex) + { + LogError("Game failed to start: " + ex); + } + } + + static void StardewForm_Closing(object sender, CancelEventArgs e) + { + e.Cancel = true; + gamePtr.Exit(); + gamePtr.Dispose(); + StardewForm.Hide(); + ready = false; + } + + public static void LoadMods() + { + LogColour(ConsoleColor.Green, "LOADING MODS"); + int loadedMods = 0; + foreach (string ModPath in ModPaths) + { + foreach (String s in Directory.GetFiles(ModPath, "*.dll")) + { + if (s.Contains("StardewInjector")) + continue; + LogColour(ConsoleColor.Green, "Found DLL: " + s); + try + { + Assembly mod = Assembly.UnsafeLoadFrom(s); //to combat internet-downloaded DLLs + + if (mod.DefinedTypes.Count(x => x.BaseType == typeof (Mod)) > 0) + { + LogColour(ConsoleColor.Green, "Loading Mod DLL..."); + TypeInfo tar = mod.DefinedTypes.First(x => x.BaseType == typeof (Mod)); + Mod m = (Mod) mod.CreateInstance(tar.ToString()); + Console.WriteLine("LOADED MOD: {0} by {1} - Version {2} | Description: {3}", m.Name, m.Authour, m.Version, m.Description); + loadedMods += 1; + m.Entry(); + } + else + { + LogError("Invalid Mod DLL"); + } + } + catch (Exception ex) + { + LogError("Failed to load mod '{0}'. Exception details:\n" + ex, s); + } + } + } + LogColour(ConsoleColor.Green, "LOADED {0} MODS", loadedMods); + } + + public static void ConsoleInputThread() + { + string input = string.Empty; + + while (true) + { + Command.CallCommand(Console.ReadLine()); + } + } + + static void Events_LoadContent(object o, EventArgs e) + { + LogInfo("Initializing Debug Assets..."); + DebugPixel = new Texture2D(Game1.graphics.GraphicsDevice, 1, 1); + DebugPixel.SetData(new Color[] { Color.White }); + + if (debug) + { + LogColour(ConsoleColor.Magenta, "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; + LogColour(ConsoleColor.Cyan, "REGISTERED WITH ID OF: " + SGame.RegisterModItem(so)); + + LogColour(ConsoleColor.Magenta, "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; + LogColour(ConsoleColor.Cyan, "REGISTERED WITH ID OF: " + SGame.RegisterModItem(so2)); + } + + if (debug) + Command.CallCommand("load"); + } + + static void Events_KeyPressed(object o, EventArgsKeyPressed e) + { + + } + + static void Events_MenuChanged(IClickableMenu newMenu) + { + LogInfo("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); + } + } + + 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); + } + //Game1.currentLocation = SGame.CurrentLocation; + //LogInfo(((SGameLocation) newLocation).name); + //LogInfo("LOC CHANGED: " + SGame.currentLocation.name); + } + + public static void StardewInvoke(Action a) + { + StardewForm.Invoke(a); + } + + static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + Console.WriteLine("An exception has been caught"); + File.WriteAllText(Program.LogPath + "\\MODDED_ErrorLog_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.ExceptionObject.ToString()); + } + + static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) + { + Console.WriteLine("A thread exception has been caught"); + File.WriteAllText(Program.LogPath + "\\MODDED_ErrorLog_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.Exception.ToString()); + } + + static void help_CommandFired(object o, EventArgsCommand e) + { + if (e.Command.CalledArgs.Length > 0) + { + Command fnd = Command.FindCommand(e.Command.CalledArgs[0]); + if (fnd == null) + LogError("The command specified could not be found"); + else + { + if (fnd.CommandArgs.Length > 0) + LogInfo("{0}: {1} - {2}", fnd.CommandName, fnd.CommandDesc, fnd.CommandArgs.ToSingular()); + else + LogInfo("{0}: {1}", fnd.CommandName, fnd.CommandDesc); + } + } + else + LogInfo("Commands: " + Command.RegisteredCommands.Select(x => x.CommandName).ToSingular()); + } + + #region Logging + + public static void Log(object o, params object[] format) + { + if (format.Length > 0) + { + if (format[0] is bool) + { + if ((bool)format[0] == false) + { + //suppress logging to file + Console.WriteLine("[{0}] {1}", System.DateTime.Now.ToLongTimeString(), String.Format(o.ToString(), format)); + return; + } + } + } + string toLog = string.Format("[{0}] {1}", System.DateTime.Now.ToLongTimeString(), String.Format(o.ToString(), format)); + Console.WriteLine(toLog); + + if (!disableLogging) + { + LogStream.WriteLine(toLog); + LogStream.Flush(); + } + } + + public static void LogColour(ConsoleColor c, object o, params object[] format) + { + Console.ForegroundColor = c; + Log(o.ToString(), format); + Console.ForegroundColor = ConsoleColor.Gray; + } + + public static void LogInfo(object o, params object[] format) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Log(o.ToString(), format); + Console.ForegroundColor = ConsoleColor.Gray; + } + + public static void LogError(object o, params object[] format) + { + Console.ForegroundColor = ConsoleColor.Red; + Log(o.ToString(), format); + Console.ForegroundColor = ConsoleColor.Gray; + } + + public static void LogDebug(object o, params object[] format) + { + if (!debug) + return; + Console.ForegroundColor = ConsoleColor.DarkYellow; + Log(o.ToString(), format); + Console.ForegroundColor = ConsoleColor.Gray; + } + + public static void LogValueNotSpecified() + { + LogError("<value> must be specified"); + } + + public static void LogObjectValueNotSpecified() + { + LogError("<object> and <value> must be specified"); + } + + public static void LogValueInvalid() + { + LogError("<value> is invalid"); + } + + public static void LogObjectInvalid() + { + LogError("<object> is invalid"); + } + + public static void LogValueNotInt32() + { + LogError("<value> must be a whole number (Int32)"); + } + + #endregion + } +}
\ No newline at end of file diff --git a/StardewModdingAPI/StardewModdingAPI.csproj b/StardewModdingAPI/StardewModdingAPI.csproj index 58ad0399..7d3e129c 100644 --- a/StardewModdingAPI/StardewModdingAPI.csproj +++ b/StardewModdingAPI/StardewModdingAPI.csproj @@ -47,16 +47,13 @@ <ApplicationIcon>icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Microsoft.QualityTools.Testing.Fakes, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <Private>False</Private>
- </Reference>
<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="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="Stardew Valley, Version=1.0.5900.38427, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
+ <HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
<EmbedInteropTypes>False</EmbedInteropTypes>
<Private>False</Private>
</Reference>
@@ -71,7 +68,7 @@ <Reference Include="System.Xml" />
<Reference Include="xTile, Version=2.0.4.0, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
- <HintPath>D:\#Network-Steam\SteamRepo\steamapps\common\Stardew Valley\xTile.dll</HintPath>
+ <HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\xTile.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
diff --git a/StardewModdingAPI/obj/x86/Debug/StardewModdingAPI.csproj.FileListAbsolute.txt b/StardewModdingAPI/obj/x86/Debug/StardewModdingAPI.csproj.FileListAbsolute.txt index 241cf998..38097ea8 100644 --- a/StardewModdingAPI/obj/x86/Debug/StardewModdingAPI.csproj.FileListAbsolute.txt +++ b/StardewModdingAPI/obj/x86/Debug/StardewModdingAPI.csproj.FileListAbsolute.txt @@ -30,9 +30,17 @@ C:\TFSource\Master-Collection\StardewModdingAPI\StardewModdingAPI\bin\x86\Debug\ C:\TFSource\Master-Collection\StardewModdingAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.exe
C:\TFSource\Master-Collection\StardewModdingAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.pdb
C:\TFSource\Master-Collection\StardewModdingAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.csprojResolveAssemblyReference.cache
+C:\Users\zoryn\Documents\GitHub\SMAPI\StardewModdingAPI\bin\x86\Debug\StardewModdingAPI.exe.config
+C:\Users\zoryn\Documents\GitHub\SMAPI\StardewModdingAPI\bin\x86\Debug\steam_appid.txt
+C:\Users\zoryn\Documents\GitHub\SMAPI\StardewModdingAPI\bin\x86\Debug\StardewModdingAPI.exe
+C:\Users\zoryn\Documents\GitHub\SMAPI\StardewModdingAPI\bin\x86\Debug\StardewModdingAPI.pdb
+C:\Users\zoryn\Documents\GitHub\SMAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.csprojResolveAssemblyReference.cache
+C:\Users\zoryn\Documents\GitHub\SMAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.exe
+C:\Users\zoryn\Documents\GitHub\SMAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.pdb
Z:\Projects\C#\SMAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.exe
Z:\Projects\C#\SMAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.pdb
Z:\Projects\C#\SMAPI\StardewModdingAPI\bin\x86\Debug\steam_appid.txt
Z:\Projects\C#\SMAPI\StardewModdingAPI\bin\x86\Debug\StardewModdingAPI.exe.config
Z:\Projects\C#\SMAPI\StardewModdingAPI\bin\x86\Debug\StardewModdingAPI.exe
Z:\Projects\C#\SMAPI\StardewModdingAPI\bin\x86\Debug\StardewModdingAPI.pdb
+Z:\Projects\C#\SMAPI\StardewModdingAPI\obj\x86\Debug\StardewModdingAPI.csprojResolveAssemblyReference.cache
|