diff --git a/README.md b/README.md index d153428b..140c15fa 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,16 @@ A Modding API For Stardew Valley See: https://github.com/Zoryn4163/SMAPI-Mods +NOTICE: THIS PROJECT IS STILL IN ALPHA + +Mod directories: %appdata%\StardewValley\Mods\ and .\Mods\ <- That means next to StardewModdingApi.exe in the Mods folder! + +To install a mod, put a DLL in one of those directories. If you are not on the latest version, do not post any errors, issues, etc. + + + +NOTICE: THIS PART AND ONWARD REQUIRE VISUAL STUDIOS AND KNOWLEDGE OF C# PROGRAMMING + You can create a mod by making a direct reference to the ModdingApi.exe From there, you need to inherit from StardewModdingAPI.Mod diff --git a/Release/Mods/TrainerMod.dll b/Release/Mods/TrainerMod.dll index 790f0444..9fc10782 100644 Binary files a/Release/Mods/TrainerMod.dll and b/Release/Mods/TrainerMod.dll differ diff --git a/Release/SMAPI_0.35.zip b/Release/SMAPI_0.35.zip new file mode 100644 index 00000000..fd587597 Binary files /dev/null and b/Release/SMAPI_0.35.zip differ diff --git a/Release/StardewModdingAPI.exe b/Release/StardewModdingAPI.exe index c6c9e3cc..aa593708 100644 Binary files a/Release/StardewModdingAPI.exe and b/Release/StardewModdingAPI.exe differ diff --git a/StardewModdingAPI/Command.cs b/StardewModdingAPI/Command.cs index 1659b1e9..c65e8122 100644 --- a/StardewModdingAPI/Command.cs +++ b/StardewModdingAPI/Command.cs @@ -30,7 +30,7 @@ namespace StardewModdingAPI { args = input.Split(new[] {" "}, 2, StringSplitOptions.RemoveEmptyEntries); fnd = FindCommand(args[0]); - args = args[1].Split(new[] { " " }, 2, StringSplitOptions.RemoveEmptyEntries); + args = args[1].Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries); } else { diff --git a/StardewModdingAPI/Events.cs b/StardewModdingAPI/Events.cs index 05cabc4b..97e55d8d 100644 --- a/StardewModdingAPI/Events.cs +++ b/StardewModdingAPI/Events.cs @@ -39,6 +39,17 @@ namespace StardewModdingAPI public static event EventHandler Resize = delegate { }; + public delegate void FarmerChangedD(Farmer newFarmer); + public static event FarmerChangedD FarmerChanged = delegate { }; + + public delegate void IntChanged(Int32 newInt); + public static event IntChanged TimeOfDayChanged = delegate { }; + public static event IntChanged DayOfMonthChanged = delegate { }; + public static event IntChanged YearOfGameChanged = delegate { }; + + public delegate void StringChanged(String newString); + public static event StringChanged SeasonOfYearChanged = delegate { }; + public static void InvokeGameLoaded() { GameLoaded.Invoke(); @@ -126,5 +137,30 @@ namespace StardewModdingAPI { Resize.Invoke(sender, e); } + + public static void InvokeFarmerChanged(Farmer newFarmer) + { + FarmerChanged.Invoke(newFarmer); + } + + public static void InvokeTimeOfDayChanged(Int32 newInt) + { + TimeOfDayChanged.Invoke(newInt); + } + + public static void InvokeDayOfMonthChanged(Int32 newInt) + { + DayOfMonthChanged.Invoke(newInt); + } + + public static void InvokeYearOfGameChanged(Int32 newInt) + { + YearOfGameChanged.Invoke(newInt); + } + + public static void InvokeSeasonOfYearChanged(String newString) + { + SeasonOfYearChanged.Invoke(newString); + } } } diff --git a/StardewModdingAPI/Inheritance/SGame.cs b/StardewModdingAPI/Inheritance/SGame.cs index fdc6f3f7..99db73d9 100644 --- a/StardewModdingAPI/Inheritance/SGame.cs +++ b/StardewModdingAPI/Inheritance/SGame.cs @@ -1,19 +1,12 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using System.Threading.Tasks; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using StardewValley; using StardewValley.Menus; -using StardewValley.Minigames; namespace StardewModdingAPI.Inheritance { @@ -49,6 +42,21 @@ namespace StardewModdingAPI.Inheritance public GameLocation PreviousGameLocation { get; private set; } public IClickableMenu PreviousActiveMenu { get; private set; } + public Int32 PreviousTimeOfDay { get; private set; } + public Int32 PreviousDayOfMonth { get; private set; } + public String PreviousSeasonOfYear { get; private set; } + public Int32 PreviousYearOfGame { get; private set; } + + public Farmer PreviousFarmer { get; private set; } + + public SGame() + { + if (Program.debug) + { + //SaveGame.serializer. + } + } + protected override void Initialize() { Program.Log("XNA Initialize"); @@ -67,47 +75,18 @@ namespace StardewModdingAPI.Inheritance protected override void Update(GameTime gameTime) { - KStateNow = Keyboard.GetState(); - CurrentlyPressedKeys = KStateNow.GetPressedKeys(); - MStateNow = Mouse.GetState(); - - foreach (Keys k in FramePressedKeys) - Events.InvokeKeyPressed(k); + UpdateEventCalls(); - if (KStateNow != KStatePrior) + try { - Events.InvokeKeyboardChanged(KStateNow); - KStatePrior = KStateNow; + base.Update(gameTime); + } + catch (Exception ex) + { + Program.LogError("An error occured in the base update loop: " + ex); + Console.ReadKey(); } - if (MStateNow != MStatePrior) - { - Events.InvokeMouseChanged(MStateNow); - MStatePrior = MStateNow; - } - - if (Game1.activeClickableMenu != null && Game1.activeClickableMenu != PreviousActiveMenu) - { - Events.InvokeMenuChanged(Game1.activeClickableMenu); - PreviousActiveMenu = Game1.activeClickableMenu; - } - - if (Game1.locations.GetHash() != PreviousGameLocations) - { - Events.InvokeLocationsChanged(Game1.locations); - PreviousGameLocations = Game1.locations.GetHash(); - } - - if (Game1.currentLocation != PreviousGameLocation) - { - Events.InvokeCurrentLocationChanged(Game1.currentLocation); - PreviousGameLocation = Game1.currentLocation; - } - - if (CurrentLocation != null) - CurrentLocation.update(gameTime); - - base.Update(gameTime); Events.InvokeUpdateTick(); PreviouslyPressedKeys = CurrentlyPressedKeys; @@ -118,15 +97,15 @@ namespace StardewModdingAPI.Inheritance base.Draw(gameTime); Events.InvokeDrawTick(); - if (Program.debug) + if (false) { spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); if (CurrentLocation != null) - CurrentLocation.draw(Game1.spriteBatch); + CurrentLocation.draw(spriteBatch); if (player != null && player.position != null) - spriteBatch.DrawString(Game1.dialogueFont, Game1.player.position.ToString(), new Vector2(0, 180), Color.Orange); + spriteBatch.DrawString(dialogueFont, player.position.ToString(), new Vector2(0, 180), Color.Orange); spriteBatch.End(); } @@ -156,24 +135,15 @@ namespace StardewModdingAPI.Inheritance { return ModItems.ElementAt(id).Value.Clone(); } - else - { - Program.LogError("ModItem Dictionary does not contain index: " + id); - return null; - } + Program.LogError("ModItem Dictionary does not contain index: " + id); + return null; } - else + if (ModItems.ContainsKey(id)) { - if (ModItems.ContainsKey(id)) - { - return ModItems[id].Clone(); - } - else - { - Program.LogError("ModItem Dictionary does not contain ID: " + id); - return null; - } + return ModItems[id].Clone(); } + Program.LogError("ModItem Dictionary does not contain ID: " + id); + return null; } public static SGameLocation GetLocationFromName(String name) @@ -184,5 +154,101 @@ namespace StardewModdingAPI.Inheritance } return null; } + + public static SGameLocation LoadOrCreateSGameLocationFromName(String name) + { + if (GetLocationFromName(name) != null) + return GetLocationFromName(name); + GameLocation gl = locations.FirstOrDefault(x => x.name == name); + if (gl != null) + { + Program.LogDebug("A custom location was created for the new name: " + name); + SGameLocation s = SGameLocation.ConstructFromBaseClass(gl); + ModLocations.Add(s); + return s; + } + if (currentLocation != null && currentLocation.name == name) + { + gl = currentLocation; + Program.LogDebug("A custom location was created from the current location for the new name: " + name); + SGameLocation s = SGameLocation.ConstructFromBaseClass(gl); + ModLocations.Add(s); + return s; + } + + Program.LogDebug("A custom location could not be created for: " + name); + return null; + } + + + public void UpdateEventCalls() + { + KStateNow = Keyboard.GetState(); + CurrentlyPressedKeys = KStateNow.GetPressedKeys(); + MStateNow = Mouse.GetState(); + + foreach (Keys k in FramePressedKeys) + Events.InvokeKeyPressed(k); + + if (KStateNow != KStatePrior) + { + Events.InvokeKeyboardChanged(KStateNow); + KStatePrior = KStateNow; + } + + if (MStateNow != MStatePrior) + { + Events.InvokeMouseChanged(MStateNow); + MStatePrior = MStateNow; + } + + if (activeClickableMenu != null && activeClickableMenu != PreviousActiveMenu) + { + Events.InvokeMenuChanged(activeClickableMenu); + PreviousActiveMenu = activeClickableMenu; + } + + if (locations.GetHash() != PreviousGameLocations) + { + Events.InvokeLocationsChanged(locations); + PreviousGameLocations = locations.GetHash(); + } + + if (currentLocation != PreviousGameLocation) + { + Events.InvokeCurrentLocationChanged(currentLocation); + PreviousGameLocation = currentLocation; + } + + if (player != null && player != PreviousFarmer) + { + Events.InvokeFarmerChanged(player); + PreviousFarmer = player; + } + + if (timeOfDay != PreviousTimeOfDay) + { + Events.InvokeTimeOfDayChanged(timeOfDay); + PreviousTimeOfDay = timeOfDay; + } + + if (dayOfMonth != PreviousDayOfMonth) + { + Events.InvokeDayOfMonthChanged(dayOfMonth); + PreviousDayOfMonth = dayOfMonth; + } + + if (currentSeason != PreviousSeasonOfYear) + { + Events.InvokeSeasonOfYearChanged(currentSeason); + PreviousSeasonOfYear = currentSeason; + } + + if (year != PreviousYearOfGame) + { + Events.InvokeYearOfGameChanged(year); + PreviousYearOfGame = year; + } + } } } \ No newline at end of file diff --git a/StardewModdingAPI/Inheritance/SGameLocation.cs b/StardewModdingAPI/Inheritance/SGameLocation.cs index 14d9afa6..0787c0e1 100644 --- a/StardewModdingAPI/Inheritance/SGameLocation.cs +++ b/StardewModdingAPI/Inheritance/SGameLocation.cs @@ -12,91 +12,47 @@ using StardewValley.BellsAndWhistles; namespace StardewModdingAPI.Inheritance { + [Obsolete] public class SGameLocation : GameLocation { public GameLocation BaseGameLocation { get; private set; } public SerializableDictionary ModObjects { get; set; } - public static SGameLocation ConstructFromBaseClass(GameLocation baseClass) + public static SGameLocation ConstructFromBaseClass(GameLocation baseClass, bool copyAllData = false) { SGameLocation s = new SGameLocation(); s.BaseGameLocation = baseClass; - s.ModObjects = new SerializableDictionary(); + s.name = baseClass.name; - foreach (var v in baseClass.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + Program.LogDebug("CONSTRUCTED: " + s.name); + + if (copyAllData) { - try + foreach (var v in baseClass.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { - var fi = s.GetType().GetField(v.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - if (fi != null && !fi.IsStatic) + try { - fi.SetValue(s, v.GetValue(baseClass)); - //Console.WriteLine("SET {0} ON {1} TO {2}", fi.Name, s.name, v.GetValue(baseClass)); + var fi = s.GetType().GetField(v.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (fi != null && !fi.IsStatic) + { + fi.SetValue(s, v.GetValue(baseClass)); + //Console.WriteLine("SET {0} ON {1} TO {2}", fi.Name, s.name, v.GetValue(baseClass)); + } + } + catch (Exception ex) + { + Program.LogError(ex); } } - catch (Exception ex) - { - Program.LogError(ex); - } } - //s.IsFarm = baseClass.IsFarm; - //s.IsOutdoors = baseClass.IsOutdoors; - //s.LightLevel = baseClass.LightLevel; - //s.Map = baseClass.Map; - //s.objects = baseClass.objects; - //s.temporarySprites = baseClass.temporarySprites; - - /* - s.actionObjectForQuestionDialogue = baseClass.actionObjectForQuestionDialogue; - s.characters = baseClass.characters; - s.critters = (List)typeof(GameLocation).GetField("critters", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(baseClass); - s.currentEvent = baseClass.currentEvent; - s.debris = baseClass.debris; - s.doorSprites = baseClass.doorSprites; - s.doors = baseClass.doors; - s.farmers = baseClass.farmers; - s.fishSplashAnimation = baseClass.fishSplashAnimation; - s.fishSplashPoint = baseClass.fishSplashPoint; - s.forceViewportPlayerFollow = baseClass.forceViewportPlayerFollow; - s.ignoreDebrisWeather = baseClass.ignoreDebrisWeather; - s.ignoreLights = baseClass.ignoreLights; - s.ignoreOutdoorLighting = baseClass.ignoreOutdoorLighting; - s.isFarm = baseClass.isFarm; - s.isOutdoors = baseClass.isOutdoors; - s.isStructure = baseClass.isStructure; - s.largeTerrainFeatures = baseClass.largeTerrainFeatures; - s.lastQuestionKey = baseClass.lastQuestionKey; - s.lastTouchActionLocation = baseClass.lastTouchActionLocation; - s.lightGlows = baseClass.lightGlows; - s.map = baseClass.map; - s.name = baseClass.name; - s.numberOfSpawnedObjectsOnMap = baseClass.numberOfSpawnedObjectsOnMap; - s.objects = baseClass.objects; - s.orePanAnimation = baseClass.orePanAnimation; - s.orePanPoint = baseClass.orePanPoint; - s.projectiles = baseClass.projectiles; - s.temporarySprites = baseClass.temporarySprites; - s.terrainFeatures = baseClass.terrainFeatures; - s.uniqueName = baseClass.uniqueName; - s.warps = baseClass.warps; - s.wasUpdated = (bool)typeof(GameLocation).GetField("wasUpdated", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(baseClass); - s.waterAnimationIndex = baseClass.waterAnimationIndex; - s.waterAnimationTimer = baseClass.waterAnimationTimer; - s.waterColor = baseClass.waterColor; - s.waterTileFlip = baseClass.waterTileFlip; - s.waterTiles = baseClass.waterTiles; - */ - - - return s; } - public static List ConvertGameLocations(List baseGameLocations) + public static List ConstructFromBaseClasses(List baseGameLocations, bool copyAllData = false) { - return baseGameLocations.Select(ConstructFromBaseClass).ToList(); + return baseGameLocations.Select(gl => ConstructFromBaseClass(gl, copyAllData)).ToList(); } public virtual void update(GameTime gameTime) @@ -110,5 +66,10 @@ namespace StardewModdingAPI.Inheritance v.Value.draw(b, (int)v.Key.X, (int)v.Key.Y, 0.999f, 1); } } + + public SGameLocation() + { + ModObjects = new SerializableDictionary(); + } } } diff --git a/StardewModdingAPI/Inheritance/SObject.cs b/StardewModdingAPI/Inheritance/SObject.cs index 97d2fa41..5c80cd52 100644 --- a/StardewModdingAPI/Inheritance/SObject.cs +++ b/StardewModdingAPI/Inheritance/SObject.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Xml.Serialization; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewValley; @@ -12,7 +13,10 @@ namespace StardewModdingAPI.Inheritance { public class SObject : StardewValley.Object { - public override String Name { get; set; } + public override String Name { + get { return name; } + set { name = value; } + } public String Description { get; set; } public Texture2D Texture { get; set; } public String CategoryName { get; set; } @@ -29,9 +33,18 @@ namespace StardewModdingAPI.Inheritance public Boolean FlaggedForPickup { get; set; } + public Vector2 CurrentMouse { get; protected set; } + public Vector2 PlacedAt { get; protected set; } + + public override int Stack + { + get { return stack; } + set { stack = value; } + } + public SObject() { - Name = "Modded Item Name"; + name = "Modded Item Name"; Description = "Modded Item Description"; CategoryName = "Modded Item Category"; Category = 4163; @@ -39,6 +52,9 @@ namespace StardewModdingAPI.Inheritance IsPassable = false; IsPlaceable = false; boundingBox = new Rectangle(0, 0, 64, 64); + MaxStackSize = 999; + + type = "interactive"; } public override string getDescription() @@ -48,13 +64,19 @@ namespace StardewModdingAPI.Inheritance public override void draw(SpriteBatch spriteBatch, int x, int y, float alpha = 1) { - if (Texture != null) - spriteBatch.Draw(Texture, new Vector2(x, y), new Color(255, 255, 255, 255f * alpha)); + { + int targSize = Game1.tileSize; + + Vector2 local = Game1.GlobalToLocal(Game1.viewport, new Vector2(x,y)); + Rectangle targ = new Rectangle((int)local.X, (int)local.Y, targSize, targSize); + spriteBatch.Draw(Texture, targ, null, new Color(255, 255, 255, 255f * alpha)); + } } public override void draw(SpriteBatch spriteBatch, int xNonTile, int yNonTile, float layerDepth, float alpha = 1) { + Program.LogInfo("THIS DRAW FUNCTION IS NOT IMPLEMENTED I WANT TO KNOW WHERE IT IS CALLED"); return; try { @@ -181,34 +203,62 @@ namespace StardewModdingAPI.Inheritance return this.Clone(); } + public override void actionWhenBeingHeld(Farmer who) + { + Point p = Game1.getMousePosition(); + CurrentMouse = new Vector2((p.X / Game1.tileSize), (p.Y / Game1.tileSize)); + Program.LogInfo(canBePlacedHere(Game1.currentLocation, CurrentMouse)); + base.actionWhenBeingHeld(who); + } + + public override bool canBePlacedHere(GameLocation l, Vector2 tile) + { + Program.LogInfo(CurrentMouse.ToString().Replace("{", "").Replace("}", "")); + if (!l.objects.ContainsKey(tile)) + return true; + + return false; + } + public override bool placementAction(GameLocation location, int x, int y, Farmer who = null) { - SGameLocation s = SGame.GetLocationFromName(location.name); - - if (s.GetHashCode() != SGame.CurrentLocation.GetHashCode()) - { - Program.LogError("HASH DIFFERENCE: " + s.GetHashCode() + " | " + SGame.ModLocations[SGame.ModLocations.IndexOf(SGame.ModLocations.First(z => z.name == location.name))].GetHashCode() + " | " + SGame.CurrentLocation.GetHashCode()); - Console.ReadKey(); - } - - Console.Title = (this.GetHashCode() + " PLACEMENT"); - - if (s != null) - { - Vector2 index1 = new Vector2(x - (Game1.tileSize / 2), y - (Game1.tileSize / 2)); - if (!s.ModObjects.ContainsKey(index1)) - { - s.ModObjects.Add(index1, this); - Game1.player.position = index1; - return true; - } - } - else - { - Program.LogError("No SGameLocation could be found for the supplied GameLocation!"); + if (Game1.didPlayerJustRightClick()) return false; + + x = (x / Game1.tileSize) * Game1.tileSize; + y = (y / Game1.tileSize) * Game1.tileSize; + + Vector2 key = new Vector2(x, y); + + if (!canBePlacedHere(location, key)) + return false; + + SObject s = Clone(); + + s.PlacedAt = key; + s.boundingBox = new Rectangle(x / Game1.tileSize * Game1.tileSize, y / Game1.tileSize * Game1.tileSize, this.boundingBox.Width, this.boundingBox.Height); + + location.objects.Add(key, s); + Program.LogInfo("{0} - {1}", this.GetHashCode(), s.GetHashCode()); + + return true; + } + + public override void actionOnPlayerEntry() + { + //base.actionOnPlayerEntry(); + } + + public override void drawPlacementBounds(SpriteBatch spriteBatch, GameLocation location) + { + if (canBePlacedHere(location, CurrentMouse)) + { + int targSize = Game1.tileSize; + + int x = Game1.oldMouseState.X + Game1.viewport.X; + int y = Game1.oldMouseState.Y + Game1.viewport.Y; + spriteBatch.Draw(Game1.mouseCursors, new Vector2((float)(x / Game1.tileSize * Game1.tileSize - Game1.viewport.X), (float)(y / Game1.tileSize * Game1.tileSize - Game1.viewport.Y)), new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(Utility.playerCanPlaceItemHere(location, (Item)this, x, y, Game1.player) ? 194 : 210, 388, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)Game1.pixelZoom, SpriteEffects.None, 0.01f); } - return false; } } } \ No newline at end of file diff --git a/StardewModdingAPI/Program.cs b/StardewModdingAPI/Program.cs index 4277bdce..313fcbe5 100644 --- a/StardewModdingAPI/Program.cs +++ b/StardewModdingAPI/Program.cs @@ -49,30 +49,30 @@ namespace StardewModdingAPI public static Thread gameThread; public static Thread consoleInputThread; - public const string Version = "0.33 Alpha"; - public const bool debug = false; + public const string Version = "0.36 Alpha"; + public const bool debug = true; public static bool disableLogging { 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 FORGOT TO INCREMENT VERSION VARS"; - - Application.ThreadException += Application_ThreadException; - Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - + 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 @@ -84,9 +84,11 @@ namespace StardewModdingAPI } catch (Exception ex) { + LogError("Could not create a missing ModPath: " + ModPath + "\n\n" + ex); } } + //Same for content foreach (string ModContentPath in ModContentPaths) { try @@ -99,7 +101,7 @@ namespace StardewModdingAPI 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)) @@ -110,10 +112,12 @@ namespace StardewModdingAPI LogError("Could not create the missing ErrorLogs path: " + LogPath + "\n\n" + ex); } - CurrentLog = LogPath + "\\MODDED_ProgramLog_" + System.DateTime.Now.Ticks + ".txt"; + //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); @@ -124,48 +128,62 @@ namespace StardewModdingAPI 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); } - StardewAssembly = Assembly.LoadFile(ExecutionPath + "\\Stardew Valley.exe"); + //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"); - consoleInputThread = new Thread(ConsoleInputThread); + //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 ' 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; - Events.LocationsChanged += Events_LocationsChanged; - Events.CurrentLocationChanged += Events_CurrentLocationChanged; + //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(() => { @@ -174,11 +192,13 @@ namespace StardewModdingAPI StardewForm.Resize += Events.InvokeResize; }); + //Game's in memory now, send the event LogInfo("Game Loaded"); Events.InvokeGameLoaded(); - consoleInputThread.Start(); LogColour(ConsoleColor.Cyan, "Type 'help' for help, or 'help ' for a command's usage"); + //Begin listening to input + consoleInputThread.Start(); while (ready) @@ -187,11 +207,14 @@ namespace StardewModdingAPI 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; @@ -205,6 +228,7 @@ namespace StardewModdingAPI if (time >= target) break; } + */ Environment.Exit(0); } @@ -216,6 +240,12 @@ namespace StardewModdingAPI 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(); @@ -320,6 +350,9 @@ namespace StardewModdingAPI so2.IsPlaceable = true; LogColour(ConsoleColor.Cyan, "REGISTERED WITH ID OF: " + SGame.RegisterModItem(so2)); } + + if (debug) + Command.CallCommand("load"); } static void Events_KeyPressed(Keys key) @@ -340,7 +373,7 @@ namespace StardewModdingAPI { if (debug) { - SGame.ModLocations = SGameLocation.ConvertGameLocations(Game1.locations); + SGame.ModLocations = SGameLocation.ConstructFromBaseClasses(Game1.locations); } } @@ -351,7 +384,7 @@ namespace StardewModdingAPI if (debug) { Console.WriteLine(newLocation.name); - SGame.CurrentLocation = SGame.ModLocations.FirstOrDefault(x => x.name == newLocation.name); + SGame.CurrentLocation = SGame.LoadOrCreateSGameLocationFromName(newLocation.name); } //Game1.currentLocation = SGame.CurrentLocation; //LogInfo(((SGameLocation) newLocation).name); @@ -375,10 +408,6 @@ namespace StardewModdingAPI File.WriteAllText(Program.LogPath + "\\MODDED_ErrorLog_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.Exception.ToString()); } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - static void help_CommandFired(Command cmd) { if (cmd.CalledArgs.Length > 0) @@ -398,11 +427,6 @@ namespace StardewModdingAPI LogInfo("Commands: " + Command.RegisteredCommands.Select(x => x.CommandName).ToSingular()); } - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - #region Logging public static void Log(object o, params object[] format) @@ -450,6 +474,15 @@ namespace StardewModdingAPI 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(" must be specified"); diff --git a/TrainerMod/TrainerMod.cs b/TrainerMod/TrainerMod.cs index 6e1b4b17..86b03673 100644 --- a/TrainerMod/TrainerMod.cs +++ b/TrainerMod/TrainerMod.cs @@ -46,6 +46,9 @@ namespace TrainerMod static void Events_UpdateTick() { + if (Game1.player == null) + return; + if (infHealth) { Game1.player.health = Game1.player.maxHealth; @@ -90,7 +93,7 @@ namespace TrainerMod Command.RegisterCommand("player_changecolour", "Sets the player's colour of the specified object | player_changecolor ", new[] { "(hair, eyes, pants) (r,g,b)" }).CommandFired += player_changeColour; Command.RegisterCommand("player_changestyle", "Sets the player's style of the specified object | player_changecolor ", new[] { "(hair, shirt, skin, acc, shoe, swim, gender) (Int32)" }).CommandFired += player_changeStyle; - Command.RegisterCommand("player_additem", "Gives the player an item | player_additem ", new[] { "? (Int32)" }).CommandFired += player_addItem; + Command.RegisterCommand("player_additem", "Gives the player an item | player_additem [count] [quality]", new[] { "(Int32) (Int32)[count] (Int32)[quality]" }).CommandFired += player_addItem; Command.RegisterCommand("player_addmelee", "Gives the player a melee item | player_addmelee ", new[] { "?" }).CommandFired += player_addMelee; Command.RegisterCommand("player_addring", "Gives the player a ring | player_addring ", new[] { "?" }).CommandFired += player_addRing; @@ -596,21 +599,39 @@ namespace TrainerMod if (cmd.CalledArgs[0].IsInt32()) { int count = 1; + int quality = 0; if (cmd.CalledArgs.Length > 1) { + Console.WriteLine(cmd.CalledArgs[1]); if (cmd.CalledArgs[1].IsInt32()) { count = cmd.CalledArgs[1].AsInt32(); } else { - Program.LogError(" is invalid"); + Program.LogError("[count] is invalid"); return; } + + if (cmd.CalledArgs.Length > 2) + { + if (cmd.CalledArgs[2].IsInt32()) + { + quality = cmd.CalledArgs[2].AsInt32(); + } + else + { + Program.LogError("[quality] is invalid"); + return; + } + + } } - Item i = (Item) new StardewValley.Object(cmd.CalledArgs[0].AsInt32(), count); - - Game1.player.addItemByMenuIfNecessary(i); + + StardewValley.Object o = new StardewValley.Object(cmd.CalledArgs[0].AsInt32(), count); + o.quality = quality; + + Game1.player.addItemByMenuIfNecessary((Item)o); } else { @@ -739,7 +760,11 @@ namespace TrainerMod static void RegisterNewItem(Command cmd) { - Game1.player.addItemToInventory(SGame.PullModItemFromDict(0, true)); + if (!Program.debug) + return; + SObject s = SGame.PullModItemFromDict(0, true); + s.Stack = 999; + Game1.player.addItemToInventory(s); } } } diff --git a/TrainerMod/bin/Debug/TrainerMod.dll b/TrainerMod/bin/Debug/TrainerMod.dll index 790f0444..9fc10782 100644 Binary files a/TrainerMod/bin/Debug/TrainerMod.dll and b/TrainerMod/bin/Debug/TrainerMod.dll differ diff --git a/TrainerMod/obj/Debug/TrainerMod.dll b/TrainerMod/obj/Debug/TrainerMod.dll index 790f0444..9fc10782 100644 Binary files a/TrainerMod/obj/Debug/TrainerMod.dll and b/TrainerMod/obj/Debug/TrainerMod.dll differ