From 37d5390ed0ef854abd7dac5cd1fb40c2d808ee1f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 30 Mar 2017 19:15:23 -0400 Subject: unbackport for SDV 1.2 branch (#258) --- src/StardewModdingAPI/Constants.cs | 16 +- src/StardewModdingAPI/Framework/SGame.cs | 1039 +++++++++++++------- src/StardewModdingAPI/Program.cs | 5 +- .../StardewModdingAPI.config.json | 85 +- 4 files changed, 759 insertions(+), 386 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 4a036cd0..6091b864 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -33,13 +33,13 @@ namespace StardewModdingAPI ** Public ****/ /// SMAPI's current semantic version. - public static ISemanticVersion ApiVersion { get; } = new SemanticVersion(1, 9, 0); + public static ISemanticVersion ApiVersion { get; } = new SemanticVersion(1, 10, 0); /// The minimum supported version of Stardew Valley. - public static ISemanticVersion MinimumGameVersion { get; } = new SemanticVersion("1.1"); + public static ISemanticVersion MinimumGameVersion { get; } = new SemanticVersion("1.2.15"); /// The maximum supported version of Stardew Valley. - public static ISemanticVersion MaximumGameVersion { get; } = new SemanticVersion("1.1.1"); + public static ISemanticVersion MaximumGameVersion { get; } = null; /// The path to the game folder. public static string ExecutionPath { get; } = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); @@ -146,6 +146,9 @@ namespace StardewModdingAPI /**** ** Finders throw an exception when incompatible code is found. ****/ + // changes in Stardew Valley 1.2 (with no rewriters) + new FieldFinder("StardewValley.Item", "set_Name"), + // APIs removed in SMAPI 1.9 new TypeFinder("StardewModdingAPI.Advanced.ConfigFile"), new TypeFinder("StardewModdingAPI.Advanced.IConfigFile"), @@ -169,6 +172,13 @@ namespace StardewModdingAPI // crossplatform new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchWrapper), onlyIfPlatformChanged: true), + // Stardew Valley 1.2 + new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.activeClickableMenu)), + new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.gameMode)), + new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.player)), + new FieldReplaceRewriter(typeof(Game1), "borderFont", nameof(Game1.smallFont)), + new FieldReplaceRewriter(typeof(Game1), "smoothFont", nameof(Game1.smallFont)), + // SMAPI 1.9 new TypeReferenceRewriter("StardewModdingAPI.Inheritance.ItemStackChange", typeof(ItemStackChange)) }; diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 5f265139..c16bf1cf 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -1,8 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading.Tasks; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -14,7 +16,7 @@ using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Tools; using xTile.Dimensions; -using Rectangle = Microsoft.Xna.Framework.Rectangle; +using xTile.Layers; using SFarmer = StardewValley.Farmer; namespace StardewModdingAPI.Framework @@ -134,6 +136,9 @@ namespace StardewModdingAPI.Framework /// The player character at last check. private SFarmer PreviousFarmer; + /// The previous content locale. + private LocalizedContentManager.LanguageCode? PreviousLocale; + /// An index incremented on every tick and reset every 60th tick (0–59). private int CurrentUpdateTick; @@ -149,12 +154,20 @@ namespace StardewModdingAPI.Framework // ReSharper disable ArrangeStaticMemberQualifier, ArrangeThisQualifier, InconsistentNaming /// Used to access private fields and methods. private static readonly IReflectionHelper Reflection = new ReflectionHelper(); + private static List _fpsList => SGame.Reflection.GetPrivateField>(typeof(Game1), nameof(_fpsList)).GetValue(); + private static Stopwatch _fpsStopwatch => SGame.Reflection.GetPrivateField(typeof(Game1), nameof(SGame._fpsStopwatch)).GetValue(); + private static float _fps + { + set { SGame.Reflection.GetPrivateField(typeof(Game1), nameof(_fps)).SetValue(value); } + } + private static Task _newDayTask => SGame.Reflection.GetPrivateField(typeof(Game1), nameof(_newDayTask)).GetValue(); private Color bgColor => SGame.Reflection.GetPrivateField(this, nameof(bgColor)).GetValue(); - public RenderTarget2D screenWrapper => SGame.Reflection.GetPrivateField(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop + public RenderTarget2D screenWrapper => SGame.Reflection.GetPrivateProperty(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop public BlendState lightingBlend => SGame.Reflection.GetPrivateField(this, nameof(lightingBlend)).GetValue(); private readonly Action drawFarmBuildings = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawFarmBuildings)).Invoke(new object[0]); private readonly Action drawHUD = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawHUD)).Invoke(new object[0]); private readonly Action drawDialogueBox = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawDialogueBox)).Invoke(new object[0]); + private readonly Action renderScreenBuffer = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(renderScreenBuffer)).Invoke(new object[0]); // ReSharper restore ArrangeStaticMemberQualifier, ArrangeThisQualifier, InconsistentNaming @@ -184,6 +197,14 @@ namespace StardewModdingAPI.Framework GameEvents.InvokeInitialize(this.Monitor); } + /// Constructor a content manager to read XNB files. + /// The service provider to use to locate services. + /// The root directory to search for content. + protected override LocalizedContentManager CreateContentManager(IServiceProvider serviceProvider, string rootDirectory) + { + return new SContentManager(this.Content.ServiceProvider, this.Content.RootDirectory, this.Monitor); + } + /// The method called before XNA or MonoGame loads or reloads graphics resources. protected override void LoadContent() { @@ -195,6 +216,22 @@ namespace StardewModdingAPI.Framework /// A snapshot of the game timing state. protected override void Update(GameTime gameTime) { + // While a background new-day task is in progress, the game skips its own update logic + // and defers to the XNA Update method. Running mod code in parallel to the background + // update is risky, because data changes can conflict (e.g. collection changed during + // enumeration errors) and data may change unexpectedly from one mod instruction to the + // next. + // + // Therefore we can just run Game1.Update here without raising any SMAPI events. There's + // a small chance that the task will finish after we defer but before the game checks, + // which means technically events should be raised, but the effects of missing one + // update tick are neglible and not worth the complications of bypassing Game1.Update. + if (SGame._newDayTask != null) + { + base.Update(gameTime); + return; + } + // raise game loaded if (this.FirstUpdate) GameEvents.InvokeGameLoaded(this.Monitor); @@ -258,412 +295,649 @@ namespace StardewModdingAPI.Framework { try { - if (!this.ZoomLevelIsOne) - this.GraphicsDevice.SetRenderTarget(this.screenWrapper); - - this.GraphicsDevice.Clear(this.bgColor); - if (Game1.options.showMenuBackground && Game1.activeClickableMenu != null && Game1.activeClickableMenu.showWithoutTransparencyIfOptionIsSet()) + if (Game1.debugMode) { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - try + if (SGame._fpsStopwatch.IsRunning) { - Game1.activeClickableMenu.drawBackground(Game1.spriteBatch); + float totalSeconds = (float)SGame._fpsStopwatch.Elapsed.TotalSeconds; + SGame._fpsList.Add(totalSeconds); + while (SGame._fpsList.Count >= 120) + SGame._fpsList.RemoveAt(0); + float num = 0.0f; + foreach (float fps in SGame._fpsList) + num += fps; + SGame._fps = (float)(1.0 / ((double)num / (double)SGame._fpsList.Count)); } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing its background. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); - } - GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); - try - { - Game1.activeClickableMenu.draw(Game1.spriteBatch); - } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); - } - GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); - Game1.spriteBatch.End(); - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; + SGame._fpsStopwatch.Restart(); } - if (Game1.gameMode == 11) - { - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - Game1.spriteBatch.DrawString(Game1.smoothFont, "Stardew Valley has crashed...", new Vector2(16f, 16f), Color.HotPink); - Game1.spriteBatch.DrawString(Game1.smoothFont, "Please send the error report or a screenshot of this message to @ConcernedApe. (http://stardewvalley.net/contact/)", new Vector2(16f, 32f), new Color(0, 255, 0)); - Game1.spriteBatch.DrawString(Game1.smoothFont, Game1.parseText(Game1.errorMessage, Game1.smoothFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); - Game1.spriteBatch.End(); - return; - } - if (Game1.currentMinigame != null) + else { - Game1.currentMinigame.draw(Game1.spriteBatch); - if (Game1.globalFade && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha)); - Game1.spriteBatch.End(); - } - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; + if (SGame._fpsStopwatch.IsRunning) + SGame._fpsStopwatch.Reset(); + SGame._fps = 0.0f; + SGame._fpsList.Clear(); } - if (Game1.showingEndOfNightStuff) + if (SGame._newDayTask != null) { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - try - { - Game1.activeClickableMenu?.draw(Game1.spriteBatch); - } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); - } - Game1.spriteBatch.End(); - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; - } - if (Game1.gameMode == 6) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - string text = ""; - int num = 0; - while (num < gameTime.TotalGameTime.TotalMilliseconds % 999.0 / 333.0) - { - text += "."; - num++; - } - SpriteText.drawString(Game1.spriteBatch, "Loading" + text, 64, Game1.graphics.GraphicsDevice.Viewport.Height - 64, 999, -1, 999, 1f, 1f, false, 0, "Loading..."); - Game1.spriteBatch.End(); - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; + this.GraphicsDevice.Clear(this.bgColor); + //base.Draw(gameTime); } - if (Game1.gameMode == 0) - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); else { - if (Game1.drawLighting) - { - this.GraphicsDevice.SetRenderTarget(Game1.lightmap); - this.GraphicsDevice.Clear(Color.White * 0f); - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null); - Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, Game1.currentLocation.name.Equals("UndergroundMine") ? Game1.mine.getLightingColor(gameTime) : ((!Game1.ambientLight.Equals(Color.White) && (!Game1.isRaining || !Game1.currentLocation.isOutdoors)) ? Game1.ambientLight : Game1.outdoorLight)); - for (int i = 0; i < Game1.currentLightSources.Count; i++) - { - if (Utility.isOnScreen(Game1.currentLightSources.ElementAt(i).position, (int)(Game1.currentLightSources.ElementAt(i).radius * Game1.tileSize * 4f))) - Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(i).lightTexture, Game1.GlobalToLocal(Game1.viewport, Game1.currentLightSources.ElementAt(i).position) / Game1.options.lightingQuality, Game1.currentLightSources.ElementAt(i).lightTexture.Bounds, Game1.currentLightSources.ElementAt(i).color, 0f, new Vector2(Game1.currentLightSources.ElementAt(i).lightTexture.Bounds.Center.X, Game1.currentLightSources.ElementAt(i).lightTexture.Bounds.Center.Y), Game1.currentLightSources.ElementAt(i).radius / Game1.options.lightingQuality, SpriteEffects.None, 0.9f); - } - Game1.spriteBatch.End(); - this.GraphicsDevice.SetRenderTarget(this.ZoomLevelIsOne ? null : this.screenWrapper); - } - if (Game1.bloomDay) - Game1.bloom?.BeginDraw(); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - GraphicsEvents.InvokeOnPreRenderEvent(this.Monitor); - Game1.background?.draw(Game1.spriteBatch); - Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); - Game1.currentLocation.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.currentLocation.drawWater(Game1.spriteBatch); - if (Game1.CurrentEvent == null) + if ((double)Game1.options.zoomLevel != 1.0) + this.GraphicsDevice.SetRenderTarget(this.screenWrapper); + if (this.IsSaving) { - using (List.Enumerator enumerator = Game1.currentLocation.characters.GetEnumerator()) + this.GraphicsDevice.Clear(this.bgColor); + IClickableMenu activeClickableMenu = Game1.activeClickableMenu; + if (activeClickableMenu != null) { - while (enumerator.MoveNext()) + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + try { - NPC current = enumerator.Current; - if (current != null && !current.swimming && !current.hideShadow && !current.IsMonster && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current.position + new Vector2(current.sprite.spriteWidth * Game1.pixelZoom / 2f, current.GetBoundingBox().Height + (current.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current.yJumpOffset / 40f) * current.scale, SpriteEffects.None, Math.Max(0f, current.getStandingY() / 10000f) - 1E-06f); + GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); + activeClickableMenu.draw(Game1.spriteBatch); + GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); } - goto IL_B30; + catch (Exception ex) + { + this.Monitor.Log($"The {activeClickableMenu.GetType().FullName} menu crashed while drawing itself during save. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + activeClickableMenu.exitThisMenu(); + } + Game1.spriteBatch.End(); } + //base.Draw(gameTime); + this.renderScreenBuffer(); } - foreach (NPC current2 in Game1.CurrentEvent.actors) - { - if (!current2.swimming && !current2.hideShadow && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current2.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current2.position + new Vector2(current2.sprite.spriteWidth * Game1.pixelZoom / 2f, current2.GetBoundingBox().Height + (current2.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current2.yJumpOffset / 40f) * current2.scale, SpriteEffects.None, Math.Max(0f, current2.getStandingY() / 10000f) - 1E-06f); - } - IL_B30: - if (!Game1.player.swimming && !Game1.player.isRidingHorse() && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((Game1.player.running || Game1.player.usingTool) && Game1.player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, 0f); - Game1.currentLocation.Map.GetLayer("Buildings").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.mapDisplayDevice.EndScene(); - Game1.spriteBatch.End(); - Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.CurrentEvent == null) + else { - using (List.Enumerator enumerator3 = Game1.currentLocation.characters.GetEnumerator()) + this.GraphicsDevice.Clear(this.bgColor); + if (Game1.activeClickableMenu != null && Game1.options.showMenuBackground && Game1.activeClickableMenu.showWithoutTransparencyIfOptionIsSet()) { - while (enumerator3.MoveNext()) + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + try + { + Game1.activeClickableMenu.drawBackground(Game1.spriteBatch); + GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); + Game1.activeClickableMenu.draw(Game1.spriteBatch); + GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); + } + catch (Exception ex) + { + this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + Game1.activeClickableMenu.exitThisMenu(); + } + Game1.spriteBatch.End(); + if ((double)Game1.options.zoomLevel != 1.0) { - NPC current3 = enumerator3.Current; - if (current3 != null && !current3.swimming && !current3.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current3.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current3.position + new Vector2(current3.sprite.spriteWidth * Game1.pixelZoom / 2f, current3.GetBoundingBox().Height + (current3.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current3.yJumpOffset / 40f) * current3.scale, SpriteEffects.None, Math.Max(0f, current3.getStandingY() / 10000f) - 1E-06f); + this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); } - goto IL_F5F; + if (Game1.overlayMenu == null) + return; + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); } - } - foreach (NPC current4 in Game1.CurrentEvent.actors) - { - if (!current4.swimming && !current4.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current4.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current4.position + new Vector2(current4.sprite.spriteWidth * Game1.pixelZoom / 2f, current4.GetBoundingBox().Height + (current4.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current4.yJumpOffset / 40f) * current4.scale, SpriteEffects.None, Math.Max(0f, current4.getStandingY() / 10000f) - 1E-06f); - } - IL_F5F: - if (!Game1.player.swimming && !Game1.player.isRidingHorse() && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((Game1.player.running || Game1.player.usingTool) && Game1.player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, Math.Max(0.0001f, Game1.player.getStandingY() / 10000f + 0.00011f) - 0.0001f); - if (Game1.displayFarmer) - Game1.player.draw(Game1.spriteBatch); - if ((Game1.eventUp || Game1.killScreen) && !Game1.killScreen) - Game1.currentLocation.currentEvent?.draw(Game1.spriteBatch); - if (Game1.player.currentUpgrade != null && Game1.player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && Game1.currentLocation.Name.Equals("Farm")) - Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), Game1.player.currentUpgrade.getSourceRectangle(), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, (Game1.player.currentUpgrade.positionOfCarpenter.Y + Game1.tileSize * 3 / 4) / 10000f); - Game1.currentLocation.draw(Game1.spriteBatch); - if (Game1.eventUp && Game1.currentLocation.currentEvent?.messageToScreen != null) - Game1.drawWithBorder(Game1.currentLocation.currentEvent.messageToScreen, Color.Black, Color.White, new Vector2(Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width / 2 - Game1.borderFont.MeasureString(Game1.currentLocation.currentEvent.messageToScreen).X / 2f, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Height - Game1.tileSize), 0f, 1f, 0.999f); - if (Game1.player.ActiveObject == null && (Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && (!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool)) - Game1.drawTool(Game1.player); - if (Game1.currentLocation.Name.Equals("Farm")) - this.drawFarmBuildings(); - if (Game1.tvStation >= 0) - Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(6 * Game1.tileSize + Game1.tileSize / 4, 2 * Game1.tileSize + Game1.tileSize / 2)), new Rectangle(Game1.tvStation * 24, 0, 24, 15), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f); - if (Game1.panMode) - { - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle((int)Math.Floor((Game1.getOldMouseX() + Game1.viewport.X) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.X, (int)Math.Floor((Game1.getOldMouseY() + Game1.viewport.Y) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Lime * 0.75f); - foreach (Warp current5 in Game1.currentLocation.warps) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle(current5.X * Game1.tileSize - Game1.viewport.X, current5.Y * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Red * 0.75f); - } - Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); - Game1.currentLocation.Map.GetLayer("Front").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.mapDisplayDevice.EndScene(); - Game1.currentLocation.drawAboveFrontLayer(Game1.spriteBatch); - Game1.spriteBatch.End(); - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.currentLocation.Name.Equals("Farm") && Game1.stats.SeedsSown >= 200u) - { - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(3 * Game1.tileSize + Game1.tileSize / 4, Game1.tileSize + Game1.tileSize / 3)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize + Game1.tileSize, 2 * Game1.tileSize + Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(5 * Game1.tileSize, 2 * Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(3 * Game1.tileSize + Game1.tileSize / 2, 3 * Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(5 * Game1.tileSize - Game1.tileSize / 4, Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize, 3 * Game1.tileSize + Game1.tileSize / 6)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize + Game1.tileSize / 5, 2 * Game1.tileSize + Game1.tileSize / 3)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - } - if (Game1.displayFarmer && Game1.player.ActiveObject != null && Game1.player.ActiveObject.bigCraftable && this.checkBigCraftableBoundariesForFrontLayer() && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) - Game1.drawPlayerHeldObject(Game1.player); - else if (Game1.displayFarmer && Game1.player.ActiveObject != null && ((Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")) || (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")))) - Game1.drawPlayerHeldObject(Game1.player); - if ((Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && (!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool) && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) - Game1.drawTool(Game1.player); - if (Game1.currentLocation.Map.GetLayer("AlwaysFront") != null) - { - Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); - Game1.currentLocation.Map.GetLayer("AlwaysFront").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.mapDisplayDevice.EndScene(); - } - if (Game1.toolHold > 400f && Game1.player.CurrentTool.UpgradeLevel >= 1 && Game1.player.canReleaseTool) - { - Color color = Color.White; - switch ((int)(Game1.toolHold / 600f) + 2) + else if ((int)Game1.gameMode == 11) { - case 1: - color = Tool.copperColor; - break; - case 2: - color = Tool.steelColor; - break; - case 3: - color = Tool.goldColor; - break; - case 4: - color = Tool.iridiumColor; - break; + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3685"), new Vector2(16f, 16f), Color.HotPink); + Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Color(0, (int)byte.MaxValue, 0)); + Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); + Game1.spriteBatch.End(); } - Game1.spriteBatch.Draw(Game1.littleEffect, new Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize) - 2, (int)(Game1.toolHold % 600f * 0.08f) + 4, Game1.tileSize / 8 + 4), Color.Black); - Game1.spriteBatch.Draw(Game1.littleEffect, new Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize), (int)(Game1.toolHold % 600f * 0.08f), Game1.tileSize / 8), color); - } - if (Game1.isDebrisWeather && Game1.currentLocation.IsOutdoors && !Game1.currentLocation.ignoreDebrisWeather && !Game1.currentLocation.Name.Equals("Desert") && Game1.viewport.X > -10) - { - foreach (WeatherDebris current6 in Game1.debrisWeather) - current6.draw(Game1.spriteBatch); - } - Game1.farmEvent?.draw(Game1.spriteBatch); - if (Game1.currentLocation.LightLevel > 0f && Game1.timeOfDay < 2000) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * Game1.currentLocation.LightLevel); - if (Game1.screenGlow) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Game1.screenGlowColor * Game1.screenGlowAlpha); - Game1.currentLocation.drawAboveAlwaysFrontLayer(Game1.spriteBatch); - if (Game1.player.CurrentTool is FishingRod && ((Game1.player.CurrentTool as FishingRod).isTimingCast || (Game1.player.CurrentTool as FishingRod).castingChosenCountdown > 0f || (Game1.player.CurrentTool as FishingRod).fishCaught || (Game1.player.CurrentTool as FishingRod).showingTreasure)) - Game1.player.CurrentTool.draw(Game1.spriteBatch); - if (Game1.isRaining && Game1.currentLocation.IsOutdoors && !Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit) && (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2(Game1.viewport.X / Game1.tileSize, Game1.viewport.Y / Game1.tileSize)))) - { - for (int j = 0; j < Game1.rainDrops.Length; j++) - Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[j].position, Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[j].frame), Color.White); - } - - Game1.spriteBatch.End(); - - //base.Draw(gameTime); - - Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.eventUp && Game1.currentLocation.currentEvent != null) - { - foreach (NPC current7 in Game1.currentLocation.currentEvent.actors) + else if (Game1.currentMinigame != null) { - if (current7.isEmoting) + Game1.currentMinigame.draw(Game1.spriteBatch); + if (Game1.globalFade && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) { - Vector2 localPosition = current7.getLocalPosition(Game1.viewport); - localPosition.Y -= Game1.tileSize * 2 + Game1.pixelZoom * 3; - if (current7.age == 2) - localPosition.Y += Game1.tileSize / 2; - else if (current7.gender == 1) - localPosition.Y += Game1.tileSize / 6; - Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, localPosition, new Rectangle(current7.CurrentEmoteIndex * (Game1.tileSize / 4) % Game1.emoteSpriteSheet.Width, current7.CurrentEmoteIndex * (Game1.tileSize / 4) / Game1.emoteSpriteSheet.Width * (Game1.tileSize / 4), Game1.tileSize / 4, Game1.tileSize / 4), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, current7.getStandingY() / 10000f); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((int)Game1.gameMode == 0 ? 1f - Game1.fadeToBlackAlpha : Game1.fadeToBlackAlpha)); + Game1.spriteBatch.End(); } + if ((double)Game1.options.zoomLevel != 1.0) + { + this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + if (Game1.overlayMenu == null) + return; + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); } - } - Game1.spriteBatch.End(); - if (Game1.drawLighting) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, new BlendState + else if (Game1.showingEndOfNightStuff) { - ColorBlendFunction = BlendFunction.ReverseSubtract, - ColorDestinationBlend = Blend.One, - ColorSourceBlend = Blend.SourceColor - }, SamplerState.LinearClamp, null, null); - Game1.spriteBatch.Draw(Game1.lightmap, Vector2.Zero, Game1.lightmap.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.lightingQuality, SpriteEffects.None, 1f); - if (Game1.isRaining && Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert)) + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + if (Game1.activeClickableMenu != null) + { + try + { + GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); + Game1.activeClickableMenu.draw(Game1.spriteBatch); + GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); + } + catch (Exception ex) + { + this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself during end-of-night-stuff. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + Game1.activeClickableMenu.exitThisMenu(); + } + } + Game1.spriteBatch.End(); + if ((double)Game1.options.zoomLevel != 1.0) + { + this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + if (Game1.overlayMenu == null) + return; + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); + } + else if ((int)Game1.gameMode == 6) { - Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.OrangeRed * 0.45f); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + string str1 = ""; + for (int index = 0; (double)index < gameTime.TotalGameTime.TotalMilliseconds % 999.0 / 333.0; ++index) + str1 += "."; + string str2 = Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3688"); + string str3 = str1; + string s = str2 + str3; + string str4 = "..."; + string str5 = str2 + str4; + int widthOfString = SpriteText.getWidthOfString(str5); + int height = 64; + int x = 64; + int y = Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - height; + SpriteText.drawString(Game1.spriteBatch, s, x, y, 999999, widthOfString, height, 1f, 0.88f, false, 0, str5, -1); + Game1.spriteBatch.End(); + if ((double)Game1.options.zoomLevel != 1.0) + { + this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + if (Game1.overlayMenu == null) + return; + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); } - Game1.spriteBatch.End(); - } - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.drawGrid) - { - int num2 = -Game1.viewport.X % Game1.tileSize; - float num3 = -(float)Game1.viewport.Y % Game1.tileSize; - for (int k = num2; k < Game1.graphics.GraphicsDevice.Viewport.Width; k += Game1.tileSize) - Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(k, (int)num3, 1, Game1.graphics.GraphicsDevice.Viewport.Height), Color.Red * 0.5f); - for (float num4 = num3; num4 < (float)Game1.graphics.GraphicsDevice.Viewport.Height; num4 += (float)Game1.tileSize) - Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(num2, (int)num4, Game1.graphics.GraphicsDevice.Viewport.Width, 1), Color.Red * 0.5f); - } - if (Game1.currentBillboard != 0) - this.drawBillboard(); - - if ((Game1.displayHUD || Game1.eventUp) && Game1.currentBillboard == 0 && Game1.gameMode == 3 && !Game1.freezeControls && !Game1.panMode) - { - GraphicsEvents.InvokeOnPreRenderHudEvent(this.Monitor); - this.drawHUD(); - GraphicsEvents.InvokeOnPostRenderHudEvent(this.Monitor); - } - else if (Game1.activeClickableMenu == null && Game1.farmEvent == null) - Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2(Game1.getOldMouseX(), Game1.getOldMouseY()), Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16), Color.White, 0f, Vector2.Zero, 4f + Game1.dialogueButtonScale / 150f, SpriteEffects.None, 1f); + else + { + Microsoft.Xna.Framework.Rectangle rectangle; + if ((int)Game1.gameMode == 0) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + } + else + { + if (Game1.drawLighting) + { + this.GraphicsDevice.SetRenderTarget(Game1.lightmap); + this.GraphicsDevice.Clear(Color.White * 0.0f); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, Game1.currentLocation.name.Equals("UndergroundMine") ? Game1.mine.getLightingColor(gameTime) : (Game1.ambientLight.Equals(Color.White) || Game1.isRaining && Game1.currentLocation.isOutdoors ? Game1.outdoorLight : Game1.ambientLight)); + for (int index = 0; index < Game1.currentLightSources.Count; ++index) + { + if (Utility.isOnScreen(Game1.currentLightSources.ElementAt(index).position, (int)((double)Game1.currentLightSources.ElementAt(index).radius * (double)Game1.tileSize * 4.0))) + Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, Game1.currentLightSources.ElementAt(index).position) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), Game1.currentLightSources.ElementAt(index).color, 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), Game1.currentLightSources.ElementAt(index).radius / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); + } + Game1.spriteBatch.End(); + this.GraphicsDevice.SetRenderTarget((double)Game1.options.zoomLevel == 1.0 ? (RenderTarget2D)null : this.screenWrapper); + } + if (Game1.bloomDay && Game1.bloom != null) + Game1.bloom.BeginDraw(); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + GraphicsEvents.InvokeOnPreRenderEvent(this.Monitor); + if (Game1.background != null) + Game1.background.draw(Game1.spriteBatch); + Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); + Game1.currentLocation.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.currentLocation.drawWater(Game1.spriteBatch); + if (Game1.CurrentEvent == null) + { + foreach (NPC character in Game1.currentLocation.characters) + { + if (!character.swimming && !character.hideShadow && (!character.isInvisible && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(character.getTileLocation()))) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, character.position + new Vector2((float)(character.sprite.spriteWidth * Game1.pixelZoom) / 2f, (float)(character.GetBoundingBox().Height + (character.IsMonster ? 0 : Game1.pixelZoom * 3)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), ((float)Game1.pixelZoom + (float)character.yJumpOffset / 40f) * character.scale, SpriteEffects.None, Math.Max(0.0f, (float)character.getStandingY() / 10000f) - 1E-06f); + } + } + else + { + foreach (NPC actor in Game1.CurrentEvent.actors) + { + if (!actor.swimming && !actor.hideShadow && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(actor.getTileLocation())) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, actor.position + new Vector2((float)(actor.sprite.spriteWidth * Game1.pixelZoom) / 2f, (float)(actor.GetBoundingBox().Height + (actor.IsMonster ? 0 : (actor.sprite.spriteHeight <= 16 ? -Game1.pixelZoom : Game1.pixelZoom * 3))))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), ((float)Game1.pixelZoom + (float)actor.yJumpOffset / 40f) * actor.scale, SpriteEffects.None, Math.Max(0.0f, (float)actor.getStandingY() / 10000f) - 1E-06f); + } + } + Microsoft.Xna.Framework.Rectangle bounds; + if (Game1.displayFarmer && !Game1.player.swimming && (!Game1.player.isRidingHorse() && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation()))) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D shadowTexture = Game1.shadowTexture; + Vector2 local = Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)); + Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); + Color white = Color.White; + double num1 = 0.0; + double x = (double)Game1.shadowTexture.Bounds.Center.X; + bounds = Game1.shadowTexture.Bounds; + double y = (double)bounds.Center.Y; + Vector2 origin = new Vector2((float)x, (float)y); + double num2 = 4.0 - (!Game1.player.running && !Game1.player.usingTool || Game1.player.FarmerSprite.indexInCurrentAnimation <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5); + int num3 = 0; + double num4 = 0.0; + spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, (float)num1, origin, (float)num2, (SpriteEffects)num3, (float)num4); + } + Game1.currentLocation.Map.GetLayer("Buildings").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.mapDisplayDevice.EndScene(); + Game1.spriteBatch.End(); + Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + if (Game1.CurrentEvent == null) + { + foreach (NPC character in Game1.currentLocation.characters) + { + if (!character.swimming && !character.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(character.getTileLocation())) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D shadowTexture = Game1.shadowTexture; + Vector2 local = Game1.GlobalToLocal(Game1.viewport, character.position + new Vector2((float)(character.sprite.spriteWidth * Game1.pixelZoom) / 2f, (float)(character.GetBoundingBox().Height + (character.IsMonster ? 0 : Game1.pixelZoom * 3)))); + Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); + Color white = Color.White; + double num1 = 0.0; + bounds = Game1.shadowTexture.Bounds; + double x = (double)bounds.Center.X; + bounds = Game1.shadowTexture.Bounds; + double y = (double)bounds.Center.Y; + Vector2 origin = new Vector2((float)x, (float)y); + double num2 = ((double)Game1.pixelZoom + (double)character.yJumpOffset / 40.0) * (double)character.scale; + int num3 = 0; + double num4 = (double)Math.Max(0.0f, (float)character.getStandingY() / 10000f) - 9.99999997475243E-07; + spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, (float)num1, origin, (float)num2, (SpriteEffects)num3, (float)num4); + } + } + } + else + { + foreach (NPC actor in Game1.CurrentEvent.actors) + { + if (!actor.swimming && !actor.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(actor.getTileLocation())) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D shadowTexture = Game1.shadowTexture; + Vector2 local = Game1.GlobalToLocal(Game1.viewport, actor.position + new Vector2((float)(actor.sprite.spriteWidth * Game1.pixelZoom) / 2f, (float)(actor.GetBoundingBox().Height + (actor.IsMonster ? 0 : Game1.pixelZoom * 3)))); + Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); + Color white = Color.White; + double num1 = 0.0; + bounds = Game1.shadowTexture.Bounds; + double x = (double)bounds.Center.X; + bounds = Game1.shadowTexture.Bounds; + double y = (double)bounds.Center.Y; + Vector2 origin = new Vector2((float)x, (float)y); + double num2 = ((double)Game1.pixelZoom + (double)actor.yJumpOffset / 40.0) * (double)actor.scale; + int num3 = 0; + double num4 = (double)Math.Max(0.0f, (float)actor.getStandingY() / 10000f) - 9.99999997475243E-07; + spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, (float)num1, origin, (float)num2, (SpriteEffects)num3, (float)num4); + } + } + } + if (Game1.displayFarmer && !Game1.player.swimming && (!Game1.player.isRidingHorse() && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation()))) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D shadowTexture = Game1.shadowTexture; + Vector2 local = Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)); + Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); + Color white = Color.White; + double num1 = 0.0; + double x = (double)Game1.shadowTexture.Bounds.Center.X; + rectangle = Game1.shadowTexture.Bounds; + double y = (double)rectangle.Center.Y; + Vector2 origin = new Vector2((float)x, (float)y); + double num2 = 4.0 - (!Game1.player.running && !Game1.player.usingTool || Game1.player.FarmerSprite.indexInCurrentAnimation <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5); + int num3 = 0; + double num4 = (double)Math.Max(0.0001f, (float)((double)Game1.player.getStandingY() / 10000.0 + 0.000110000000859145)) - 9.99999974737875E-05; + spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, (float)num1, origin, (float)num2, (SpriteEffects)num3, (float)num4); + } + if (Game1.displayFarmer) + Game1.player.draw(Game1.spriteBatch); + if ((Game1.eventUp || Game1.killScreen) && (!Game1.killScreen && Game1.currentLocation.currentEvent != null)) + Game1.currentLocation.currentEvent.draw(Game1.spriteBatch); + if (Game1.player.currentUpgrade != null && Game1.player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && Game1.currentLocation.Name.Equals("Farm")) + Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), new Microsoft.Xna.Framework.Rectangle?(Game1.player.currentUpgrade.getSourceRectangle()), Color.White, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, (float)(((double)Game1.player.currentUpgrade.positionOfCarpenter.Y + (double)(Game1.tileSize * 3 / 4)) / 10000.0)); + Game1.currentLocation.draw(Game1.spriteBatch); + if (Game1.eventUp && Game1.currentLocation.currentEvent != null) + { + string messageToScreen = Game1.currentLocation.currentEvent.messageToScreen; + } + if (Game1.player.ActiveObject == null && (Game1.player.UsingTool || Game1.pickingTool) && (Game1.player.CurrentTool != null && (!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool))) + Game1.drawTool(Game1.player); + if (Game1.currentLocation.Name.Equals("Farm")) + this.drawFarmBuildings(); + if (Game1.tvStation >= 0) + Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(6 * Game1.tileSize + Game1.tileSize / 4), (float)(2 * Game1.tileSize + Game1.tileSize / 2))), new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(Game1.tvStation * 24, 0, 24, 15)), Color.White, 0.0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f); + if (Game1.panMode) + { + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((int)Math.Floor((double)(Game1.getOldMouseX() + Game1.viewport.X) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.X, (int)Math.Floor((double)(Game1.getOldMouseY() + Game1.viewport.Y) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Lime * 0.75f); + foreach (Warp warp in Game1.currentLocation.warps) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(warp.X * Game1.tileSize - Game1.viewport.X, warp.Y * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Red * 0.75f); + } + Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); + Game1.currentLocation.Map.GetLayer("Front").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.mapDisplayDevice.EndScene(); + Game1.currentLocation.drawAboveFrontLayer(Game1.spriteBatch); + Game1.spriteBatch.End(); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + if (Game1.currentLocation.Name.Equals("Farm") && Game1.stats.SeedsSown >= 200U) + { + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(3 * Game1.tileSize + Game1.tileSize / 4), (float)(Game1.tileSize + Game1.tileSize / 3))), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16, -1, -1)), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(4 * Game1.tileSize + Game1.tileSize), (float)(2 * Game1.tileSize + Game1.tileSize))), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16, -1, -1)), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(5 * Game1.tileSize), (float)(2 * Game1.tileSize))), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16, -1, -1)), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(3 * Game1.tileSize + Game1.tileSize / 2), (float)(3 * Game1.tileSize))), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16, -1, -1)), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(5 * Game1.tileSize - Game1.tileSize / 4), (float)Game1.tileSize)), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16, -1, -1)), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(4 * Game1.tileSize), (float)(3 * Game1.tileSize + Game1.tileSize / 6))), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16, -1, -1)), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(4 * Game1.tileSize + Game1.tileSize / 5), (float)(2 * Game1.tileSize + Game1.tileSize / 3))), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16, -1, -1)), Color.White); + } + if (Game1.displayFarmer && Game1.player.ActiveObject != null && (Game1.player.ActiveObject.bigCraftable && this.checkBigCraftableBoundariesForFrontLayer()) && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) + Game1.drawPlayerHeldObject(Game1.player); + else if (Game1.displayFarmer && Game1.player.ActiveObject != null) + { + if (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) == null || Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")) + { + Layer layer1 = Game1.currentLocation.Map.GetLayer("Front"); + rectangle = Game1.player.GetBoundingBox(); + Location mapDisplayLocation1 = new Location(rectangle.Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5); + Size size1 = Game1.viewport.Size; + if (layer1.PickTile(mapDisplayLocation1, size1) != null) + { + Layer layer2 = Game1.currentLocation.Map.GetLayer("Front"); + rectangle = Game1.player.GetBoundingBox(); + Location mapDisplayLocation2 = new Location(rectangle.Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5); + Size size2 = Game1.viewport.Size; + if (layer2.PickTile(mapDisplayLocation2, size2).TileIndexProperties.ContainsKey("FrontAlways")) + goto label_127; + } + else + goto label_127; + } + Game1.drawPlayerHeldObject(Game1.player); + } + label_127: + if ((Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && ((!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool) && (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null))) + Game1.drawTool(Game1.player); + if (Game1.currentLocation.Map.GetLayer("AlwaysFront") != null) + { + Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); + Game1.currentLocation.Map.GetLayer("AlwaysFront").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.mapDisplayDevice.EndScene(); + } + if ((double)Game1.toolHold > 400.0 && Game1.player.CurrentTool.UpgradeLevel >= 1 && Game1.player.canReleaseTool) + { + Color color = Color.White; + switch ((int)((double)Game1.toolHold / 600.0) + 2) + { + case 1: + color = Tool.copperColor; + break; + case 2: + color = Tool.steelColor; + break; + case 3: + color = Tool.goldColor; + break; + case 4: + color = Tool.iridiumColor; + break; + } + Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize) - 2, (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607) + 4, Game1.tileSize / 8 + 4), Color.Black); + Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize), (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607), Game1.tileSize / 8), color); + } + if (Game1.isDebrisWeather && Game1.currentLocation.IsOutdoors && (!Game1.currentLocation.ignoreDebrisWeather && !Game1.currentLocation.Name.Equals("Desert")) && Game1.viewport.X > -10) + { + foreach (WeatherDebris weatherDebris in Game1.debrisWeather) + weatherDebris.draw(Game1.spriteBatch); + } + if (Game1.farmEvent != null) + Game1.farmEvent.draw(Game1.spriteBatch); + if ((double)Game1.currentLocation.LightLevel > 0.0 && Game1.timeOfDay < 2000) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * Game1.currentLocation.LightLevel); + if (Game1.screenGlow) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Game1.screenGlowColor * Game1.screenGlowAlpha); + Game1.currentLocation.drawAboveAlwaysFrontLayer(Game1.spriteBatch); + if (Game1.player.CurrentTool != null && Game1.player.CurrentTool is FishingRod && ((Game1.player.CurrentTool as FishingRod).isTimingCast || (double)(Game1.player.CurrentTool as FishingRod).castingChosenCountdown > 0.0 || ((Game1.player.CurrentTool as FishingRod).fishCaught || (Game1.player.CurrentTool as FishingRod).showingTreasure))) + Game1.player.CurrentTool.draw(Game1.spriteBatch); + if (Game1.isRaining && Game1.currentLocation.IsOutdoors && (!Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit)) && (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2((float)(Game1.viewport.X / Game1.tileSize), (float)(Game1.viewport.Y / Game1.tileSize))))) + { + for (int index = 0; index < Game1.rainDrops.Length; ++index) + Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[index].position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Color.White); + } + Game1.spriteBatch.End(); + //base.Draw(gameTime); + Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + if (Game1.eventUp && Game1.currentLocation.currentEvent != null) + { + foreach (NPC actor in Game1.currentLocation.currentEvent.actors) + { + if (actor.isEmoting) + { + Vector2 localPosition = actor.getLocalPosition(Game1.viewport); + localPosition.Y -= (float)(Game1.tileSize * 2 + Game1.pixelZoom * 3); + if (actor.age == 2) + localPosition.Y += (float)(Game1.tileSize / 2); + else if (actor.gender == 1) + localPosition.Y += (float)(Game1.tileSize / 6); + Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, localPosition, new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(actor.CurrentEmoteIndex * (Game1.tileSize / 4) % Game1.emoteSpriteSheet.Width, actor.CurrentEmoteIndex * (Game1.tileSize / 4) / Game1.emoteSpriteSheet.Width * (Game1.tileSize / 4), Game1.tileSize / 4, Game1.tileSize / 4)), Color.White, 0.0f, Vector2.Zero, 4f, SpriteEffects.None, (float)actor.getStandingY() / 10000f); + } + } + } + Game1.spriteBatch.End(); + if (Game1.drawLighting) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, this.lightingBlend, SamplerState.LinearClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.spriteBatch.Draw((Texture2D)Game1.lightmap, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(Game1.lightmap.Bounds), Color.White, 0.0f, Vector2.Zero, (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 1f); + if (Game1.isRaining && Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert)) + Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.OrangeRed * 0.45f); + Game1.spriteBatch.End(); + } + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + if (Game1.drawGrid) + { + int x1 = -Game1.viewport.X % Game1.tileSize; + float num1 = (float)(-Game1.viewport.Y % Game1.tileSize); + int x2 = x1; + while (x2 < Game1.graphics.GraphicsDevice.Viewport.Width) + { + Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle(x2, (int)num1, 1, Game1.graphics.GraphicsDevice.Viewport.Height), Color.Red * 0.5f); + x2 += Game1.tileSize; + } + float num2 = num1; + while ((double)num2 < (double)Game1.graphics.GraphicsDevice.Viewport.Height) + { + Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle(x1, (int)num2, Game1.graphics.GraphicsDevice.Viewport.Width, 1), Color.Red * 0.5f); + num2 += (float)Game1.tileSize; + } + } + if (Game1.currentBillboard != 0) + this.drawBillboard(); + if ((Game1.displayHUD || Game1.eventUp) && (Game1.currentBillboard == 0 && (int)Game1.gameMode == 3) && (!Game1.freezeControls && !Game1.panMode)) + { + GraphicsEvents.InvokeOnPreRenderHudEvent(this.Monitor); + this.drawHUD(); + GraphicsEvents.InvokeOnPostRenderHudEvent(this.Monitor); + } + else if (Game1.activeClickableMenu == null && Game1.farmEvent == null) + Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2((float)Game1.getOldMouseX(), (float)Game1.getOldMouseY()), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)(4.0 + (double)Game1.dialogueButtonScale / 150.0), SpriteEffects.None, 1f); + if (Game1.hudMessages.Count > 0 && (!Game1.eventUp || Game1.isFestival())) + { + for (int i = Game1.hudMessages.Count - 1; i >= 0; --i) + Game1.hudMessages[i].draw(Game1.spriteBatch, i); + } + } + if (Game1.farmEvent != null) + Game1.farmEvent.draw(Game1.spriteBatch); + if (Game1.dialogueUp && !Game1.nameSelectUp && !Game1.messagePause && (Game1.activeClickableMenu == null || !(Game1.activeClickableMenu is DialogueBox))) + this.drawDialogueBox(); + Viewport viewport; + if (Game1.progressBar) + { + SpriteBatch spriteBatch1 = Game1.spriteBatch; + Texture2D fadeToBlackRect = Game1.fadeToBlackRect; + int x1 = (Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2; + rectangle = Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea; + int y1 = rectangle.Bottom - Game1.tileSize * 2; + int dialogueWidth = Game1.dialogueWidth; + int height1 = Game1.tileSize / 2; + Microsoft.Xna.Framework.Rectangle destinationRectangle1 = new Microsoft.Xna.Framework.Rectangle(x1, y1, dialogueWidth, height1); + Color lightGray = Color.LightGray; + spriteBatch1.Draw(fadeToBlackRect, destinationRectangle1, lightGray); + SpriteBatch spriteBatch2 = Game1.spriteBatch; + Texture2D staminaRect = Game1.staminaRect; + viewport = Game1.graphics.GraphicsDevice.Viewport; + int x2 = (viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2; + viewport = Game1.graphics.GraphicsDevice.Viewport; + rectangle = viewport.TitleSafeArea; + int y2 = rectangle.Bottom - Game1.tileSize * 2; + int width = (int)((double)Game1.pauseAccumulator / (double)Game1.pauseTime * (double)Game1.dialogueWidth); + int height2 = Game1.tileSize / 2; + Microsoft.Xna.Framework.Rectangle destinationRectangle2 = new Microsoft.Xna.Framework.Rectangle(x2, y2, width, height2); + Color dimGray = Color.DimGray; + spriteBatch2.Draw(staminaRect, destinationRectangle2, dimGray); + } + if (Game1.eventUp && Game1.currentLocation != null && Game1.currentLocation.currentEvent != null) + Game1.currentLocation.currentEvent.drawAfterMap(Game1.spriteBatch); + if (Game1.isRaining && Game1.currentLocation != null && (Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert))) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D staminaRect = Game1.staminaRect; + viewport = Game1.graphics.GraphicsDevice.Viewport; + Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; + Color color = Color.Blue * 0.2f; + spriteBatch.Draw(staminaRect, bounds, color); + } + if ((Game1.fadeToBlack || Game1.globalFade) && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D fadeToBlackRect = Game1.fadeToBlackRect; + viewport = Game1.graphics.GraphicsDevice.Viewport; + Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; + Color color = Color.Black * ((int)Game1.gameMode == 0 ? 1f - Game1.fadeToBlackAlpha : Game1.fadeToBlackAlpha); + spriteBatch.Draw(fadeToBlackRect, bounds, color); + } + else if ((double)Game1.flashAlpha > 0.0) + { + if (Game1.options.screenFlash) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D fadeToBlackRect = Game1.fadeToBlackRect; + viewport = Game1.graphics.GraphicsDevice.Viewport; + Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; + Color color = Color.White * Math.Min(1f, Game1.flashAlpha); + spriteBatch.Draw(fadeToBlackRect, bounds, color); + } + Game1.flashAlpha -= 0.1f; + } + if ((Game1.messagePause || Game1.globalFade) && Game1.dialogueUp) + this.drawDialogueBox(); + foreach (TemporaryAnimatedSprite overlayTempSprite in Game1.screenOverlayTempSprites) + overlayTempSprite.draw(Game1.spriteBatch, true, 0, 0); + if (Game1.debugMode) + { + SpriteBatch spriteBatch = Game1.spriteBatch; + SpriteFont smallFont = Game1.smallFont; + object[] objArray = new object[10]; + int index1 = 0; + string str1; + if (!Game1.panMode) + str1 = "player: " + (object)(Game1.player.getStandingX() / Game1.tileSize) + ", " + (object)(Game1.player.getStandingY() / Game1.tileSize); + else + str1 = ((Game1.getOldMouseX() + Game1.viewport.X) / Game1.tileSize).ToString() + "," + (object)((Game1.getOldMouseY() + Game1.viewport.Y) / Game1.tileSize); + objArray[index1] = (object)str1; + int index2 = 1; + string str2 = " mouseTransparency: "; + objArray[index2] = (object)str2; + int index3 = 2; + float cursorTransparency = Game1.mouseCursorTransparency; + objArray[index3] = (object)cursorTransparency; + int index4 = 3; + string str3 = " mousePosition: "; + objArray[index4] = (object)str3; + int index5 = 4; + int mouseX = Game1.getMouseX(); + objArray[index5] = (object)mouseX; + int index6 = 5; + string str4 = ","; + objArray[index6] = (object)str4; + int index7 = 6; + int mouseY = Game1.getMouseY(); + objArray[index7] = (object)mouseY; + int index8 = 7; + string newLine = Environment.NewLine; + objArray[index8] = (object)newLine; + int index9 = 8; + string str5 = "debugOutput: "; + objArray[index9] = (object)str5; + int index10 = 9; + string debugOutput = Game1.debugOutput; + objArray[index10] = (object)debugOutput; + string text = string.Concat(objArray); + Vector2 position = new Vector2((float)this.GraphicsDevice.Viewport.TitleSafeArea.X, (float)this.GraphicsDevice.Viewport.TitleSafeArea.Y); + Color red = Color.Red; + double num1 = 0.0; + Vector2 zero = Vector2.Zero; + double num2 = 1.0; + int num3 = 0; + double num4 = 0.99999988079071; + spriteBatch.DrawString(smallFont, text, position, red, (float)num1, zero, (float)num2, (SpriteEffects)num3, (float)num4); + } + if (Game1.showKeyHelp) + Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2((float)Game1.tileSize, (float)(Game1.viewport.Height - Game1.tileSize - (Game1.dialogueUp ? Game1.tileSize * 3 + (Game1.isQuestion ? Game1.questionChoices.Count * Game1.tileSize : 0) : 0)) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Color.LightGray, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + if (Game1.activeClickableMenu != null) + { + try + { + GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); + Game1.activeClickableMenu.draw(Game1.spriteBatch); + GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); + } + catch (Exception ex) + { + this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + Game1.activeClickableMenu.exitThisMenu(); + } + } + else if (Game1.farmEvent != null) + Game1.farmEvent.drawAboveEverything(Game1.spriteBatch); + Game1.spriteBatch.End(); + if (Game1.overlayMenu != null) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); + } - if (Game1.hudMessages.Any() && (!Game1.eventUp || Game1.isFestival())) - { - for (int l = Game1.hudMessages.Count - 1; l >= 0; l--) - Game1.hudMessages[l].draw(Game1.spriteBatch, l); - } - } - Game1.farmEvent?.draw(Game1.spriteBatch); - if (Game1.dialogueUp && !Game1.nameSelectUp && !Game1.messagePause && !(Game1.activeClickableMenu is DialogueBox)) - this.drawDialogueBox(); - if (Game1.progressBar) - { - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle((Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - Game1.tileSize * 2, Game1.dialogueWidth, Game1.tileSize / 2), Color.LightGray); - Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle((Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - Game1.tileSize * 2, (int)(Game1.pauseAccumulator / Game1.pauseTime * Game1.dialogueWidth), Game1.tileSize / 2), Color.DimGray); - } - if (Game1.eventUp) - Game1.currentLocation.currentEvent?.drawAfterMap(Game1.spriteBatch); - if (Game1.isRaining && Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert)) - Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Blue * 0.2f); - if ((Game1.fadeToBlack || Game1.globalFade) && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha)); - else if (Game1.flashAlpha > 0f) - { - if (Game1.options.screenFlash) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.White * Math.Min(1f, Game1.flashAlpha)); - Game1.flashAlpha -= 0.1f; - } - if ((Game1.messagePause || Game1.globalFade) && Game1.dialogueUp) - this.drawDialogueBox(); - foreach (TemporaryAnimatedSprite current8 in Game1.screenOverlayTempSprites) - current8.draw(Game1.spriteBatch, true); - if (Game1.debugMode) - { - Game1.spriteBatch.DrawString(Game1.smallFont, string.Concat(new object[] - { - Game1.panMode ? ((Game1.getOldMouseX() + Game1.viewport.X) / Game1.tileSize + "," + (Game1.getOldMouseY() + Game1.viewport.Y) / Game1.tileSize) : string.Concat("aplayer: ", Game1.player.getStandingX() / Game1.tileSize, ", ", Game1.player.getStandingY() / Game1.tileSize), - Environment.NewLine, - "debugOutput: ", - Game1.debugOutput - }), new Vector2(this.GraphicsDevice.Viewport.TitleSafeArea.X, this.GraphicsDevice.Viewport.TitleSafeArea.Y), Color.Red, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); - } - /*if (inputMode) - { - spriteBatch.DrawString(smallFont, "Input: " + debugInput, new Vector2(tileSize, tileSize * 3), Color.Purple); - }*/ - if (Game1.showKeyHelp) - Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(Game1.tileSize, Game1.viewport.Height - Game1.tileSize - (Game1.dialogueUp ? (Game1.tileSize * 3 + (Game1.isQuestion ? (Game1.questionChoices.Count * Game1.tileSize) : 0)) : 0) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Color.LightGray, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + if (GraphicsEvents.HasPostRenderListeners()) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + GraphicsEvents.InvokeOnPostRenderEvent(this.Monitor); + Game1.spriteBatch.End(); + } - if (Game1.activeClickableMenu != null) - { - GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); - try - { - Game1.activeClickableMenu.draw(Game1.spriteBatch); - } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); + this.renderScreenBuffer(); + } } - GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); - } - else - Game1.farmEvent?.drawAboveEverything(Game1.spriteBatch); - - GraphicsEvents.InvokeOnPostRenderEvent(this.Monitor); - Game1.spriteBatch.End(); - - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); } } catch (Exception ex) @@ -801,8 +1075,19 @@ namespace StardewModdingAPI.Framework /// Detect changes since the last update ticket and trigger mod events. private void UpdateEventCalls() { + // content locale changed event + if (this.PreviousLocale != LocalizedContentManager.CurrentLanguageCode) + { + var oldValue = this.PreviousLocale; + var newValue = LocalizedContentManager.CurrentLanguageCode; + + if (oldValue != null) + ContentEvents.InvokeAfterLocaleChanged(this.Monitor, oldValue.ToString(), newValue.ToString()); + this.PreviousLocale = newValue; + } + // save loaded event - if (Constants.IsSaveLoaded && this.AfterLoadTimer >= 0) + if (Constants.IsSaveLoaded && !SaveGame.IsProcessing/*still loading save*/ && this.AfterLoadTimer >= 0) { if (this.AfterLoadTimer == 0) { @@ -1060,4 +1345,4 @@ namespace StardewModdingAPI.Framework return hash; } } -} \ No newline at end of file +} diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 58850dc3..019ac0e3 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -246,10 +246,7 @@ namespace StardewModdingAPI this.GameInstance.Exiting += (sender, e) => this.IsGameRunning = false; this.GameInstance.Window.ClientSizeChanged += (sender, e) => GraphicsEvents.InvokeResize(this.Monitor, sender, e); this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} with SMAPI {Constants.ApiVersion}"; - { - Type type = typeof(Game1).Assembly.GetType("StardewValley.Program", true); - type.GetField("gamePtr").SetValue(null, this.GameInstance); - } + StardewValley.Program.gamePtr = this.GameInstance; // configure Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json index 0b6f3a37..9438c621 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.config.json +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -27,6 +27,15 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha * Changing this field is not recommended and may destabilise your game. */ "ModCompatibility": [ + { + "Name": "AccessChestAnywhere", + "ID": "AccessChestAnywhere", + "UpperVersion": "1.1", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/257", + "UnofficialUpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." + }, { "Name": "Almighty Tool", "ID": "AlmightyTool.dll", @@ -49,7 +58,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpperVersion": "2.3", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/41", - "Notes": "Uses obsolete StardewModdingAPI.Extensions." + "Notes": "ID changed in 2.3. Uses obsolete StardewModdingAPI.Extensions." }, { "Name": "Chest Label System", @@ -59,6 +68,30 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/242", "Notes": "Not compatible with Stardew Valley 1.1+" }, + { + "Name": "Chests Anywhere", + "ID": "ChestsAnywhere", + "UpperVersion": "1.8.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "Notes": "Crashes with 'Method not found: Void StardewValley.Menus.TextBox.set_Highlighted(Boolean)'." + }, + { + "Name": "Chests Anywhere", + "ID": "Pathoschild.ChestsAnywhere", + "UpperVersion": "1.9-beta", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "Notes": "ID changed in 1.9. Crashes with InvalidOperationException: 'The menu doesn't seem to have a player inventory'." + }, + { + "Name": "CJB Automation", + "ID": "CJBAutomation", + "UpperVersion": "1.4", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/211", + "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." + }, { "Name": "CJB Cheats Menu", "ID": "CJBCheatsMenu", @@ -81,6 +114,14 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", "Notes": "Uses SMAPI's internal SGame class." }, + { + "Name": "Cooking Skill", + "ID": "CookingSkill", + "UpperVersion": "1.0.3", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/522", + "Notes": "Crashes with 'Method not found: Void StardewValley.Buff..ctor(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, System.String)'." + }, { "Name": "Enemy Health Bars", "ID": "SPDHealthBar", @@ -97,6 +138,38 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://community.playstarbound.com/resources/4228", "Notes": "Uses obsolete StardewModdingAPI.Inheritance.SObject until 1.6.1; then crashes until 1.6.4 ('Entoarox Framework requested an immediate game shutdown: Fatal error attempting to update player tick properties System.NullReferenceException: Object reference not set to an instance of an object. at Entoarox.Framework.PlayerHelper.Update(Object s, EventArgs e)')." }, + { + "Name": "Extended Fridge", + "ID": "Mystra007ExtendedFridge", + "UpperVersion": "1.0", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/485", + "Notes": "Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest. Crashes with 'Field not found: StardewValley.Game1.mouseCursorTransparency'." + }, + { + "Name": "Get Dressed", + "ID": "GetDressed.dll", + "UpperVersion": "3.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/331", + "Notes": "Crashes with NullReferenceException in GameEvents.UpdateTick." + }, + { + "Name": "Lookup Anything", + "ID": "LookupAnything", + "UpperVersion": "1.10", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", + "Notes": "Crashes with FormatException when looking up NPCs." + }, + { + "Name": "Lookup Anything", + "ID": "Pathoschild.LookupAnything", + "UpperVersion": "1.10.1", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", + "Notes": "ID changed in 1.10.1. Crashes with FormatException when looking up NPCs." + }, { "Name": "Makeshift Multiplayer", "ID": "StardewValleyMP", @@ -111,7 +184,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpperVersion": "0.5", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/237", - "Notes": "Uses obsolete StardewModdingAPI.Extensions." + "Notes": "Uses obsolete StardewModdingAPI.Extensions and Assembly.GetExecutingAssembly().Location." }, { "Name": "NPC Map Locations", @@ -154,6 +227,14 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/683", "Notes": "Crashes with 'Method not found: Void StardewModdingAPI.Command.CallCommand(System.String)'." }, + { + "Name": "Teleporter", + "ID": "Teleporter", + "UpperVersion": "1.0.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/resources/4374", + "Notes": "Crashes with 'InvalidOperationException: The StardewValley.Menus.MapPage object doesn't have a private 'points' instance field'." + }, { "Name": "Zoryn's Better RNG", "ID": "76b6d1e1-f7ba-4d72-8c32-5a1e6d2716f6", -- cgit From 780c3335e8b9377144c782834b24ebfaf0769f0e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 1 Apr 2017 12:39:04 -0400 Subject: rewrite references to Game1.currentMinigame broken by SDV 1.2 --- src/StardewModdingAPI/Constants.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 6091b864..c4051258 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -174,6 +174,7 @@ namespace StardewModdingAPI // Stardew Valley 1.2 new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.activeClickableMenu)), + new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.currentMinigame)), new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.gameMode)), new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.player)), new FieldReplaceRewriter(typeof(Game1), "borderFont", nameof(Game1.smallFont)), -- cgit From 4f87a2b478b9c15ac3eb3d245228e9e72ac847ae Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 7 Apr 2017 15:36:45 -0400 Subject: fix mouse-changed event never updating prior mouse position --- release-notes.md | 6 ++++++ src/StardewModdingAPI/Framework/SGame.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index a5ef4a0b..5c693292 100644 --- a/release-notes.md +++ b/release-notes.md @@ -15,6 +15,12 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). * SMAPI now rewrites many mods for compatibility with game updates, but some mods will need an update. --> +## 1.9.1 +See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.9.1). + +For mod developers: +* Fixed mouse-changed event never updating prior mouse position. + ## 1.9 See [log](https://github.com/Pathoschild/SMAPI/compare/1.8...1.9). diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 5f265139..0b4d7494 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -874,7 +874,7 @@ namespace StardewModdingAPI.Framework { ControlEvents.InvokeMouseChanged(this.Monitor, this.MStatePrior, this.MStateNow, this.MPositionPrior, this.MPositionNow); this.MStatePrior = this.MStateNow; - this.MPositionPrior = this.MPositionPrior; + this.MPositionPrior = this.MPositionNow; } } -- cgit From 7f8d738e86ae602edc91f0fa80643ee0cf47b089 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 00:03:12 -0400 Subject: tweak installer to suggest common fix for file permission issues --- src/StardewModdingAPI.Installer/InteractiveInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs index fffba30f..b59e8305 100644 --- a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs +++ b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs @@ -435,7 +435,7 @@ namespace StardewModdingApi.Installer catch (Exception ex) { this.PrintError($"Oops! The installer couldn't delete {path}: [{ex.GetType().Name}] {ex.Message}."); - this.PrintError("Please delete it yourself, then press any key to retry."); + this.PrintError("Try rebooting your computer and then run the installer again. If that doesn't work, try deleting it yourself then press any key to retry."); Console.ReadKey(); } } -- cgit From bcaf5b21c1e64ddca29b27d2b96652a3d925d8ff Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 18:57:43 -0400 Subject: remove Initialize/LoadContent overrides & deprecate related events (#265) --- src/StardewModdingAPI/Events/GameEvents.cs | 48 ++++++++++++++++++++++++------ src/StardewModdingAPI/Framework/SGame.cs | 24 ++++----------- src/StardewModdingAPI/Program.cs | 1 + 3 files changed, 45 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Events/GameEvents.cs b/src/StardewModdingAPI/Events/GameEvents.cs index 715083b9..47c1275b 100644 --- a/src/StardewModdingAPI/Events/GameEvents.cs +++ b/src/StardewModdingAPI/Events/GameEvents.cs @@ -6,18 +6,27 @@ namespace StardewModdingAPI.Events /// Events raised when the game changes state. public static class GameEvents { + /********* + ** Properties + *********/ + /// Manages deprecation warnings. + private static DeprecationManager DeprecationManager; + + /********* ** Events *********/ /// Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called during . + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(Initialize) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] public static event EventHandler Initialize; - /// Raised during launch after configuring Stardew Valley, loading it into memory, and opening the game window. The window is still blank by this point. - public static event EventHandler GameLoaded; - /// Raised before XNA loads or reloads graphics resources. Called during . + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(LoadContent) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] public static event EventHandler LoadContent; + /// Raised during launch after configuring Stardew Valley, loading it into memory, and opening the game window. The window is still blank by this point. + public static event EventHandler GameLoaded; + /// Raised during the first game update tick. public static event EventHandler FirstUpdateTick; @@ -46,25 +55,46 @@ namespace StardewModdingAPI.Events /********* ** Internal methods *********/ - /// Raise a event. - /// Encapsulates monitoring and logging. - internal static void InvokeGameLoaded(IMonitor monitor) + /// Injects types required for backwards compatibility. + /// Manages deprecation warnings. + internal static void Shim(DeprecationManager deprecationManager) { - monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoaded)}", GameEvents.GameLoaded?.GetInvocationList()); + GameEvents.DeprecationManager = deprecationManager; } /// Raise an event. /// Encapsulates logging and monitoring. internal static void InvokeInitialize(IMonitor monitor) { - monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.Initialize)}", GameEvents.Initialize?.GetInvocationList()); + if (GameEvents.Initialize == null) + return; + + string name = $"{nameof(GameEvents)}.{nameof(GameEvents.Initialize)}"; + Delegate[] handlers = GameEvents.Initialize.GetInvocationList(); + + GameEvents.DeprecationManager.WarnForEvent(handlers, name, "1.10", DeprecationLevel.Info); + monitor.SafelyRaisePlainEvent(name, handlers); } /// Raise a event. /// Encapsulates logging and monitoring. internal static void InvokeLoadContent(IMonitor monitor) { - monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.LoadContent)}", GameEvents.LoadContent?.GetInvocationList()); + if (GameEvents.LoadContent == null) + return; + + string name = $"{nameof(GameEvents)}.{nameof(GameEvents.LoadContent)}"; + Delegate[] handlers = GameEvents.LoadContent.GetInvocationList(); + + GameEvents.DeprecationManager.WarnForEvent(handlers, name, "1.10", DeprecationLevel.Info); + monitor.SafelyRaisePlainEvent(name, handlers); + } + + /// Raise a event. + /// Encapsulates monitoring and logging. + internal static void InvokeGameLoaded(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoaded)}", GameEvents.GameLoaded?.GetInvocationList()); } /// Raise an event. diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 0b4d7494..0bbab904 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -48,7 +48,7 @@ namespace StardewModdingAPI.Framework ** Game state ****/ /// Arrays of pressed controller buttons indexed by . - private Buttons[][] PreviouslyPressedButtons; + private readonly Buttons[][] PreviouslyPressedButtons = { new Buttons[0], new Buttons[0], new Buttons[0], new Buttons[0] }; /// A record of the keyboard state (i.e. the up/down state for each button) as of the latest tick. private KeyboardState KStateNow; @@ -173,31 +173,17 @@ namespace StardewModdingAPI.Framework /**** ** Intercepted methods & events ****/ - /// The method called during game launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. - protected override void Initialize() - { - this.PreviouslyPressedButtons = new Buttons[4][]; - for (var i = 0; i < 4; ++i) - this.PreviouslyPressedButtons[i] = new Buttons[0]; - - base.Initialize(); - GameEvents.InvokeInitialize(this.Monitor); - } - - /// The method called before XNA or MonoGame loads or reloads graphics resources. - protected override void LoadContent() - { - base.LoadContent(); - GameEvents.InvokeLoadContent(this.Monitor); - } - /// The method called when the game is updating its state. This happens roughly 60 times per second. /// A snapshot of the game timing state. protected override void Update(GameTime gameTime) { // raise game loaded if (this.FirstUpdate) + { + GameEvents.InvokeInitialize(this.Monitor); + GameEvents.InvokeLoadContent(this.Monitor); GameEvents.InvokeGameLoaded(this.Monitor); + } // update SMAPI events this.UpdateEventCalls(); diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 58850dc3..909a817c 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -120,6 +120,7 @@ namespace StardewModdingAPI Log.Shim(this.DeprecationManager, this.GetSecondaryMonitor("legacy mod"), this.ModRegistry); Mod.Shim(this.DeprecationManager); ContentEvents.Shim(this.ModRegistry, this.Monitor); + GameEvents.Shim(this.DeprecationManager); PlayerEvents.Shim(this.DeprecationManager); TimeEvents.Shim(this.DeprecationManager); #pragma warning restore 618 -- cgit From 489cacca5ef79a77ca04d12395ff1ec5c7a05c5f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 19:12:48 -0400 Subject: minor cleanup --- .../InteractiveInstaller.cs | 32 +++++++++++----------- .../Events/EventArgsClickableMenuChanged.cs | 4 +-- .../Events/EventArgsClickableMenuClosed.cs | 2 +- src/StardewModdingAPI/Events/EventArgsCommand.cs | 2 +- .../Events/EventArgsControllerButtonPressed.cs | 4 +-- .../Events/EventArgsControllerButtonReleased.cs | 4 +-- .../Events/EventArgsControllerTriggerPressed.cs | 6 ++-- .../Events/EventArgsControllerTriggerReleased.cs | 6 ++-- .../Events/EventArgsCurrentLocationChanged.cs | 4 +-- .../Events/EventArgsGameLocationsChanged.cs | 2 +- .../Events/EventArgsInventoryChanged.cs | 8 +++--- .../Events/EventArgsKeyPressed.cs | 2 +- .../Events/EventArgsKeyboardStateChanged.cs | 4 +-- src/StardewModdingAPI/Events/EventArgsLevelUp.cs | 4 +-- .../Events/EventArgsLoadedGameChanged.cs | 2 +- .../Events/EventArgsLocationObjectsChanged.cs | 2 +- .../Events/EventArgsMineLevelChanged.cs | 4 +-- .../Events/EventArgsMouseStateChanged.cs | 8 +++--- src/StardewModdingAPI/Events/EventArgsNewDay.cs | 6 ++-- .../Events/EventArgsStringChanged.cs | 4 +-- src/StardewModdingAPI/Framework/AssemblyLoader.cs | 2 +- .../Framework/InternalExtensions.cs | 12 ++++---- src/StardewModdingAPI/Framework/Monitor.cs | 2 +- 23 files changed, 63 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs index b59e8305..e1e62d89 100644 --- a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs +++ b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs @@ -65,30 +65,30 @@ namespace StardewModdingApi.Installer /// The folder for SMAPI mods. private IEnumerable GetUninstallPaths(DirectoryInfo installDir, DirectoryInfo modsDir) { - Func installPath = path => Path.Combine(installDir.FullName, path); + string GetInstallPath(string path) => Path.Combine(installDir.FullName, path); // common - yield return installPath("Mono.Cecil.dll"); - yield return installPath("Newtonsoft.Json.dll"); - yield return installPath("StardewModdingAPI.exe"); - yield return installPath("StardewModdingAPI.config.json"); - yield return installPath("StardewModdingAPI.data.json"); - yield return installPath("StardewModdingAPI.AssemblyRewriters.dll"); - yield return installPath("steam_appid.txt"); + yield return GetInstallPath("Mono.Cecil.dll"); + yield return GetInstallPath("Newtonsoft.Json.dll"); + yield return GetInstallPath("StardewModdingAPI.exe"); + yield return GetInstallPath("StardewModdingAPI.config.json"); + yield return GetInstallPath("StardewModdingAPI.data.json"); + yield return GetInstallPath("StardewModdingAPI.AssemblyRewriters.dll"); + yield return GetInstallPath("steam_appid.txt"); // Linux/Mac only - yield return installPath("StardewModdingAPI"); - yield return installPath("StardewModdingAPI.exe.mdb"); - yield return installPath("System.Numerics.dll"); - yield return installPath("System.Runtime.Caching.dll"); + yield return GetInstallPath("StardewModdingAPI"); + yield return GetInstallPath("StardewModdingAPI.exe.mdb"); + yield return GetInstallPath("System.Numerics.dll"); + yield return GetInstallPath("System.Runtime.Caching.dll"); // Windows only - yield return installPath("StardewModdingAPI.pdb"); + yield return GetInstallPath("StardewModdingAPI.pdb"); // obsolete - yield return installPath("Mods/.cache"); // 1.3-1.4 - yield return installPath("Mono.Cecil.Rocks.dll"); // 1.3–1.8 - yield return installPath("StardewModdingAPI-settings.json"); // 1.0-1.4 + yield return GetInstallPath("Mods/.cache"); // 1.3-1.4 + yield return GetInstallPath("Mono.Cecil.Rocks.dll"); // 1.3–1.8 + yield return GetInstallPath("StardewModdingAPI-settings.json"); // 1.0-1.4 if (modsDir.Exists) { foreach (DirectoryInfo modDir in modsDir.EnumerateDirectories()) diff --git a/src/StardewModdingAPI/Events/EventArgsClickableMenuChanged.cs b/src/StardewModdingAPI/Events/EventArgsClickableMenuChanged.cs index 708c02e0..2a2aa163 100644 --- a/src/StardewModdingAPI/Events/EventArgsClickableMenuChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsClickableMenuChanged.cs @@ -10,10 +10,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The previous menu. - public IClickableMenu NewMenu { get; private set; } + public IClickableMenu NewMenu { get; } /// The current menu. - public IClickableMenu PriorMenu { get; private set; } + public IClickableMenu PriorMenu { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsClickableMenuClosed.cs b/src/StardewModdingAPI/Events/EventArgsClickableMenuClosed.cs index 1a62432f..5e6585f0 100644 --- a/src/StardewModdingAPI/Events/EventArgsClickableMenuClosed.cs +++ b/src/StardewModdingAPI/Events/EventArgsClickableMenuClosed.cs @@ -10,7 +10,7 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The menu that was closed. - public IClickableMenu PriorMenu { get; private set; } + public IClickableMenu PriorMenu { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsCommand.cs b/src/StardewModdingAPI/Events/EventArgsCommand.cs index bae13694..88a9e5a3 100644 --- a/src/StardewModdingAPI/Events/EventArgsCommand.cs +++ b/src/StardewModdingAPI/Events/EventArgsCommand.cs @@ -10,7 +10,7 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The triggered command. - public Command Command { get; private set; } + public Command Command { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsControllerButtonPressed.cs b/src/StardewModdingAPI/Events/EventArgsControllerButtonPressed.cs index 87c96678..3243b80b 100644 --- a/src/StardewModdingAPI/Events/EventArgsControllerButtonPressed.cs +++ b/src/StardewModdingAPI/Events/EventArgsControllerButtonPressed.cs @@ -11,10 +11,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; private set; } + public PlayerIndex PlayerIndex { get; } /// The controller button that was pressed. - public Buttons ButtonPressed { get; private set; } + public Buttons ButtonPressed { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsControllerButtonReleased.cs b/src/StardewModdingAPI/Events/EventArgsControllerButtonReleased.cs index cb53b545..e05a080b 100644 --- a/src/StardewModdingAPI/Events/EventArgsControllerButtonReleased.cs +++ b/src/StardewModdingAPI/Events/EventArgsControllerButtonReleased.cs @@ -11,10 +11,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; private set; } + public PlayerIndex PlayerIndex { get; } /// The controller button that was pressed. - public Buttons ButtonReleased { get; private set; } + public Buttons ButtonReleased { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsControllerTriggerPressed.cs b/src/StardewModdingAPI/Events/EventArgsControllerTriggerPressed.cs index 72b73040..a2087733 100644 --- a/src/StardewModdingAPI/Events/EventArgsControllerTriggerPressed.cs +++ b/src/StardewModdingAPI/Events/EventArgsControllerTriggerPressed.cs @@ -11,13 +11,13 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; private set; } + public PlayerIndex PlayerIndex { get; } /// The controller button that was pressed. - public Buttons ButtonPressed { get; private set; } + public Buttons ButtonPressed { get; } /// The current trigger value. - public float Value { get; private set; } + public float Value { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsControllerTriggerReleased.cs b/src/StardewModdingAPI/Events/EventArgsControllerTriggerReleased.cs index de28a159..d2eecbec 100644 --- a/src/StardewModdingAPI/Events/EventArgsControllerTriggerReleased.cs +++ b/src/StardewModdingAPI/Events/EventArgsControllerTriggerReleased.cs @@ -11,13 +11,13 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; private set; } + public PlayerIndex PlayerIndex { get; } /// The controller button that was released. - public Buttons ButtonReleased { get; private set; } + public Buttons ButtonReleased { get; } /// The current trigger value. - public float Value { get; private set; } + public float Value { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsCurrentLocationChanged.cs b/src/StardewModdingAPI/Events/EventArgsCurrentLocationChanged.cs index aa0bb377..25d3ebf3 100644 --- a/src/StardewModdingAPI/Events/EventArgsCurrentLocationChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsCurrentLocationChanged.cs @@ -10,10 +10,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The player's current location. - public GameLocation NewLocation { get; private set; } + public GameLocation NewLocation { get; } /// The player's previous location. - public GameLocation PriorLocation { get; private set; } + public GameLocation PriorLocation { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsGameLocationsChanged.cs b/src/StardewModdingAPI/Events/EventArgsGameLocationsChanged.cs index c68951ce..fb8c821e 100644 --- a/src/StardewModdingAPI/Events/EventArgsGameLocationsChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsGameLocationsChanged.cs @@ -11,7 +11,7 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The current list of game locations. - public List NewLocations { get; private set; } + public List NewLocations { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsInventoryChanged.cs b/src/StardewModdingAPI/Events/EventArgsInventoryChanged.cs index 11cbcedf..1ee02842 100644 --- a/src/StardewModdingAPI/Events/EventArgsInventoryChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsInventoryChanged.cs @@ -12,16 +12,16 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The player's inventory. - public List Inventory { get; private set; } + public List Inventory { get; } /// The added items. - public List Added { get; private set; } + public List Added { get; } /// The removed items. - public List Removed { get; private set; } + public List Removed { get; } /// The items whose stack sizes changed. - public List QuantityChanged { get; private set; } + public List QuantityChanged { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsKeyPressed.cs b/src/StardewModdingAPI/Events/EventArgsKeyPressed.cs index 82a593be..d9d81e10 100644 --- a/src/StardewModdingAPI/Events/EventArgsKeyPressed.cs +++ b/src/StardewModdingAPI/Events/EventArgsKeyPressed.cs @@ -10,7 +10,7 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The keyboard button that was pressed. - public Keys KeyPressed { get; private set; } + public Keys KeyPressed { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsKeyboardStateChanged.cs b/src/StardewModdingAPI/Events/EventArgsKeyboardStateChanged.cs index 2e314731..14e397ce 100644 --- a/src/StardewModdingAPI/Events/EventArgsKeyboardStateChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsKeyboardStateChanged.cs @@ -10,10 +10,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The previous keyboard state. - public KeyboardState NewState { get; private set; } + public KeyboardState NewState { get; } /// The current keyboard state. - public KeyboardState PriorState { get; private set; } + public KeyboardState PriorState { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsLevelUp.cs b/src/StardewModdingAPI/Events/EventArgsLevelUp.cs index 826914da..fe6696d4 100644 --- a/src/StardewModdingAPI/Events/EventArgsLevelUp.cs +++ b/src/StardewModdingAPI/Events/EventArgsLevelUp.cs @@ -9,10 +9,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The player skill that leveled up. - public LevelType Type { get; private set; } + public LevelType Type { get; } /// The new skill level. - public int NewLevel { get; private set; } + public int NewLevel { get; } /// The player skill types. public enum LevelType diff --git a/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs b/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs index cd7a366f..51d64016 100644 --- a/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs @@ -9,7 +9,7 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// Whether the save has been loaded. This is always true. - public bool LoadedGame { get; private set; } + public bool LoadedGame { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsLocationObjectsChanged.cs b/src/StardewModdingAPI/Events/EventArgsLocationObjectsChanged.cs index f708ab6b..058999e9 100644 --- a/src/StardewModdingAPI/Events/EventArgsLocationObjectsChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsLocationObjectsChanged.cs @@ -12,7 +12,7 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The current list of objects in the current location. - public SerializableDictionary NewObjects { get; private set; } + public SerializableDictionary NewObjects { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsMineLevelChanged.cs b/src/StardewModdingAPI/Events/EventArgsMineLevelChanged.cs index a02921d2..c82fed35 100644 --- a/src/StardewModdingAPI/Events/EventArgsMineLevelChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsMineLevelChanged.cs @@ -9,10 +9,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The previous mine level. - public int PreviousMineLevel { get; private set; } + public int PreviousMineLevel { get; } /// The current mine level. - public int CurrentMineLevel { get; private set; } + public int CurrentMineLevel { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsMouseStateChanged.cs b/src/StardewModdingAPI/Events/EventArgsMouseStateChanged.cs index a589e29d..57298164 100644 --- a/src/StardewModdingAPI/Events/EventArgsMouseStateChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsMouseStateChanged.cs @@ -11,16 +11,16 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The previous mouse state. - public MouseState PriorState { get; private set; } + public MouseState PriorState { get; } /// The current mouse state. - public MouseState NewState { get; private set; } + public MouseState NewState { get; } /// The previous mouse position on the screen adjusted for the zoom level. - public Point PriorPosition { get; private set; } + public Point PriorPosition { get; } /// The current mouse position on the screen adjusted for the zoom level. - public Point NewPosition { get; private set; } + public Point NewPosition { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsNewDay.cs b/src/StardewModdingAPI/Events/EventArgsNewDay.cs index 5088cb5c..aba837e4 100644 --- a/src/StardewModdingAPI/Events/EventArgsNewDay.cs +++ b/src/StardewModdingAPI/Events/EventArgsNewDay.cs @@ -9,13 +9,13 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The previous day value. - public int PreviousDay { get; private set; } + public int PreviousDay { get; } /// The current day value. - public int CurrentDay { get; private set; } + public int CurrentDay { get; } /// Whether the game just started the transition (true) or finished it (false). - public bool IsNewDay { get; private set; } + public bool IsNewDay { get; } /********* diff --git a/src/StardewModdingAPI/Events/EventArgsStringChanged.cs b/src/StardewModdingAPI/Events/EventArgsStringChanged.cs index f91951ae..85b6fab5 100644 --- a/src/StardewModdingAPI/Events/EventArgsStringChanged.cs +++ b/src/StardewModdingAPI/Events/EventArgsStringChanged.cs @@ -9,10 +9,10 @@ namespace StardewModdingAPI.Events ** Accessors *********/ /// The previous value. - public string NewString { get; private set; } + public string NewString { get; } /// The current value. - public string PriorString { get; private set; } + public string PriorString { get; } /********* ** Public methods diff --git a/src/StardewModdingAPI/Framework/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/AssemblyLoader.cs index f6fe89f5..2c9973c1 100644 --- a/src/StardewModdingAPI/Framework/AssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/AssemblyLoader.cs @@ -284,7 +284,7 @@ namespace StardewModdingAPI.Framework { if (!hash.Contains(message)) { - this.Monitor.Log(message, level); + monitor.Log(message, level); hash.Add(message); } } diff --git a/src/StardewModdingAPI/Framework/InternalExtensions.cs b/src/StardewModdingAPI/Framework/InternalExtensions.cs index 4ca79518..a2d589ff 100644 --- a/src/StardewModdingAPI/Framework/InternalExtensions.cs +++ b/src/StardewModdingAPI/Framework/InternalExtensions.cs @@ -39,7 +39,7 @@ namespace StardewModdingAPI.Framework if (handlers == null) return; - foreach (EventHandler handler in Enumerable.Cast(handlers)) + foreach (EventHandler handler in handlers.Cast()) { try { @@ -64,7 +64,7 @@ namespace StardewModdingAPI.Framework if (handlers == null) return; - foreach (EventHandler handler in Enumerable.Cast>(handlers)) + foreach (EventHandler handler in handlers.Cast>()) { try { @@ -85,14 +85,14 @@ namespace StardewModdingAPI.Framework public static string GetLogSummary(this Exception exception) { // type load exception - if (exception is TypeLoadException) - return $"Failed loading type: {((TypeLoadException)exception).TypeName}: {exception}"; + if (exception is TypeLoadException typeLoadEx) + return $"Failed loading type: {typeLoadEx.TypeName}: {exception}"; // reflection type load exception - if (exception is ReflectionTypeLoadException) + if (exception is ReflectionTypeLoadException reflectionTypeLoadEx) { string summary = exception.ToString(); - foreach (Exception childEx in ((ReflectionTypeLoadException)exception).LoaderExceptions) + foreach (Exception childEx in reflectionTypeLoadEx.LoaderExceptions) summary += $"\n\n{childEx.GetLogSummary()}"; return summary; } diff --git a/src/StardewModdingAPI/Framework/Monitor.cs b/src/StardewModdingAPI/Framework/Monitor.cs index 64075f2f..70dd94c0 100644 --- a/src/StardewModdingAPI/Framework/Monitor.cs +++ b/src/StardewModdingAPI/Framework/Monitor.cs @@ -21,7 +21,7 @@ namespace StardewModdingAPI.Framework private readonly LogFileManager LogFile; /// The maximum length of the values. - private static readonly int MaxLevelLength = (from level in Enumerable.Cast(Enum.GetValues(typeof(LogLevel))) select level.ToString().Length).Max(); + private static readonly int MaxLevelLength = (from level in Enum.GetValues(typeof(LogLevel)).Cast() select level.ToString().Length).Max(); /// The console text color for each log level. private static readonly Dictionary Colors = new Dictionary -- cgit From a35fe4744782f4895b110dc03cfa7cf850af0500 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 19:21:48 -0400 Subject: fix monitor.ExitGameImmediately not working correctly --- release-notes.md | 3 ++- src/StardewModdingAPI/Framework/Monitor.cs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 5c693292..5f2999d1 100644 --- a/release-notes.md +++ b/release-notes.md @@ -15,11 +15,12 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). * SMAPI now rewrites many mods for compatibility with game updates, but some mods will need an update. --> -## 1.9.1 +## 1.10 See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.9.1). For mod developers: * Fixed mouse-changed event never updating prior mouse position. +* Fixed `monitor.ExitGameImmediately` not working correctly. ## 1.9 See [log](https://github.com/Pathoschild/SMAPI/compare/1.8...1.9). diff --git a/src/StardewModdingAPI/Framework/Monitor.cs b/src/StardewModdingAPI/Framework/Monitor.cs index 70dd94c0..76793bbf 100644 --- a/src/StardewModdingAPI/Framework/Monitor.cs +++ b/src/StardewModdingAPI/Framework/Monitor.cs @@ -71,6 +71,7 @@ namespace StardewModdingAPI.Framework this.Source = source; this.LogFile = logFile; this.ConsoleManager = consoleManager; + this.RequestExit = requestExitDelegate; } /// Log a message for the player or developer. @@ -129,6 +130,8 @@ namespace StardewModdingAPI.Framework { if (this.ConsoleManager.SupportsColor) { + if (background.HasValue) + Console.BackgroundColor = background.Value; Console.ForegroundColor = color; Console.WriteLine(message); Console.ResetColor(); -- cgit From 6f43a3dae5795f941819168475fc3bef08ecec70 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 20:27:55 -0400 Subject: unify SMAPI versions for SDV 1.11 and 1.2 using compile switches where needed (#264) --- release-notes.md | 7 +- src/StardewModdingAPI/Constants.cs | 18 +- src/StardewModdingAPI/Framework/ModRegistry.cs | 3 + .../Framework/Models/ModCompatibility.cs | 3 + src/StardewModdingAPI/Framework/SGame.cs | 455 ++++++++++++++++++++- src/StardewModdingAPI/Program.cs | 7 + .../StardewModdingAPI.config.json | 163 ++++---- 7 files changed, 572 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 953ef683..fcad4ccc 100644 --- a/release-notes.md +++ b/release-notes.md @@ -12,11 +12,10 @@ For mod developers: ## 1.10 See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). -* Updated for Stardew Valley 1.2. -* SMAPI now rewrites many mods for compatibility with game updates, but some mods may still need an update. -## 1.10 -See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.9.1). +For players: +* Added support for Stardew Valley 1.2 beta. +* SMAPI now rewrites many mods for compatibility with game updates, but some mods may still need an update. For mod developers: * Fixed mouse-changed event never updating prior mouse position. diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index c4051258..a8121461 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -36,10 +36,20 @@ namespace StardewModdingAPI public static ISemanticVersion ApiVersion { get; } = new SemanticVersion(1, 10, 0); /// The minimum supported version of Stardew Valley. - public static ISemanticVersion MinimumGameVersion { get; } = new SemanticVersion("1.2.15"); + public static ISemanticVersion MinimumGameVersion { get; } = +#if SDV_1_2 + new SemanticVersion("1.2.15"); +#else + new SemanticVersion("1.1"); +#endif /// The maximum supported version of Stardew Valley. - public static ISemanticVersion MaximumGameVersion { get; } = null; + public static ISemanticVersion MaximumGameVersion { get; } = +#if SDV_1_2 + null; +#else + new SemanticVersion("1.1.1"); +#endif /// The path to the game folder. public static string ExecutionPath { get; } = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); @@ -146,8 +156,10 @@ namespace StardewModdingAPI /**** ** Finders throw an exception when incompatible code is found. ****/ +#if SDV_1_2 // changes in Stardew Valley 1.2 (with no rewriters) new FieldFinder("StardewValley.Item", "set_Name"), +#endif // APIs removed in SMAPI 1.9 new TypeFinder("StardewModdingAPI.Advanced.ConfigFile"), @@ -172,6 +184,7 @@ namespace StardewModdingAPI // crossplatform new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchWrapper), onlyIfPlatformChanged: true), +#if SDV_1_2 // Stardew Valley 1.2 new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.activeClickableMenu)), new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.currentMinigame)), @@ -179,6 +192,7 @@ namespace StardewModdingAPI new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.player)), new FieldReplaceRewriter(typeof(Game1), "borderFont", nameof(Game1.smallFont)), new FieldReplaceRewriter(typeof(Game1), "smoothFont", nameof(Game1.smallFont)), +#endif // SMAPI 1.9 new TypeReferenceRewriter("StardewModdingAPI.Inheritance.ItemStackChange", typeof(ItemStackChange)) diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs index f015b7ba..8ea3502b 100644 --- a/src/StardewModdingAPI/Framework/ModRegistry.cs +++ b/src/StardewModdingAPI/Framework/ModRegistry.cs @@ -138,6 +138,9 @@ namespace StardewModdingAPI.Framework mod.ID == key && (mod.LowerSemanticVersion == null || !manifest.Version.IsOlderThan(mod.LowerSemanticVersion)) && !manifest.Version.IsNewerThan(mod.UpperSemanticVersion) +#if !SDV_1_2 + && !mod.OnlyStardewValleyBeta +#endif select mod ).FirstOrDefault(); } diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs index 1e71dae0..e1ee8135 100644 --- a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs @@ -37,6 +37,9 @@ namespace StardewModdingAPI.Framework.Models /// Indicates how SMAPI should consider the mod. public ModCompatibilityType Compatibility { get; set; } + /// Whether this record only applies to the Stardew Valley 1.2 beta. + public bool OnlyStardewValleyBeta { get; set; } + /**** ** Injected diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index b262d4dd..99b9f991 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -1,10 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Threading.Tasks; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -16,8 +14,14 @@ using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Tools; using xTile.Dimensions; -using xTile.Layers; using SFarmer = StardewValley.Farmer; +#if SDV_1_2 +using System.Diagnostics; +using System.Threading.Tasks; +using xTile.Layers; +#else +using Rectangle = Microsoft.Xna.Framework.Rectangle; +#endif namespace StardewModdingAPI.Framework { @@ -136,8 +140,10 @@ namespace StardewModdingAPI.Framework /// The player character at last check. private SFarmer PreviousFarmer; +#if SDV_1_2 /// The previous content locale. private LocalizedContentManager.LanguageCode? PreviousLocale; +#endif /// An index incremented on every tick and reset every 60th tick (0–59). private int CurrentUpdateTick; @@ -154,6 +160,7 @@ namespace StardewModdingAPI.Framework // ReSharper disable ArrangeStaticMemberQualifier, ArrangeThisQualifier, InconsistentNaming /// Used to access private fields and methods. private static readonly IReflectionHelper Reflection = new ReflectionHelper(); +#if SDV_1_2 private static List _fpsList => SGame.Reflection.GetPrivateField>(typeof(Game1), nameof(_fpsList)).GetValue(); private static Stopwatch _fpsStopwatch => SGame.Reflection.GetPrivateField(typeof(Game1), nameof(SGame._fpsStopwatch)).GetValue(); private static float _fps @@ -161,13 +168,21 @@ namespace StardewModdingAPI.Framework set { SGame.Reflection.GetPrivateField(typeof(Game1), nameof(_fps)).SetValue(value); } } private static Task _newDayTask => SGame.Reflection.GetPrivateField(typeof(Game1), nameof(_newDayTask)).GetValue(); +#endif private Color bgColor => SGame.Reflection.GetPrivateField(this, nameof(bgColor)).GetValue(); - public RenderTarget2D screenWrapper => SGame.Reflection.GetPrivateProperty(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop + public RenderTarget2D screenWrapper => +#if SDV_1_2 + SGame.Reflection.GetPrivateProperty(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop +#else + SGame.Reflection.GetPrivateField(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop +#endif public BlendState lightingBlend => SGame.Reflection.GetPrivateField(this, nameof(lightingBlend)).GetValue(); private readonly Action drawFarmBuildings = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawFarmBuildings)).Invoke(new object[0]); private readonly Action drawHUD = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawHUD)).Invoke(new object[0]); private readonly Action drawDialogueBox = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawDialogueBox)).Invoke(new object[0]); +#if SDV_1_2 private readonly Action renderScreenBuffer = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(renderScreenBuffer)).Invoke(new object[0]); +#endif // ReSharper restore ArrangeStaticMemberQualifier, ArrangeThisQualifier, InconsistentNaming @@ -186,6 +201,7 @@ namespace StardewModdingAPI.Framework /**** ** Intercepted methods & events ****/ +#if SDV_1_2 /// Constructor a content manager to read XNB files. /// The service provider to use to locate services. /// The root directory to search for content. @@ -193,11 +209,13 @@ namespace StardewModdingAPI.Framework { return new SContentManager(this.Content.ServiceProvider, this.Content.RootDirectory, this.Monitor); } +#endif /// The method called when the game is updating its state. This happens roughly 60 times per second. /// A snapshot of the game timing state. protected override void Update(GameTime gameTime) { +#if SDV_1_2 // While a background new-day task is in progress, the game skips its own update logic // and defers to the XNA Update method. Running mod code in parallel to the background // update is risky, because data changes can conflict (e.g. collection changed during @@ -213,6 +231,7 @@ namespace StardewModdingAPI.Framework base.Update(gameTime); return; } +#endif // raise game loaded if (this.FirstUpdate) @@ -277,6 +296,7 @@ namespace StardewModdingAPI.Framework [SuppressMessage("ReSharper", "RedundantCast", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantExplicitNullableCreation", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantTypeArgumentsOfMethod", Justification = "copied from game code as-is")] +#if SDV_1_2 protected override void Draw(GameTime gameTime) { try @@ -931,6 +951,425 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"An error occured in the overridden draw loop: {ex.GetLogSummary()}", LogLevel.Error); } } +#else + protected override void Draw(GameTime gameTime) + { + try + { + if (!this.ZoomLevelIsOne) + this.GraphicsDevice.SetRenderTarget(this.screenWrapper); + + this.GraphicsDevice.Clear(this.bgColor); + if (Game1.options.showMenuBackground && Game1.activeClickableMenu != null && Game1.activeClickableMenu.showWithoutTransparencyIfOptionIsSet()) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + try + { + Game1.activeClickableMenu.drawBackground(Game1.spriteBatch); + } + catch (Exception ex) + { + this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing its background. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + Game1.activeClickableMenu.exitThisMenu(); + } + GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); + try + { + Game1.activeClickableMenu.draw(Game1.spriteBatch); + } + catch (Exception ex) + { + this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + Game1.activeClickableMenu.exitThisMenu(); + } + GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); + Game1.spriteBatch.End(); + if (!this.ZoomLevelIsOne) + { + this.GraphicsDevice.SetRenderTarget(null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + return; + } + if (Game1.gameMode == 11) + { + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + Game1.spriteBatch.DrawString(Game1.smoothFont, "Stardew Valley has crashed...", new Vector2(16f, 16f), Color.HotPink); + Game1.spriteBatch.DrawString(Game1.smoothFont, "Please send the error report or a screenshot of this message to @ConcernedApe. (http://stardewvalley.net/contact/)", new Vector2(16f, 32f), new Color(0, 255, 0)); + Game1.spriteBatch.DrawString(Game1.smoothFont, Game1.parseText(Game1.errorMessage, Game1.smoothFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); + Game1.spriteBatch.End(); + return; + } + if (Game1.currentMinigame != null) + { + Game1.currentMinigame.draw(Game1.spriteBatch); + if (Game1.globalFade && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha)); + Game1.spriteBatch.End(); + } + if (!this.ZoomLevelIsOne) + { + this.GraphicsDevice.SetRenderTarget(null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + return; + } + if (Game1.showingEndOfNightStuff) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + try + { + Game1.activeClickableMenu?.draw(Game1.spriteBatch); + } + catch (Exception ex) + { + this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + Game1.activeClickableMenu.exitThisMenu(); + } + Game1.spriteBatch.End(); + if (!this.ZoomLevelIsOne) + { + this.GraphicsDevice.SetRenderTarget(null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + return; + } + if (Game1.gameMode == 6) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + string text = ""; + int num = 0; + while (num < gameTime.TotalGameTime.TotalMilliseconds % 999.0 / 333.0) + { + text += "."; + num++; + } + SpriteText.drawString(Game1.spriteBatch, "Loading" + text, 64, Game1.graphics.GraphicsDevice.Viewport.Height - 64, 999, -1, 999, 1f, 1f, false, 0, "Loading..."); + Game1.spriteBatch.End(); + if (!this.ZoomLevelIsOne) + { + this.GraphicsDevice.SetRenderTarget(null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + return; + } + if (Game1.gameMode == 0) + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + else + { + if (Game1.drawLighting) + { + this.GraphicsDevice.SetRenderTarget(Game1.lightmap); + this.GraphicsDevice.Clear(Color.White * 0f); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null); + Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, Game1.currentLocation.name.Equals("UndergroundMine") ? Game1.mine.getLightingColor(gameTime) : ((!Game1.ambientLight.Equals(Color.White) && (!Game1.isRaining || !Game1.currentLocation.isOutdoors)) ? Game1.ambientLight : Game1.outdoorLight)); + for (int i = 0; i < Game1.currentLightSources.Count; i++) + { + if (Utility.isOnScreen(Game1.currentLightSources.ElementAt(i).position, (int)(Game1.currentLightSources.ElementAt(i).radius * Game1.tileSize * 4f))) + Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(i).lightTexture, Game1.GlobalToLocal(Game1.viewport, Game1.currentLightSources.ElementAt(i).position) / Game1.options.lightingQuality, Game1.currentLightSources.ElementAt(i).lightTexture.Bounds, Game1.currentLightSources.ElementAt(i).color, 0f, new Vector2(Game1.currentLightSources.ElementAt(i).lightTexture.Bounds.Center.X, Game1.currentLightSources.ElementAt(i).lightTexture.Bounds.Center.Y), Game1.currentLightSources.ElementAt(i).radius / Game1.options.lightingQuality, SpriteEffects.None, 0.9f); + } + Game1.spriteBatch.End(); + this.GraphicsDevice.SetRenderTarget(this.ZoomLevelIsOne ? null : this.screenWrapper); + } + if (Game1.bloomDay) + Game1.bloom?.BeginDraw(); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + GraphicsEvents.InvokeOnPreRenderEvent(this.Monitor); + Game1.background?.draw(Game1.spriteBatch); + Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); + Game1.currentLocation.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.currentLocation.drawWater(Game1.spriteBatch); + if (Game1.CurrentEvent == null) + { + using (List.Enumerator enumerator = Game1.currentLocation.characters.GetEnumerator()) + { + while (enumerator.MoveNext()) + { + NPC current = enumerator.Current; + if (current != null && !current.swimming && !current.hideShadow && !current.IsMonster && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current.getTileLocation())) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current.position + new Vector2(current.sprite.spriteWidth * Game1.pixelZoom / 2f, current.GetBoundingBox().Height + (current.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current.yJumpOffset / 40f) * current.scale, SpriteEffects.None, Math.Max(0f, current.getStandingY() / 10000f) - 1E-06f); + } + goto IL_B30; + } + } + foreach (NPC current2 in Game1.CurrentEvent.actors) + { + if (!current2.swimming && !current2.hideShadow && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current2.getTileLocation())) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current2.position + new Vector2(current2.sprite.spriteWidth * Game1.pixelZoom / 2f, current2.GetBoundingBox().Height + (current2.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current2.yJumpOffset / 40f) * current2.scale, SpriteEffects.None, Math.Max(0f, current2.getStandingY() / 10000f) - 1E-06f); + } + IL_B30: + if (!Game1.player.swimming && !Game1.player.isRidingHorse() && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation())) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((Game1.player.running || Game1.player.usingTool) && Game1.player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, 0f); + Game1.currentLocation.Map.GetLayer("Buildings").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.mapDisplayDevice.EndScene(); + Game1.spriteBatch.End(); + Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (Game1.CurrentEvent == null) + { + using (List.Enumerator enumerator3 = Game1.currentLocation.characters.GetEnumerator()) + { + while (enumerator3.MoveNext()) + { + NPC current3 = enumerator3.Current; + if (current3 != null && !current3.swimming && !current3.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current3.getTileLocation())) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current3.position + new Vector2(current3.sprite.spriteWidth * Game1.pixelZoom / 2f, current3.GetBoundingBox().Height + (current3.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current3.yJumpOffset / 40f) * current3.scale, SpriteEffects.None, Math.Max(0f, current3.getStandingY() / 10000f) - 1E-06f); + } + goto IL_F5F; + } + } + foreach (NPC current4 in Game1.CurrentEvent.actors) + { + if (!current4.swimming && !current4.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current4.getTileLocation())) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current4.position + new Vector2(current4.sprite.spriteWidth * Game1.pixelZoom / 2f, current4.GetBoundingBox().Height + (current4.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current4.yJumpOffset / 40f) * current4.scale, SpriteEffects.None, Math.Max(0f, current4.getStandingY() / 10000f) - 1E-06f); + } + IL_F5F: + if (!Game1.player.swimming && !Game1.player.isRidingHorse() && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation())) + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((Game1.player.running || Game1.player.usingTool) && Game1.player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, Math.Max(0.0001f, Game1.player.getStandingY() / 10000f + 0.00011f) - 0.0001f); + if (Game1.displayFarmer) + Game1.player.draw(Game1.spriteBatch); + if ((Game1.eventUp || Game1.killScreen) && !Game1.killScreen) + Game1.currentLocation.currentEvent?.draw(Game1.spriteBatch); + if (Game1.player.currentUpgrade != null && Game1.player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && Game1.currentLocation.Name.Equals("Farm")) + Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), Game1.player.currentUpgrade.getSourceRectangle(), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, (Game1.player.currentUpgrade.positionOfCarpenter.Y + Game1.tileSize * 3 / 4) / 10000f); + Game1.currentLocation.draw(Game1.spriteBatch); + if (Game1.eventUp && Game1.currentLocation.currentEvent?.messageToScreen != null) + Game1.drawWithBorder(Game1.currentLocation.currentEvent.messageToScreen, Color.Black, Color.White, new Vector2(Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width / 2 - Game1.borderFont.MeasureString(Game1.currentLocation.currentEvent.messageToScreen).X / 2f, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Height - Game1.tileSize), 0f, 1f, 0.999f); + if (Game1.player.ActiveObject == null && (Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && (!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool)) + Game1.drawTool(Game1.player); + if (Game1.currentLocation.Name.Equals("Farm")) + this.drawFarmBuildings(); + if (Game1.tvStation >= 0) + Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(6 * Game1.tileSize + Game1.tileSize / 4, 2 * Game1.tileSize + Game1.tileSize / 2)), new Rectangle(Game1.tvStation * 24, 0, 24, 15), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f); + if (Game1.panMode) + { + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle((int)Math.Floor((Game1.getOldMouseX() + Game1.viewport.X) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.X, (int)Math.Floor((Game1.getOldMouseY() + Game1.viewport.Y) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Lime * 0.75f); + foreach (Warp current5 in Game1.currentLocation.warps) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle(current5.X * Game1.tileSize - Game1.viewport.X, current5.Y * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Red * 0.75f); + } + Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); + Game1.currentLocation.Map.GetLayer("Front").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.mapDisplayDevice.EndScene(); + Game1.currentLocation.drawAboveFrontLayer(Game1.spriteBatch); + Game1.spriteBatch.End(); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (Game1.currentLocation.Name.Equals("Farm") && Game1.stats.SeedsSown >= 200u) + { + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(3 * Game1.tileSize + Game1.tileSize / 4, Game1.tileSize + Game1.tileSize / 3)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize + Game1.tileSize, 2 * Game1.tileSize + Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(5 * Game1.tileSize, 2 * Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(3 * Game1.tileSize + Game1.tileSize / 2, 3 * Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(5 * Game1.tileSize - Game1.tileSize / 4, Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize, 3 * Game1.tileSize + Game1.tileSize / 6)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); + Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize + Game1.tileSize / 5, 2 * Game1.tileSize + Game1.tileSize / 3)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); + } + if (Game1.displayFarmer && Game1.player.ActiveObject != null && Game1.player.ActiveObject.bigCraftable && this.checkBigCraftableBoundariesForFrontLayer() && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) + Game1.drawPlayerHeldObject(Game1.player); + else if (Game1.displayFarmer && Game1.player.ActiveObject != null && ((Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")) || (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")))) + Game1.drawPlayerHeldObject(Game1.player); + if ((Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && (!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool) && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) + Game1.drawTool(Game1.player); + if (Game1.currentLocation.Map.GetLayer("AlwaysFront") != null) + { + Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); + Game1.currentLocation.Map.GetLayer("AlwaysFront").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); + Game1.mapDisplayDevice.EndScene(); + } + if (Game1.toolHold > 400f && Game1.player.CurrentTool.UpgradeLevel >= 1 && Game1.player.canReleaseTool) + { + Color color = Color.White; + switch ((int)(Game1.toolHold / 600f) + 2) + { + case 1: + color = Tool.copperColor; + break; + case 2: + color = Tool.steelColor; + break; + case 3: + color = Tool.goldColor; + break; + case 4: + color = Tool.iridiumColor; + break; + } + Game1.spriteBatch.Draw(Game1.littleEffect, new Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize) - 2, (int)(Game1.toolHold % 600f * 0.08f) + 4, Game1.tileSize / 8 + 4), Color.Black); + Game1.spriteBatch.Draw(Game1.littleEffect, new Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize), (int)(Game1.toolHold % 600f * 0.08f), Game1.tileSize / 8), color); + } + if (Game1.isDebrisWeather && Game1.currentLocation.IsOutdoors && !Game1.currentLocation.ignoreDebrisWeather && !Game1.currentLocation.Name.Equals("Desert") && Game1.viewport.X > -10) + { + foreach (WeatherDebris current6 in Game1.debrisWeather) + current6.draw(Game1.spriteBatch); + } + Game1.farmEvent?.draw(Game1.spriteBatch); + if (Game1.currentLocation.LightLevel > 0f && Game1.timeOfDay < 2000) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * Game1.currentLocation.LightLevel); + if (Game1.screenGlow) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Game1.screenGlowColor * Game1.screenGlowAlpha); + Game1.currentLocation.drawAboveAlwaysFrontLayer(Game1.spriteBatch); + if (Game1.player.CurrentTool is FishingRod && ((Game1.player.CurrentTool as FishingRod).isTimingCast || (Game1.player.CurrentTool as FishingRod).castingChosenCountdown > 0f || (Game1.player.CurrentTool as FishingRod).fishCaught || (Game1.player.CurrentTool as FishingRod).showingTreasure)) + Game1.player.CurrentTool.draw(Game1.spriteBatch); + if (Game1.isRaining && Game1.currentLocation.IsOutdoors && !Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit) && (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2(Game1.viewport.X / Game1.tileSize, Game1.viewport.Y / Game1.tileSize)))) + { + for (int j = 0; j < Game1.rainDrops.Length; j++) + Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[j].position, Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[j].frame), Color.White); + } + + Game1.spriteBatch.End(); + + //base.Draw(gameTime); + + Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (Game1.eventUp && Game1.currentLocation.currentEvent != null) + { + foreach (NPC current7 in Game1.currentLocation.currentEvent.actors) + { + if (current7.isEmoting) + { + Vector2 localPosition = current7.getLocalPosition(Game1.viewport); + localPosition.Y -= Game1.tileSize * 2 + Game1.pixelZoom * 3; + if (current7.age == 2) + localPosition.Y += Game1.tileSize / 2; + else if (current7.gender == 1) + localPosition.Y += Game1.tileSize / 6; + Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, localPosition, new Rectangle(current7.CurrentEmoteIndex * (Game1.tileSize / 4) % Game1.emoteSpriteSheet.Width, current7.CurrentEmoteIndex * (Game1.tileSize / 4) / Game1.emoteSpriteSheet.Width * (Game1.tileSize / 4), Game1.tileSize / 4, Game1.tileSize / 4), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, current7.getStandingY() / 10000f); + } + } + } + Game1.spriteBatch.End(); + if (Game1.drawLighting) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, new BlendState + { + ColorBlendFunction = BlendFunction.ReverseSubtract, + ColorDestinationBlend = Blend.One, + ColorSourceBlend = Blend.SourceColor + }, SamplerState.LinearClamp, null, null); + Game1.spriteBatch.Draw(Game1.lightmap, Vector2.Zero, Game1.lightmap.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.lightingQuality, SpriteEffects.None, 1f); + if (Game1.isRaining && Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert)) + { + Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.OrangeRed * 0.45f); + } + Game1.spriteBatch.End(); + } + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + if (Game1.drawGrid) + { + int num2 = -Game1.viewport.X % Game1.tileSize; + float num3 = -(float)Game1.viewport.Y % Game1.tileSize; + for (int k = num2; k < Game1.graphics.GraphicsDevice.Viewport.Width; k += Game1.tileSize) + Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(k, (int)num3, 1, Game1.graphics.GraphicsDevice.Viewport.Height), Color.Red * 0.5f); + for (float num4 = num3; num4 < (float)Game1.graphics.GraphicsDevice.Viewport.Height; num4 += (float)Game1.tileSize) + Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(num2, (int)num4, Game1.graphics.GraphicsDevice.Viewport.Width, 1), Color.Red * 0.5f); + } + if (Game1.currentBillboard != 0) + this.drawBillboard(); + + if ((Game1.displayHUD || Game1.eventUp) && Game1.currentBillboard == 0 && Game1.gameMode == 3 && !Game1.freezeControls && !Game1.panMode) + { + GraphicsEvents.InvokeOnPreRenderHudEvent(this.Monitor); + this.drawHUD(); + GraphicsEvents.InvokeOnPostRenderHudEvent(this.Monitor); + } + else if (Game1.activeClickableMenu == null && Game1.farmEvent == null) + Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2(Game1.getOldMouseX(), Game1.getOldMouseY()), Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16), Color.White, 0f, Vector2.Zero, 4f + Game1.dialogueButtonScale / 150f, SpriteEffects.None, 1f); + + if (Game1.hudMessages.Any() && (!Game1.eventUp || Game1.isFestival())) + { + for (int l = Game1.hudMessages.Count - 1; l >= 0; l--) + Game1.hudMessages[l].draw(Game1.spriteBatch, l); + } + } + Game1.farmEvent?.draw(Game1.spriteBatch); + if (Game1.dialogueUp && !Game1.nameSelectUp && !Game1.messagePause && !(Game1.activeClickableMenu is DialogueBox)) + this.drawDialogueBox(); + if (Game1.progressBar) + { + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle((Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - Game1.tileSize * 2, Game1.dialogueWidth, Game1.tileSize / 2), Color.LightGray); + Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle((Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - Game1.tileSize * 2, (int)(Game1.pauseAccumulator / Game1.pauseTime * Game1.dialogueWidth), Game1.tileSize / 2), Color.DimGray); + } + if (Game1.eventUp) + Game1.currentLocation.currentEvent?.drawAfterMap(Game1.spriteBatch); + if (Game1.isRaining && Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert)) + Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Blue * 0.2f); + if ((Game1.fadeToBlack || Game1.globalFade) && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha)); + else if (Game1.flashAlpha > 0f) + { + if (Game1.options.screenFlash) + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.White * Math.Min(1f, Game1.flashAlpha)); + Game1.flashAlpha -= 0.1f; + } + if ((Game1.messagePause || Game1.globalFade) && Game1.dialogueUp) + this.drawDialogueBox(); + foreach (TemporaryAnimatedSprite current8 in Game1.screenOverlayTempSprites) + current8.draw(Game1.spriteBatch, true); + if (Game1.debugMode) + { + Game1.spriteBatch.DrawString(Game1.smallFont, string.Concat(new object[] + { + Game1.panMode ? ((Game1.getOldMouseX() + Game1.viewport.X) / Game1.tileSize + "," + (Game1.getOldMouseY() + Game1.viewport.Y) / Game1.tileSize) : string.Concat("aplayer: ", Game1.player.getStandingX() / Game1.tileSize, ", ", Game1.player.getStandingY() / Game1.tileSize), + Environment.NewLine, + "debugOutput: ", + Game1.debugOutput + }), new Vector2(this.GraphicsDevice.Viewport.TitleSafeArea.X, this.GraphicsDevice.Viewport.TitleSafeArea.Y), Color.Red, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + } + /*if (inputMode) + { + spriteBatch.DrawString(smallFont, "Input: " + debugInput, new Vector2(tileSize, tileSize * 3), Color.Purple); + }*/ + if (Game1.showKeyHelp) + Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(Game1.tileSize, Game1.viewport.Height - Game1.tileSize - (Game1.dialogueUp ? (Game1.tileSize * 3 + (Game1.isQuestion ? (Game1.questionChoices.Count * Game1.tileSize) : 0)) : 0) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Color.LightGray, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + + if (Game1.activeClickableMenu != null) + { + GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); + try + { + Game1.activeClickableMenu.draw(Game1.spriteBatch); + } + catch (Exception ex) + { + this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); + Game1.activeClickableMenu.exitThisMenu(); + } + GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); + } + else + Game1.farmEvent?.drawAboveEverything(Game1.spriteBatch); + + GraphicsEvents.InvokeOnPostRenderEvent(this.Monitor); + Game1.spriteBatch.End(); + + if (!this.ZoomLevelIsOne) + { + this.GraphicsDevice.SetRenderTarget(null); + this.GraphicsDevice.Clear(this.bgColor); + Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); + Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.End(); + } + } + catch (Exception ex) + { + this.Monitor.Log($"An error occured in the overridden draw loop: {ex.GetLogSummary()}", LogLevel.Error); + } + } +#endif /**** ** Methods @@ -1061,6 +1500,7 @@ namespace StardewModdingAPI.Framework /// Detect changes since the last update ticket and trigger mod events. private void UpdateEventCalls() { +#if SDV_1_2 // content locale changed event if (this.PreviousLocale != LocalizedContentManager.CurrentLanguageCode) { @@ -1071,9 +1511,14 @@ namespace StardewModdingAPI.Framework ContentEvents.InvokeAfterLocaleChanged(this.Monitor, oldValue.ToString(), newValue.ToString()); this.PreviousLocale = newValue; } +#endif // save loaded event - if (Constants.IsSaveLoaded && !SaveGame.IsProcessing/*still loading save*/ && this.AfterLoadTimer >= 0) + if (Constants.IsSaveLoaded +#if SDV_1_2 + && !SaveGame.IsProcessing/*still loading save*/ +#endif + && this.AfterLoadTimer >= 0) { if (this.AfterLoadTimer == 0) { diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 62961021..00b5709f 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -247,7 +247,14 @@ namespace StardewModdingAPI this.GameInstance.Exiting += (sender, e) => this.IsGameRunning = false; this.GameInstance.Window.ClientSizeChanged += (sender, e) => GraphicsEvents.InvokeResize(this.Monitor, sender, e); this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} with SMAPI {Constants.ApiVersion}"; +#if SDV_1_2 StardewValley.Program.gamePtr = this.GameInstance; +#else + { + Type type = typeof(Game1).Assembly.GetType("StardewValley.Program", true); + type.GetField("gamePtr").SetValue(null, this.GameInstance); + } +#endif // configure Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json index 9438c621..ba698d35 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.config.json +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -27,6 +27,10 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha * Changing this field is not recommended and may destabilise your game. */ "ModCompatibility": [ + + /**** + ** Stardew Valley 1.2+ only + ****/ { "Name": "AccessChestAnywhere", "ID": "AccessChestAnywhere", @@ -34,9 +38,94 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/257", "UnofficialUpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." + "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "Chests Anywhere", + "ID": "ChestsAnywhere", + "UpperVersion": "1.8.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "Notes": "Crashes with 'Method not found: Void StardewValley.Menus.TextBox.set_Highlighted(Boolean)'.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "Chests Anywhere", + "ID": "Pathoschild.ChestsAnywhere", + "UpperVersion": "1.9-beta", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "Notes": "ID changed in 1.9. Crashes with InvalidOperationException: 'The menu doesn't seem to have a player inventory'.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "CJB Automation", + "ID": "CJBAutomation", + "UpperVersion": "1.4", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/211", + "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "Cooking Skill", + "ID": "CookingSkill", + "UpperVersion": "1.0.3", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/522", + "Notes": "Crashes with 'Method not found: Void StardewValley.Buff..ctor(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, System.String)'.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "Extended Fridge", + "ID": "Mystra007ExtendedFridge", + "UpperVersion": "1.0", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/485", + "Notes": "Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest. Crashes with 'Field not found: StardewValley.Game1.mouseCursorTransparency'.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "Get Dressed", + "ID": "GetDressed.dll", + "UpperVersion": "3.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/331", + "Notes": "Crashes with NullReferenceException in GameEvents.UpdateTick.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "Lookup Anything", + "ID": "LookupAnything", + "UpperVersion": "1.10", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", + "Notes": "Crashes with FormatException when looking up NPCs.", + "OnlyStardewValleyBeta": true + }, + { + "Name": "Lookup Anything", + "ID": "Pathoschild.LookupAnything", + "UpperVersion": "1.10.1", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", + "Notes": "ID changed in 1.10.1. Crashes with FormatException when looking up NPCs.", + "OnlyStardewValleyBeta": true }, { + "Name": "Teleporter", + "ID": "Teleporter", + "UpperVersion": "1.0.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/resources/4374", + "Notes": "Crashes with 'InvalidOperationException: The StardewValley.Menus.MapPage object doesn't have a private 'points' instance field'.", + "OnlyStardewValleyBeta": true + }, + + /**** + ** Any version of Stardew Valley + ****/ { "Name": "Almighty Tool", "ID": "AlmightyTool.dll", "UpperVersion": "1.1.1", @@ -68,30 +157,6 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/242", "Notes": "Not compatible with Stardew Valley 1.1+" }, - { - "Name": "Chests Anywhere", - "ID": "ChestsAnywhere", - "UpperVersion": "1.8.2", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "Crashes with 'Method not found: Void StardewValley.Menus.TextBox.set_Highlighted(Boolean)'." - }, - { - "Name": "Chests Anywhere", - "ID": "Pathoschild.ChestsAnywhere", - "UpperVersion": "1.9-beta", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "ID changed in 1.9. Crashes with InvalidOperationException: 'The menu doesn't seem to have a player inventory'." - }, - { - "Name": "CJB Automation", - "ID": "CJBAutomation", - "UpperVersion": "1.4", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/211", - "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." - }, { "Name": "CJB Cheats Menu", "ID": "CJBCheatsMenu", @@ -114,14 +179,6 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", "Notes": "Uses SMAPI's internal SGame class." }, - { - "Name": "Cooking Skill", - "ID": "CookingSkill", - "UpperVersion": "1.0.3", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/522", - "Notes": "Crashes with 'Method not found: Void StardewValley.Buff..ctor(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, System.String)'." - }, { "Name": "Enemy Health Bars", "ID": "SPDHealthBar", @@ -138,38 +195,6 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://community.playstarbound.com/resources/4228", "Notes": "Uses obsolete StardewModdingAPI.Inheritance.SObject until 1.6.1; then crashes until 1.6.4 ('Entoarox Framework requested an immediate game shutdown: Fatal error attempting to update player tick properties System.NullReferenceException: Object reference not set to an instance of an object. at Entoarox.Framework.PlayerHelper.Update(Object s, EventArgs e)')." }, - { - "Name": "Extended Fridge", - "ID": "Mystra007ExtendedFridge", - "UpperVersion": "1.0", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/485", - "Notes": "Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest. Crashes with 'Field not found: StardewValley.Game1.mouseCursorTransparency'." - }, - { - "Name": "Get Dressed", - "ID": "GetDressed.dll", - "UpperVersion": "3.2", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/331", - "Notes": "Crashes with NullReferenceException in GameEvents.UpdateTick." - }, - { - "Name": "Lookup Anything", - "ID": "LookupAnything", - "UpperVersion": "1.10", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", - "Notes": "Crashes with FormatException when looking up NPCs." - }, - { - "Name": "Lookup Anything", - "ID": "Pathoschild.LookupAnything", - "UpperVersion": "1.10.1", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", - "Notes": "ID changed in 1.10.1. Crashes with FormatException when looking up NPCs." - }, { "Name": "Makeshift Multiplayer", "ID": "StardewValleyMP", @@ -227,14 +252,6 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/683", "Notes": "Crashes with 'Method not found: Void StardewModdingAPI.Command.CallCommand(System.String)'." }, - { - "Name": "Teleporter", - "ID": "Teleporter", - "UpperVersion": "1.0.2", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/4374", - "Notes": "Crashes with 'InvalidOperationException: The StardewValley.Menus.MapPage object doesn't have a private 'points' instance field'." - }, { "Name": "Zoryn's Better RNG", "ID": "76b6d1e1-f7ba-4d72-8c32-5a1e6d2716f6", -- cgit From 5f595d8a464174bf8ec6940476cf6e05014e17b4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 20:34:47 -0400 Subject: let mods specify a minimum game version in their manifest.json (#264) --- release-notes.md | 1 + src/StardewModdingAPI/Framework/Manifest.cs | 3 +++ src/StardewModdingAPI/IManifest.cs | 3 +++ src/StardewModdingAPI/Program.cs | 19 +++++++++++++++++++ 4 files changed, 26 insertions(+) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index fcad4ccc..2f1dffd2 100644 --- a/release-notes.md +++ b/release-notes.md @@ -20,6 +20,7 @@ For players: For mod developers: * Fixed mouse-changed event never updating prior mouse position. * Fixed `monitor.ExitGameImmediately` not working correctly. +* Mods can now specify a minimum game version in their `manifest.json`. ## 1.9 See [log](https://github.com/Pathoschild/SMAPI/compare/1.8...1.9). diff --git a/src/StardewModdingAPI/Framework/Manifest.cs b/src/StardewModdingAPI/Framework/Manifest.cs index 189da9a8..f9c90ff6 100644 --- a/src/StardewModdingAPI/Framework/Manifest.cs +++ b/src/StardewModdingAPI/Framework/Manifest.cs @@ -26,6 +26,9 @@ namespace StardewModdingAPI.Framework /// The minimum SMAPI version required by this mod, if any. public string MinimumApiVersion { get; set; } + /// The minimum game version required by this mod, if any. + public string MinimumGameVersion { get; set; } + /// The name of the DLL in the directory that has the method. public string EntryDll { get; set; } diff --git a/src/StardewModdingAPI/IManifest.cs b/src/StardewModdingAPI/IManifest.cs index 3e4b7513..f73b0c8f 100644 --- a/src/StardewModdingAPI/IManifest.cs +++ b/src/StardewModdingAPI/IManifest.cs @@ -18,6 +18,9 @@ /// The minimum SMAPI version required by this mod, if any. string MinimumApiVersion { get; set; } + /// The minimum game version required by this mod, if any. + string MinimumGameVersion { get; set; } + /// The unique mod ID. string UniqueID { get; set; } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 00b5709f..678fa90d 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -436,6 +436,25 @@ namespace StardewModdingAPI } } + // validate game version + if (!string.IsNullOrWhiteSpace(manifest.MinimumGameVersion)) + { + try + { + ISemanticVersion minVersion = new SemanticVersion(manifest.MinimumGameVersion); + if (minVersion.IsNewerThan(Constants.GameVersion)) + { + this.Monitor.Log($"{skippedPrefix} because it needs Stardew Valley {minVersion} or later. Please update Stardew Valley to the latest version to use this mod.", LogLevel.Error); + continue; + } + } + catch (FormatException ex) when (ex.Message.Contains("not a valid semantic version")) + { + this.Monitor.Log($"{skippedPrefix} because it has an invalid minimum game version '{manifest.MinimumApiVersion}'. This should be a semantic version number like {Constants.GameVersion}.", LogLevel.Error); + continue; + } + } + // create per-save directory if (manifest.PerSaveConfigs) { -- cgit From 86ef70feece302f21041204b3baa31d757730acc Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 21:51:49 -0400 Subject: revamp startup process (#265) This revamps SMAPI's startup process to simplify mod development by ensuring that core components are ready by the time mods are loaded (which is also needed for the upcoming content API), and eliminate or reduce SEHExceptions some players experience. --- release-notes.md | 4 +- src/StardewModdingAPI/Events/GameEvents.cs | 12 +- src/StardewModdingAPI/Framework/SGame.cs | 2 + src/StardewModdingAPI/Program.cs | 356 ++++++++++++++--------------- 4 files changed, 189 insertions(+), 185 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 2f1dffd2..e6ddb3db 100644 --- a/release-notes.md +++ b/release-notes.md @@ -15,12 +15,14 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). For players: * Added support for Stardew Valley 1.2 beta. -* SMAPI now rewrites many mods for compatibility with game updates, but some mods may still need an update. +* Added logic to rewrite many mods for compatibility with game updates, though some mods may still need an update. +* Fixed some players getting `SEHException` errors. For mod developers: * Fixed mouse-changed event never updating prior mouse position. * Fixed `monitor.ExitGameImmediately` not working correctly. * Mods can now specify a minimum game version in their `manifest.json`. +* Mods are now initialised after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method. ## 1.9 See [log](https://github.com/Pathoschild/SMAPI/compare/1.8...1.9). diff --git a/src/StardewModdingAPI/Events/GameEvents.cs b/src/StardewModdingAPI/Events/GameEvents.cs index 47c1275b..babf7f31 100644 --- a/src/StardewModdingAPI/Events/GameEvents.cs +++ b/src/StardewModdingAPI/Events/GameEvents.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using StardewModdingAPI.Framework; namespace StardewModdingAPI.Events @@ -16,7 +17,10 @@ namespace StardewModdingAPI.Events /********* ** Events *********/ - /// Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called during . + /// Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called after . + internal static event EventHandler InitializeInternal; + + /// Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called after . [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(Initialize) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] public static event EventHandler Initialize; @@ -66,12 +70,14 @@ namespace StardewModdingAPI.Events /// Encapsulates logging and monitoring. internal static void InvokeInitialize(IMonitor monitor) { + // notify SMAPI + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.InitializeInternal)}", GameEvents.InitializeInternal?.GetInvocationList()); + + // notify mods if (GameEvents.Initialize == null) return; - string name = $"{nameof(GameEvents)}.{nameof(GameEvents.Initialize)}"; Delegate[] handlers = GameEvents.Initialize.GetInvocationList(); - GameEvents.DeprecationManager.WarnForEvent(handlers, name, "1.10", DeprecationLevel.Info); monitor.SafelyRaisePlainEvent(name, handlers); } diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 99b9f991..39cc5cde 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -196,6 +196,8 @@ namespace StardewModdingAPI.Framework this.Monitor = monitor; this.FirstUpdate = true; SGame.Instance = this; + + Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; // required by Stardew Valley } /**** diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 678fa90d..3bd91a7c 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -10,7 +9,6 @@ using System.Threading; using System.Management; using System.Windows.Forms; #endif -using Microsoft.Xna.Framework.Graphics; using Newtonsoft.Json; using StardewModdingAPI.AssemblyRewriters; using StardewModdingAPI.Events; @@ -38,26 +36,30 @@ namespace StardewModdingAPI /// The core logger for SMAPI. private readonly Monitor Monitor; - /// The SMAPI configuration settings. - private readonly SConfig Settings; - /// Tracks whether the game should exit immediately and any pending initialisation should be cancelled. private readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource(); - /// Whether the game is currently running. - private bool IsGameRunning; - /// The underlying game instance. private SGame GameInstance; + /// The SMAPI configuration settings. + /// This is initialised after the game starts. + private SConfig Settings; + /// Tracks the installed mods. - private readonly ModRegistry ModRegistry; + /// This is initialised after the game starts. + private ModRegistry ModRegistry; /// Manages deprecation warnings. - private readonly DeprecationManager DeprecationManager; + /// This is initialised after the game starts. + private DeprecationManager DeprecationManager; /// Manages console commands. - private readonly CommandManager CommandManager = new CommandManager(); + /// This is initialised after the game starts. + private CommandManager CommandManager; + + /// Whether the game is currently running. + private bool IsGameRunning; /********* @@ -65,7 +67,7 @@ namespace StardewModdingAPI *********/ /// The main entry point which hooks into and launches the game. /// The command-line arguments. - private static void Main(string[] args) + public static void Main(string[] args) { // get flags from arguments bool writeToConsole = !args.Contains("--no-terminal"); @@ -92,65 +94,28 @@ namespace StardewModdingAPI /// Construct an instance. /// Whether to output log messages to the console. /// The full file path to which to write log messages. - internal Program(bool writeToConsole, string logPath) + public Program(bool writeToConsole, string logPath) { - // load settings - this.Settings = JsonConvert.DeserializeObject(File.ReadAllText(Constants.ApiConfigPath)); - - // initialise this.LogFile = new LogFileManager(logPath); this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.ExitGameImmediately) { WriteToConsole = writeToConsole }; - this.ModRegistry = new ModRegistry(this.Settings.ModCompatibility); - this.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry); } /// Launch SMAPI. - internal void LaunchInteractively() + public void LaunchInteractively() { - // initialise logging - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); // for consistent log formatting - this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} on {this.GetFriendlyPlatformName()}", LogLevel.Info); - Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)}"; - - // inject compatibility shims -#pragma warning disable 618 - Command.Shim(this.CommandManager, this.DeprecationManager, this.ModRegistry); - Config.Shim(this.DeprecationManager); - InternalExtensions.Shim(this.ModRegistry); - Log.Shim(this.DeprecationManager, this.GetSecondaryMonitor("legacy mod"), this.ModRegistry); - Mod.Shim(this.DeprecationManager); - ContentEvents.Shim(this.ModRegistry, this.Monitor); - GameEvents.Shim(this.DeprecationManager); - PlayerEvents.Shim(this.DeprecationManager); - TimeEvents.Shim(this.DeprecationManager); -#pragma warning restore 618 - - // redirect direct console output - { - Monitor monitor = this.GetSecondaryMonitor("Console.Out"); - monitor.WriteToFile = false; // not useful for troubleshooting mods per discussion - if (monitor.WriteToConsole) - this.ConsoleManager.OnLineIntercepted += line => monitor.Log(line, LogLevel.Trace); - } - - // add warning headers - if (this.Settings.DeveloperMode) + // initialise SMAPI + try { - this.Monitor.ShowTraceInConsole = true; - this.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Warn); - } - if (!this.Settings.CheckForUpdates) - this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn); - if (!this.Monitor.WriteToConsole) - this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn); + // init logging + this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} on {this.GetFriendlyPlatformName()}", LogLevel.Info); + this.Monitor.Log($"Mods go here: {Constants.ModPath}"); + this.Monitor.Log("Preparing SMAPI..."); - // print file paths - this.Monitor.Log($"Mods go here: {Constants.ModPath}"); + // validate paths + this.VerifyPath(Constants.ModPath); + this.VerifyPath(Constants.LogDir); - // hook into & launch the game - try - { - // verify version + // validate game version if (Constants.GameVersion.IsOlderThan(Constants.MinimumGameVersion)) { this.Monitor.Log($"Oops! You're running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)}, but the oldest supported version is {Constants.GetGameDisplayVersion(Constants.MinimumGameVersion)}. Please update your game before using SMAPI. If you have the beta version on Steam, you may need to opt out to get the latest non-beta updates.", LogLevel.Error); @@ -164,29 +129,63 @@ namespace StardewModdingAPI return; } - // initialise folders - this.Monitor.Log("Loading SMAPI..."); - this.VerifyPath(Constants.ModPath); - this.VerifyPath(Constants.LogDir); + // add error handlers +#if SMAPI_FOR_WINDOWS + Application.ThreadException += (sender, e) => this.Monitor.Log($"Critical thread exception: {e.Exception.GetLogSummary()}", LogLevel.Error); + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); +#endif + AppDomain.CurrentDomain.UnhandledException += (sender, e) => this.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error); + + // override game & hook events + this.GameInstance = new SGame(this.Monitor); +#if SDV_1_2 + StardewValley.Program.gamePtr = this.GameInstance; +#else + { + Type type = typeof(Game1).Assembly.GetType("StardewValley.Program", true); + type.GetField("gamePtr").SetValue(null, this.GameInstance); + } +#endif - // check for update when game loads - if (this.Settings.CheckForUpdates) - GameEvents.GameLoaded += (sender, e) => this.CheckForUpdateAsync(); + // hook into game events + this.GameInstance.Exiting += (sender, e) => this.IsGameRunning = false; + this.GameInstance.Window.ClientSizeChanged += (sender, e) => GraphicsEvents.InvokeResize(this.Monitor, sender, e); + GameEvents.InitializeInternal += (sender, e) => this.InitialiseAfterGameStart(); + GameEvents.GameLoaded += (sender, e) => this.CheckForUpdateAsync(); - // launch game - this.StartGame(); + // set window titles + this.GameInstance.Window.Title = $"Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} - running SMAPI {Constants.ApiVersion}"; + Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)}"; } catch (Exception ex) { - this.Monitor.Log($"Critical error: {ex.GetLogSummary()}", LogLevel.Error); + this.Monitor.Log($"SMAPI failed to initialise: {ex.GetLogSummary()}", LogLevel.Error); + this.PressAnyKeyToExit(); + return; + } + + // start game + this.Monitor.Log("Starting game..."); + try + { + this.IsGameRunning = true; + this.GameInstance.Run(); + } + catch (Exception ex) + { + this.Monitor.Log($"The game failed unexpectedly: {ex.GetLogSummary()}", LogLevel.Error); + this.PressAnyKeyToExit(); + } + finally + { + this.IsGameRunning = false; } - this.PressAnyKeyToExit(); } /// Immediately exit the game without saving. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs. /// The module which requested an immediate exit. /// The reason provided for the shutdown. - internal void ExitGameImmediately(string module, string reason) + public void ExitGameImmediately(string module, string reason) { this.Monitor.LogFatal($"{module} requested an immediate game shutdown: {reason}"); this.CancellationTokenSource.Cancel(); @@ -209,9 +208,106 @@ namespace StardewModdingAPI /********* ** Private methods *********/ + /// Initialise SMAPI and mods after the game starts. + private void InitialiseAfterGameStart() + { + // load settings + this.Settings = JsonConvert.DeserializeObject(File.ReadAllText(Constants.ApiConfigPath)); + + // load core components + this.ModRegistry = new ModRegistry(this.Settings.ModCompatibility); + this.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry); + this.CommandManager = new CommandManager(); + + // inject compatibility shims +#pragma warning disable 618 + Command.Shim(this.CommandManager, this.DeprecationManager, this.ModRegistry); + Config.Shim(this.DeprecationManager); + InternalExtensions.Shim(this.ModRegistry); + Log.Shim(this.DeprecationManager, this.GetSecondaryMonitor("legacy mod"), this.ModRegistry); + Mod.Shim(this.DeprecationManager); + ContentEvents.Shim(this.ModRegistry, this.Monitor); + GameEvents.Shim(this.DeprecationManager); + PlayerEvents.Shim(this.DeprecationManager); + TimeEvents.Shim(this.DeprecationManager); +#pragma warning restore 618 + + // redirect direct console output + { + Monitor monitor = this.GetSecondaryMonitor("Console.Out"); + monitor.WriteToFile = false; // not useful for troubleshooting mods per discussion + if (monitor.WriteToConsole) + this.ConsoleManager.OnLineIntercepted += line => monitor.Log(line, LogLevel.Trace); + } + + // add warning headers + if (this.Settings.DeveloperMode) + { + this.Monitor.ShowTraceInConsole = true; + this.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Warn); + } + if (!this.Settings.CheckForUpdates) + this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn); + if (!this.Monitor.WriteToConsole) + this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn); + + // load mods + int modsLoaded = this.LoadMods(); + if (this.CancellationTokenSource.IsCancellationRequested) + { + this.Monitor.Log("Shutdown requested; interrupting initialisation.", LogLevel.Error); + return; + } + + // update window titles + this.GameInstance.Window.Title = $"Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods"; + Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} with {modsLoaded} mods"; + + // start SMAPI console + new Thread(this.RunConsoleLoop).Start(); + } + + /// Run a loop handling console input. + [SuppressMessage("ReSharper", "FunctionNeverReturns", Justification = "The thread is aborted when the game exits.")] + private void RunConsoleLoop() + { + // prepare help command + this.Monitor.Log("Starting console..."); + this.Monitor.Log("Type 'help' for help, or 'help ' for a command's usage", LogLevel.Info); + this.CommandManager.Add("SMAPI", "help", "Lists all commands | 'help ' returns command description", this.HandleHelpCommand); + + // start handling command line input + Thread inputThread = new Thread(() => + { + while (true) + { + string input = Console.ReadLine(); + try + { + if (!string.IsNullOrWhiteSpace(input) && !this.CommandManager.Trigger(input)) + this.Monitor.Log("Unknown command; type 'help' for a list of available commands.", LogLevel.Error); + } + catch (Exception ex) + { + this.Monitor.Log($"The handler registered for that command failed:\n{ex.GetLogSummary()}", LogLevel.Error); + } + } + }); + inputThread.Start(); + + // keep console thread alive while the game is running + while (this.IsGameRunning) + Thread.Sleep(1000 / 10); + if (inputThread.ThreadState == ThreadState.Running) + inputThread.Abort(); + } + /// Asynchronously check for a new version of SMAPI, and print a message to the console if an update is available. private void CheckForUpdateAsync() { + if (!this.Settings.CheckForUpdates) + return; + new Thread(() => { try @@ -228,91 +324,6 @@ namespace StardewModdingAPI }).Start(); } - /// Hook into Stardew Valley and launch the game. - private void StartGame() - { - try - { - this.Monitor.Log("Loading game..."); - - // add error handlers -#if SMAPI_FOR_WINDOWS - Application.ThreadException += (sender, e) => this.Monitor.Log($"Critical thread exception: {e.Exception.GetLogSummary()}", LogLevel.Error); - Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); -#endif - AppDomain.CurrentDomain.UnhandledException += (sender, e) => this.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error); - - // override Game1 instance - this.GameInstance = new SGame(this.Monitor); - this.GameInstance.Exiting += (sender, e) => this.IsGameRunning = false; - this.GameInstance.Window.ClientSizeChanged += (sender, e) => GraphicsEvents.InvokeResize(this.Monitor, sender, e); - this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} with SMAPI {Constants.ApiVersion}"; -#if SDV_1_2 - StardewValley.Program.gamePtr = this.GameInstance; -#else - { - Type type = typeof(Game1).Assembly.GetType("StardewValley.Program", true); - type.GetField("gamePtr").SetValue(null, this.GameInstance); - } -#endif - - // configure - Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; - - // load mods - this.LoadMods(); - if (this.CancellationTokenSource.IsCancellationRequested) - { - this.Monitor.Log("Shutdown requested; interrupting initialisation.", LogLevel.Error); - return; - } - - // initialise console after game launches - new Thread(() => - { - // wait for the game to load up - while (!this.IsGameRunning) - Thread.Sleep(1000); - - // register help command - this.CommandManager.Add("SMAPI", "help", "Lists all commands | 'help ' returns command description", this.HandleHelpCommand); - - // listen for command line input - this.Monitor.Log("Starting console..."); - this.Monitor.Log("Type 'help' for help, or 'help ' for a command's usage", LogLevel.Info); - Thread consoleInputThread = new Thread(this.ConsoleInputLoop); - consoleInputThread.Start(); - while (this.IsGameRunning) - Thread.Sleep(1000 / 10); // Check if the game is still running 10 times a second - - // abort the console thread, we're closing - if (consoleInputThread.ThreadState == ThreadState.Running) - consoleInputThread.Abort(); - }).Start(); - - // start game loop - this.Monitor.Log("Starting game..."); - if (this.CancellationTokenSource.IsCancellationRequested) - { - this.Monitor.Log("Shutdown requested; interrupting initialisation.", LogLevel.Error); - return; - } - try - { - this.IsGameRunning = true; - this.GameInstance.Run(); - } - finally - { - this.IsGameRunning = false; - } - } - catch (Exception ex) - { - this.Monitor.Log($"The game encountered a fatal error:\n{ex.GetLogSummary()}", LogLevel.Error); - } - } - /// Create a directory path if it doesn't exist. /// The directory path. private void VerifyPath(string path) @@ -329,7 +340,8 @@ namespace StardewModdingAPI } /// Load and hook up all mods in the mod directory. - private void LoadMods() + /// Returns the number of mods loaded. + private int LoadMods() { this.Monitor.Log("Loading mods..."); @@ -354,7 +366,7 @@ namespace StardewModdingAPI if (this.CancellationTokenSource.IsCancellationRequested) { this.Monitor.Log("Shutdown requested; interrupting mod loading.", LogLevel.Error); - return; + return modsLoaded; } // get manifest path @@ -553,12 +565,12 @@ namespace StardewModdingAPI } // initialise mods - foreach (Mod mod in this.ModRegistry.GetMods()) + foreach (IMod mod in this.ModRegistry.GetMods()) { try { // call entry methods - mod.Entry(); // deprecated since 1.0 + (mod as Mod)?.Entry(); // deprecated since 1.0 mod.Entry(mod.Helper); // raise deprecation warning for old Entry() methods @@ -575,26 +587,8 @@ namespace StardewModdingAPI this.Monitor.Log($"Loaded {modsLoaded} mods."); foreach (Action warning in deprecationWarnings) warning(); - Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} with {modsLoaded} mods"; - } - /// Run a loop handling console input. - [SuppressMessage("ReSharper", "FunctionNeverReturns", Justification = "The thread is aborted when the game exits.")] - private void ConsoleInputLoop() - { - while (true) - { - string input = Console.ReadLine(); - try - { - if (!string.IsNullOrWhiteSpace(input) && !this.CommandManager.Trigger(input)) - this.Monitor.Log("Unknown command; type 'help' for a list of available commands.", LogLevel.Error); - } - catch (Exception ex) - { - this.Monitor.Log($"The handler registered for that command failed:\n{ex.GetLogSummary()}", LogLevel.Error); - } - } + return modsLoaded; } /// The method called when the user submits the help command in the console. -- cgit From 01917e70a28a4a9028417d1784ef7f2ab06869a7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 21:55:01 -0400 Subject: fix rare issue where installer crashes trying to delete a bundled mod from %appdata% (#266) --- release-notes.md | 1 + src/StardewModdingAPI.Installer/InteractiveInstaller.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index e6ddb3db..fe55ed10 100644 --- a/release-notes.md +++ b/release-notes.md @@ -17,6 +17,7 @@ For players: * Added support for Stardew Valley 1.2 beta. * Added logic to rewrite many mods for compatibility with game updates, though some mods may still need an update. * Fixed some players getting `SEHException` errors. +* Fixed rare issue where the installer would crash trying to delete a bundled mod from `%appdata%`. For mod developers: * Fixed mouse-changed event never updating prior mouse position. diff --git a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs index e1e62d89..c456fdc0 100644 --- a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs +++ b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs @@ -592,7 +592,7 @@ namespace StardewModdingApi.Installer if (isDir && packagedModNames.Contains(entry.Name, StringComparer.InvariantCultureIgnoreCase)) { this.PrintDebug($" Deleting {entry.Name} because it's bundled into SMAPI..."); - entry.Delete(); + this.InteractivelyDelete(entry.FullName); continue; } -- cgit From 5ff3184c301d382f6be528486bdd3139ef2ee2ff Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 21:59:54 -0400 Subject: add version.IsBetween method (#263) --- src/StardewModdingAPI/ISemanticVersion.cs | 5 +++++ src/StardewModdingAPI/SemanticVersion.cs | 8 ++++++++ 2 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/StardewModdingAPI/ISemanticVersion.cs b/src/StardewModdingAPI/ISemanticVersion.cs index 3b9bdb44..24e6442a 100644 --- a/src/StardewModdingAPI/ISemanticVersion.cs +++ b/src/StardewModdingAPI/ISemanticVersion.cs @@ -32,6 +32,11 @@ namespace StardewModdingAPI /// The version to compare with this instance. bool IsNewerThan(ISemanticVersion other); + /// Get whether this version is between two specified versions (inclusively). + /// The minimum version. + /// The maximum version. + bool IsBetween(ISemanticVersion min, ISemanticVersion max); + /// Get a string representation of the version. string ToString(); } diff --git a/src/StardewModdingAPI/SemanticVersion.cs b/src/StardewModdingAPI/SemanticVersion.cs index 9610562f..f6bfb04d 100644 --- a/src/StardewModdingAPI/SemanticVersion.cs +++ b/src/StardewModdingAPI/SemanticVersion.cs @@ -134,6 +134,14 @@ namespace StardewModdingAPI return this.CompareTo(other) > 0; } + /// Get whether this version is between two specified versions (inclusively). + /// The minimum version. + /// The maximum version. + public bool IsBetween(ISemanticVersion min, ISemanticVersion max) + { + return this.CompareTo(min) >= 0 && this.CompareTo(max) <= 0; + } + /// Get a string representation of the version. public override string ToString() { -- cgit From 085ae07251c9972bed941e33103f41724d8cd320 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 22:04:56 -0400 Subject: add string overloads for version methods (#263) --- release-notes.md | 5 +++-- src/StardewModdingAPI/ISemanticVersion.cs | 16 ++++++++++++++++ src/StardewModdingAPI/SemanticVersion.cs | 27 ++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index fe55ed10..628757ae 100644 --- a/release-notes.md +++ b/release-notes.md @@ -20,10 +20,11 @@ For players: * Fixed rare issue where the installer would crash trying to delete a bundled mod from `%appdata%`. For mod developers: +* Mods are now initialised after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method. +* Mods can now specify a minimum game version in their `manifest.json`. +* Added `IsBetween` and string overloads to the `ISemanticVersion` methods. * Fixed mouse-changed event never updating prior mouse position. * Fixed `monitor.ExitGameImmediately` not working correctly. -* Mods can now specify a minimum game version in their `manifest.json`. -* Mods are now initialised after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method. ## 1.9 See [log](https://github.com/Pathoschild/SMAPI/compare/1.8...1.9). diff --git a/src/StardewModdingAPI/ISemanticVersion.cs b/src/StardewModdingAPI/ISemanticVersion.cs index 24e6442a..27a2f67d 100644 --- a/src/StardewModdingAPI/ISemanticVersion.cs +++ b/src/StardewModdingAPI/ISemanticVersion.cs @@ -28,15 +28,31 @@ namespace StardewModdingAPI /// The version to compare with this instance. bool IsOlderThan(ISemanticVersion other); + /// Get whether this version is older than the specified version. + /// The version to compare with this instance. + /// The specified version is not a valid semantic version. + bool IsOlderThan(string other); + /// Get whether this version is newer than the specified version. /// The version to compare with this instance. bool IsNewerThan(ISemanticVersion other); + /// Get whether this version is newer than the specified version. + /// The version to compare with this instance. + /// The specified version is not a valid semantic version. + bool IsNewerThan(string other); + /// Get whether this version is between two specified versions (inclusively). /// The minimum version. /// The maximum version. bool IsBetween(ISemanticVersion min, ISemanticVersion max); + /// Get whether this version is between two specified versions (inclusively). + /// The minimum version. + /// The maximum version. + /// One of the specified versions is not a valid semantic version. + bool IsBetween(string min, string max); + /// Get a string representation of the version. string ToString(); } diff --git a/src/StardewModdingAPI/SemanticVersion.cs b/src/StardewModdingAPI/SemanticVersion.cs index f6bfb04d..db25dc11 100644 --- a/src/StardewModdingAPI/SemanticVersion.cs +++ b/src/StardewModdingAPI/SemanticVersion.cs @@ -67,7 +67,7 @@ namespace StardewModdingAPI /// The implementation is defined by Semantic Version 2.0 (http://semver.org/). public int CompareTo(ISemanticVersion other) { - if(other == null) + if (other == null) throw new ArgumentNullException(nameof(other)); const int same = 0; @@ -127,6 +127,14 @@ namespace StardewModdingAPI return this.CompareTo(other) < 0; } + /// Get whether this version is older than the specified version. + /// The version to compare with this instance. + /// The specified version is not a valid semantic version. + public bool IsOlderThan(string other) + { + return this.IsOlderThan(new SemanticVersion(other)); + } + /// Get whether this version is newer than the specified version. /// The version to compare with this instance. public bool IsNewerThan(ISemanticVersion other) @@ -134,6 +142,14 @@ namespace StardewModdingAPI return this.CompareTo(other) > 0; } + /// Get whether this version is newer than the specified version. + /// The version to compare with this instance. + /// The specified version is not a valid semantic version. + public bool IsNewerThan(string other) + { + return this.IsNewerThan(new SemanticVersion(other)); + } + /// Get whether this version is between two specified versions (inclusively). /// The minimum version. /// The maximum version. @@ -142,6 +158,15 @@ namespace StardewModdingAPI return this.CompareTo(min) >= 0 && this.CompareTo(max) <= 0; } + /// Get whether this version is between two specified versions (inclusively). + /// The minimum version. + /// The maximum version. + /// One of the specified versions is not a valid semantic version. + public bool IsBetween(string min, string max) + { + return this.IsBetween(new SemanticVersion(min), new SemanticVersion(max)); + } + /// Get a string representation of the version. public override string ToString() { -- cgit From c1926f263c21147047b23d91c11dac6478fa1211 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 22:13:49 -0400 Subject: add world_setyear command to TrainerMod --- release-notes.md | 1 + src/TrainerMod/TrainerMod.cs | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 628757ae..1b44b57a 100644 --- a/release-notes.md +++ b/release-notes.md @@ -16,6 +16,7 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). For players: * Added support for Stardew Valley 1.2 beta. * Added logic to rewrite many mods for compatibility with game updates, though some mods may still need an update. +* Added `world_setyear` console command to TrainerMod. * Fixed some players getting `SEHException` errors. * Fixed rare issue where the installer would crash trying to delete a bundled mod from `%appdata%`. diff --git a/src/TrainerMod/TrainerMod.cs b/src/TrainerMod/TrainerMod.cs index 7187a358..465567f7 100644 --- a/src/TrainerMod/TrainerMod.cs +++ b/src/TrainerMod/TrainerMod.cs @@ -102,10 +102,11 @@ namespace TrainerMod .Add("list_items", "Lists and searches items in the game data.\n\nUsage: list_items [search]\n- search (optional): an arbitrary search string to filter by.", this.HandleCommand) - .Add("world_settime", "Sets the time to the specified value.\n\nUsage: world_settime \n- value: the target time in military time (like 0600 for 6am and 1800 for 6pm)", this.HandleCommand) .Add("world_freezetime", "Freezes or resumes time.\n\nUsage: world_freezetime [value]\n- value: one of 0 (resume), 1 (freeze), or blank (toggle).", this.HandleCommand) + .Add("world_settime", "Sets the time to the specified value.\n\nUsage: world_settime \n- value: the target time in military time (like 0600 for 6am and 1800 for 6pm)", this.HandleCommand) .Add("world_setday", "Sets the day to the specified value.\n\nUsage: world_setday .\n- value: the target day (a number from 1 to 28).", this.HandleCommand) - .Add("world_setseason", "Sets the season to the specified value.\n\nUsage: world_setseason \n- value: the target season (one of 'spring', 'summer', 'fall', 'winter').", this.HandleCommand) + .Add("world_setseason", "Sets the season to the specified value.\n\nUsage: world_setseason \n- season: the target season (one of 'spring', 'summer', 'fall', 'winter').", this.HandleCommand) + .Add("world_setyear", "Sets the year to the specified value.\n\nUsage: world_setyear \n- year: the target year (a number starting from 1).", this.HandleCommand) .Add("world_downminelevel", "Goes down one mine level?", this.HandleCommand) .Add("world_setminelevel", "Sets the mine level?\n\nUsage: world_setminelevel \n- value: The target level (a number between 1 and 120).", this.HandleCommand) @@ -489,6 +490,27 @@ namespace TrainerMod this.Monitor.Log($"The current season is {Game1.currentSeason}. Specify a value to change it.", LogLevel.Info); break; + case "world_setyear": + if (args.Any()) + { + int year; + if (int.TryParse(args[0], out year)) + { + if (year >= 1) + { + Game1.year = year; + this.Monitor.Log($"OK, the year is now {Game1.year}.", LogLevel.Info); + } + else + this.LogUsageError("That isn't a valid year.", command); + } + else + this.LogArgumentNotInt(command); + } + else + this.Monitor.Log($"The current year is {Game1.year}. Specify a value to change the year.", LogLevel.Info); + break; + case "player_sethealth": if (args.Any()) { -- cgit From 07197fac9dbea84565f6004029b15667c9c2b038 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 22:46:14 -0400 Subject: add support for non-melee weapons to TrainerMod (#259) --- release-notes.md | 4 +++- src/TrainerMod/TrainerMod.cs | 56 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 1b44b57a..9227d4b3 100644 --- a/release-notes.md +++ b/release-notes.md @@ -16,9 +16,11 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). For players: * Added support for Stardew Valley 1.2 beta. * Added logic to rewrite many mods for compatibility with game updates, though some mods may still need an update. -* Added `world_setyear` console command to TrainerMod. * Fixed some players getting `SEHException` errors. * Fixed rare issue where the installer would crash trying to delete a bundled mod from `%appdata%`. +* Improved TrainerMod commands: + * Added `world_setyear` to change the current year. + * Replaced `player_addmelee` with `player_addweapon` with support for non-melee weapons. For mod developers: * Mods are now initialised after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method. diff --git a/src/TrainerMod/TrainerMod.cs b/src/TrainerMod/TrainerMod.cs index 465567f7..168b7e8e 100644 --- a/src/TrainerMod/TrainerMod.cs +++ b/src/TrainerMod/TrainerMod.cs @@ -97,7 +97,7 @@ namespace TrainerMod .Add("player_changestyle", "Sets the style of a player feature.\n\nUsage: player_changecolor .\n- target: what to change (one of 'hair', 'shirt', 'skin', 'acc', 'shoe', 'swim', or 'gender').\n- value: the integer style ID.", this.HandleCommand) .Add("player_additem", $"Gives the player an item.\n\nUsage: player_additem [count] [quality]\n- item: the item ID (use the 'list_items' command to see a list).\n- count (optional): how many of the item to give.\n- quality (optional): one of {Object.lowQuality} (normal), {Object.medQuality} (silver), {Object.highQuality} (gold), or {Object.bestQuality} (iridium).", this.HandleCommand) - .Add("player_addmelee", "Gives the player a melee weapon.\n\nUsage: player_addmelee \n- item: the melee weapon ID (use the 'list_items' command to see a list).", this.HandleCommand) + .Add("player_addweapon", "Gives the player a weapon.\n\nUsage: player_addweapon \n- item: the weapon ID (use the 'list_items' command to see a list).", this.HandleCommand) .Add("player_addring", "Gives the player a ring.\n\nUsage: player_addring \n- item: the ring ID (use the 'list_items' command to see a list).", this.HandleCommand) .Add("list_items", "Lists and searches items in the game data.\n\nUsage: list_items [search]\n- search (optional): an arbitrary search string to filter by.", this.HandleCommand) @@ -609,20 +609,62 @@ namespace TrainerMod this.LogArgumentsInvalid(command); break; - case "player_addmelee": + case "player_addweapon": if (args.Any()) { int weaponID; if (int.TryParse(args[0], out weaponID)) { - MeleeWeapon weapon = new MeleeWeapon(weaponID); - if (weapon.Name == null) + // get raw weapon data + string data; + if (!Game1.content.Load>("Data\\weapons").TryGetValue(weaponID, out data)) + { this.Monitor.Log("There is no such weapon ID.", LogLevel.Error); - else + return; + } + + // get raw weapon type + int type; { - Game1.player.addItemByMenuIfNecessary(weapon); - this.Monitor.Log($"OK, added {weapon.Name} to your inventory.", LogLevel.Info); + string[] fields = data.Split('/'); + string typeStr = fields.Length > 8 ? fields[8] : null; + if (!int.TryParse(typeStr, out type)) + { + this.Monitor.Log("Could not parse the data for the weapon with that ID.", LogLevel.Error); + return; + } } + + // get weapon + Tool weapon; + switch (type) + { + case MeleeWeapon.stabbingSword: + case MeleeWeapon.dagger: + case MeleeWeapon.club: + case MeleeWeapon.defenseSword: + weapon = new MeleeWeapon(weaponID); + break; + + case 4: + weapon = new Slingshot(weaponID); + break; + + default: + this.Monitor.Log($"The specified weapon has unknown type '{type}' in the game data.", LogLevel.Error); + return; + } + + // validate + if (weapon.Name == null) + { + this.Monitor.Log("That weapon doesn't seem to be valid.", LogLevel.Error); + return; + } + + // add weapon + Game1.player.addItemByMenuIfNecessary(weapon); + this.Monitor.Log($"OK, added {weapon.Name} to your inventory.", LogLevel.Info); } else this.LogUsageError("The weapon ID must be an integer.", command); -- cgit From 8ec607ba3c1d672f5aeac065dd19dc3514e209c4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 23:00:13 -0400 Subject: ensure SMAPI resources are disposed on exit (#268) --- release-notes.md | 3 ++- src/StardewModdingAPI/Program.cs | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 9227d4b3..bc2c90b8 100644 --- a/release-notes.md +++ b/release-notes.md @@ -16,7 +16,8 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). For players: * Added support for Stardew Valley 1.2 beta. * Added logic to rewrite many mods for compatibility with game updates, though some mods may still need an update. -* Fixed some players getting `SEHException` errors. +* Fixed `SEHException` errors affecting some players. +* Fixed issue where SMAPI didn't unlock some files on exit. * Fixed rare issue where the installer would crash trying to delete a bundled mod from `%appdata%`. * Improved TrainerMod commands: * Added `world_setyear` to change the current year. diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 3bd91a7c..5cf80448 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -22,7 +22,7 @@ using Monitor = StardewModdingAPI.Framework.Monitor; namespace StardewModdingAPI { /// The main entry point for SMAPI, responsible for hooking into and launching the game. - internal class Program + internal class Program : IDisposable { /********* ** Properties @@ -87,8 +87,8 @@ namespace StardewModdingAPI logPath = Constants.DefaultLogPath; // load SMAPI - new Program(writeToConsole, logPath) - .LaunchInteractively(); + using (Program program = new Program(writeToConsole, logPath)) + program.RunInteractively(); } /// Construct an instance. @@ -101,7 +101,7 @@ namespace StardewModdingAPI } /// Launch SMAPI. - public void LaunchInteractively() + public void RunInteractively() { // initialise SMAPI try @@ -204,6 +204,15 @@ namespace StardewModdingAPI return this.GetSecondaryMonitor(modName); } + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + this.LogFile?.Dispose(); + this.ConsoleManager?.Dispose(); + this.CancellationTokenSource?.Dispose(); + this.GameInstance?.Dispose(); + } + /********* ** Private methods -- cgit From a9c220c0fe0fd6f52bee73a8f5da91fd1d007d0f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 23:00:51 -0400 Subject: minor cleanup --- src/StardewModdingAPI.Installer/InteractiveInstaller.cs | 3 +-- src/StardewModdingAPI/Events/GameEvents.cs | 5 ++--- src/StardewModdingAPI/Framework/Monitor.cs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs index c456fdc0..38c19d2b 100644 --- a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs +++ b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs @@ -626,9 +626,8 @@ namespace StardewModdingApi.Installer private void Move(FileSystemInfo entry, string newPath) { // file - if (entry is FileInfo) + if (entry is FileInfo file) { - FileInfo file = (FileInfo)entry; file.CopyTo(newPath); file.Delete(); } diff --git a/src/StardewModdingAPI/Events/GameEvents.cs b/src/StardewModdingAPI/Events/GameEvents.cs index babf7f31..029ec1f9 100644 --- a/src/StardewModdingAPI/Events/GameEvents.cs +++ b/src/StardewModdingAPI/Events/GameEvents.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using StardewModdingAPI.Framework; namespace StardewModdingAPI.Events @@ -21,11 +20,11 @@ namespace StardewModdingAPI.Events internal static event EventHandler InitializeInternal; /// Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called after . - [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(Initialize) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(GameEvents.Initialize) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] public static event EventHandler Initialize; /// Raised before XNA loads or reloads graphics resources. Called during . - [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(LoadContent) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(GameEvents.LoadContent) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] public static event EventHandler LoadContent; /// Raised during launch after configuring Stardew Valley, loading it into memory, and opening the game window. The window is still blank by this point. diff --git a/src/StardewModdingAPI/Framework/Monitor.cs b/src/StardewModdingAPI/Framework/Monitor.cs index 76793bbf..51feff78 100644 --- a/src/StardewModdingAPI/Framework/Monitor.cs +++ b/src/StardewModdingAPI/Framework/Monitor.cs @@ -35,7 +35,7 @@ namespace StardewModdingAPI.Framework }; /// A delegate which requests that SMAPI immediately exit the game. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs. - private RequestExitDelegate RequestExit; + private readonly RequestExitDelegate RequestExit; /********* -- cgit From e3219bd96988c5890e4ddfeb661c942c0c86d251 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 23:10:52 -0400 Subject: dispose resources on Windows Form exit (#268) --- src/StardewModdingAPI/Program.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 5cf80448..424e1727 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -61,6 +61,9 @@ namespace StardewModdingAPI /// Whether the game is currently running. private bool IsGameRunning; + /// Whether the program has been disposed. + private bool IsDisposed; + /********* ** Public methods @@ -136,7 +139,7 @@ namespace StardewModdingAPI #endif AppDomain.CurrentDomain.UnhandledException += (sender, e) => this.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error); - // override game & hook events + // override game this.GameInstance = new SGame(this.Monitor); #if SDV_1_2 StardewValley.Program.gamePtr = this.GameInstance; @@ -148,7 +151,10 @@ namespace StardewModdingAPI #endif // hook into game events - this.GameInstance.Exiting += (sender, e) => this.IsGameRunning = false; +#if SMAPI_FOR_WINDOWS + ((Form)Control.FromHandle(this.GameInstance.Window.Handle)).FormClosing += (sender, args) => this.Dispose(); +#endif + this.GameInstance.Exiting += (sender, e) => this.Dispose(); this.GameInstance.Window.ClientSizeChanged += (sender, e) => GraphicsEvents.InvokeResize(this.Monitor, sender, e); GameEvents.InitializeInternal += (sender, e) => this.InitialiseAfterGameStart(); GameEvents.GameLoaded += (sender, e) => this.CheckForUpdateAsync(); @@ -178,7 +184,7 @@ namespace StardewModdingAPI } finally { - this.IsGameRunning = false; + this.Dispose(); } } @@ -207,6 +213,11 @@ namespace StardewModdingAPI /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. public void Dispose() { + if (this.IsDisposed) + return; + this.IsDisposed = true; + + this.IsGameRunning = false; this.LogFile?.Dispose(); this.ConsoleManager?.Dispose(); this.CancellationTokenSource?.Dispose(); -- cgit From 1de8895642c12e6e36f95c0b960679a8e30d0615 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 23 Apr 2017 23:58:08 -0400 Subject: fixed `Constants.SaveFolderName` not set for a new game until the save is created (#261) --- release-notes.md | 1 + src/StardewModdingAPI/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index bc2c90b8..103fceb5 100644 --- a/release-notes.md +++ b/release-notes.md @@ -29,6 +29,7 @@ For mod developers: * Added `IsBetween` and string overloads to the `ISemanticVersion` methods. * Fixed mouse-changed event never updating prior mouse position. * Fixed `monitor.ExitGameImmediately` not working correctly. +* Fixed `Constants.SaveFolderName` not set for a new game until the save is created. ## 1.9 See [log](https://github.com/Pathoschild/SMAPI/compare/1.8...1.9). diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index a8121461..aca5abb8 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -64,7 +64,7 @@ namespace StardewModdingAPI public static string SavesPath { get; } = Path.Combine(Constants.DataPath, "Saves"); /// The directory name containing the current save's data (if a save is loaded and the directory exists). - public static string SaveFolderName => Constants.SavePathReady ? Constants.GetSaveFolderName() : ""; + public static string SaveFolderName => Constants.IsSaveLoaded ? Constants.GetSaveFolderName() : ""; /// The directory path containing the current save's data (if a save is loaded and the directory exists). public static string CurrentSavePath => Constants.SavePathReady ? Path.Combine(Constants.SavesPath, Constants.GetSaveFolderName()) : ""; -- cgit From 4e7733ba2dd4912891e6161cca2e2dfc2e94196a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 24 Apr 2017 12:36:20 -0400 Subject: update for SDV 1.2 non-beta release --- release-notes.md | 2 +- src/StardewModdingAPI/Constants.cs | 18 +- src/StardewModdingAPI/Events/ContentEvents.cs | 1 - src/StardewModdingAPI/Framework/ModRegistry.cs | 3 - .../Framework/Models/ModCompatibility.cs | 3 - src/StardewModdingAPI/Framework/SGame.cs | 455 +-------------------- src/StardewModdingAPI/Program.cs | 8 - .../StardewModdingAPI.config.json | 163 ++++---- 8 files changed, 81 insertions(+), 572 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 103fceb5..1dd1fa6b 100644 --- a/release-notes.md +++ b/release-notes.md @@ -14,7 +14,7 @@ For mod developers: See [log](https://github.com/Pathoschild/SMAPI/compare/1.9...1.10). For players: -* Added support for Stardew Valley 1.2 beta. +* Updated to Stardew Valley 1.2. * Added logic to rewrite many mods for compatibility with game updates, though some mods may still need an update. * Fixed `SEHException` errors affecting some players. * Fixed issue where SMAPI didn't unlock some files on exit. diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index aca5abb8..6ba16935 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -36,20 +36,10 @@ namespace StardewModdingAPI public static ISemanticVersion ApiVersion { get; } = new SemanticVersion(1, 10, 0); /// The minimum supported version of Stardew Valley. - public static ISemanticVersion MinimumGameVersion { get; } = -#if SDV_1_2 - new SemanticVersion("1.2.15"); -#else - new SemanticVersion("1.1"); -#endif + public static ISemanticVersion MinimumGameVersion { get; } = new SemanticVersion("1.2.15"); /// The maximum supported version of Stardew Valley. - public static ISemanticVersion MaximumGameVersion { get; } = -#if SDV_1_2 - null; -#else - new SemanticVersion("1.1.1"); -#endif + public static ISemanticVersion MaximumGameVersion { get; } = null; /// The path to the game folder. public static string ExecutionPath { get; } = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); @@ -156,10 +146,8 @@ namespace StardewModdingAPI /**** ** Finders throw an exception when incompatible code is found. ****/ -#if SDV_1_2 // changes in Stardew Valley 1.2 (with no rewriters) new FieldFinder("StardewValley.Item", "set_Name"), -#endif // APIs removed in SMAPI 1.9 new TypeFinder("StardewModdingAPI.Advanced.ConfigFile"), @@ -184,7 +172,6 @@ namespace StardewModdingAPI // crossplatform new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchWrapper), onlyIfPlatformChanged: true), -#if SDV_1_2 // Stardew Valley 1.2 new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.activeClickableMenu)), new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.currentMinigame)), @@ -192,7 +179,6 @@ namespace StardewModdingAPI new FieldToPropertyRewriter(typeof(Game1), nameof(Game1.player)), new FieldReplaceRewriter(typeof(Game1), "borderFont", nameof(Game1.smallFont)), new FieldReplaceRewriter(typeof(Game1), "smoothFont", nameof(Game1.smallFont)), -#endif // SMAPI 1.9 new TypeReferenceRewriter("StardewModdingAPI.Inheritance.ItemStackChange", typeof(ItemStackChange)) diff --git a/src/StardewModdingAPI/Events/ContentEvents.cs b/src/StardewModdingAPI/Events/ContentEvents.cs index 9418673a..5b4146c5 100644 --- a/src/StardewModdingAPI/Events/ContentEvents.cs +++ b/src/StardewModdingAPI/Events/ContentEvents.cs @@ -5,7 +5,6 @@ using StardewModdingAPI.Framework; namespace StardewModdingAPI.Events { /// Events raised when the game loads content. - [Obsolete("This is an undocumented experimental API and may change without warning.")] public static class ContentEvents { /********* diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs index 8ea3502b..f015b7ba 100644 --- a/src/StardewModdingAPI/Framework/ModRegistry.cs +++ b/src/StardewModdingAPI/Framework/ModRegistry.cs @@ -138,9 +138,6 @@ namespace StardewModdingAPI.Framework mod.ID == key && (mod.LowerSemanticVersion == null || !manifest.Version.IsOlderThan(mod.LowerSemanticVersion)) && !manifest.Version.IsNewerThan(mod.UpperSemanticVersion) -#if !SDV_1_2 - && !mod.OnlyStardewValleyBeta -#endif select mod ).FirstOrDefault(); } diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs index e1ee8135..1e71dae0 100644 --- a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs @@ -37,9 +37,6 @@ namespace StardewModdingAPI.Framework.Models /// Indicates how SMAPI should consider the mod. public ModCompatibilityType Compatibility { get; set; } - /// Whether this record only applies to the Stardew Valley 1.2 beta. - public bool OnlyStardewValleyBeta { get; set; } - /**** ** Injected diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 39cc5cde..61493e87 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -1,8 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading.Tasks; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -14,14 +16,8 @@ using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Tools; using xTile.Dimensions; -using SFarmer = StardewValley.Farmer; -#if SDV_1_2 -using System.Diagnostics; -using System.Threading.Tasks; using xTile.Layers; -#else -using Rectangle = Microsoft.Xna.Framework.Rectangle; -#endif +using SFarmer = StardewValley.Farmer; namespace StardewModdingAPI.Framework { @@ -140,10 +136,8 @@ namespace StardewModdingAPI.Framework /// The player character at last check. private SFarmer PreviousFarmer; -#if SDV_1_2 /// The previous content locale. private LocalizedContentManager.LanguageCode? PreviousLocale; -#endif /// An index incremented on every tick and reset every 60th tick (0–59). private int CurrentUpdateTick; @@ -160,7 +154,6 @@ namespace StardewModdingAPI.Framework // ReSharper disable ArrangeStaticMemberQualifier, ArrangeThisQualifier, InconsistentNaming /// Used to access private fields and methods. private static readonly IReflectionHelper Reflection = new ReflectionHelper(); -#if SDV_1_2 private static List _fpsList => SGame.Reflection.GetPrivateField>(typeof(Game1), nameof(_fpsList)).GetValue(); private static Stopwatch _fpsStopwatch => SGame.Reflection.GetPrivateField(typeof(Game1), nameof(SGame._fpsStopwatch)).GetValue(); private static float _fps @@ -168,21 +161,13 @@ namespace StardewModdingAPI.Framework set { SGame.Reflection.GetPrivateField(typeof(Game1), nameof(_fps)).SetValue(value); } } private static Task _newDayTask => SGame.Reflection.GetPrivateField(typeof(Game1), nameof(_newDayTask)).GetValue(); -#endif private Color bgColor => SGame.Reflection.GetPrivateField(this, nameof(bgColor)).GetValue(); - public RenderTarget2D screenWrapper => -#if SDV_1_2 - SGame.Reflection.GetPrivateProperty(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop -#else - SGame.Reflection.GetPrivateField(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop -#endif + public RenderTarget2D screenWrapper => SGame.Reflection.GetPrivateProperty(this, "screen").GetValue(); // deliberately renamed to avoid an infinite loop public BlendState lightingBlend => SGame.Reflection.GetPrivateField(this, nameof(lightingBlend)).GetValue(); private readonly Action drawFarmBuildings = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawFarmBuildings)).Invoke(new object[0]); private readonly Action drawHUD = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawHUD)).Invoke(new object[0]); private readonly Action drawDialogueBox = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(drawDialogueBox)).Invoke(new object[0]); -#if SDV_1_2 private readonly Action renderScreenBuffer = () => SGame.Reflection.GetPrivateMethod(SGame.Instance, nameof(renderScreenBuffer)).Invoke(new object[0]); -#endif // ReSharper restore ArrangeStaticMemberQualifier, ArrangeThisQualifier, InconsistentNaming @@ -203,7 +188,6 @@ namespace StardewModdingAPI.Framework /**** ** Intercepted methods & events ****/ -#if SDV_1_2 /// Constructor a content manager to read XNB files. /// The service provider to use to locate services. /// The root directory to search for content. @@ -211,13 +195,11 @@ namespace StardewModdingAPI.Framework { return new SContentManager(this.Content.ServiceProvider, this.Content.RootDirectory, this.Monitor); } -#endif /// The method called when the game is updating its state. This happens roughly 60 times per second. /// A snapshot of the game timing state. protected override void Update(GameTime gameTime) { -#if SDV_1_2 // While a background new-day task is in progress, the game skips its own update logic // and defers to the XNA Update method. Running mod code in parallel to the background // update is risky, because data changes can conflict (e.g. collection changed during @@ -233,7 +215,6 @@ namespace StardewModdingAPI.Framework base.Update(gameTime); return; } -#endif // raise game loaded if (this.FirstUpdate) @@ -298,7 +279,6 @@ namespace StardewModdingAPI.Framework [SuppressMessage("ReSharper", "RedundantCast", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantExplicitNullableCreation", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantTypeArgumentsOfMethod", Justification = "copied from game code as-is")] -#if SDV_1_2 protected override void Draw(GameTime gameTime) { try @@ -953,425 +933,6 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"An error occured in the overridden draw loop: {ex.GetLogSummary()}", LogLevel.Error); } } -#else - protected override void Draw(GameTime gameTime) - { - try - { - if (!this.ZoomLevelIsOne) - this.GraphicsDevice.SetRenderTarget(this.screenWrapper); - - this.GraphicsDevice.Clear(this.bgColor); - if (Game1.options.showMenuBackground && Game1.activeClickableMenu != null && Game1.activeClickableMenu.showWithoutTransparencyIfOptionIsSet()) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - try - { - Game1.activeClickableMenu.drawBackground(Game1.spriteBatch); - } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing its background. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); - } - GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); - try - { - Game1.activeClickableMenu.draw(Game1.spriteBatch); - } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); - } - GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); - Game1.spriteBatch.End(); - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; - } - if (Game1.gameMode == 11) - { - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - Game1.spriteBatch.DrawString(Game1.smoothFont, "Stardew Valley has crashed...", new Vector2(16f, 16f), Color.HotPink); - Game1.spriteBatch.DrawString(Game1.smoothFont, "Please send the error report or a screenshot of this message to @ConcernedApe. (http://stardewvalley.net/contact/)", new Vector2(16f, 32f), new Color(0, 255, 0)); - Game1.spriteBatch.DrawString(Game1.smoothFont, Game1.parseText(Game1.errorMessage, Game1.smoothFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); - Game1.spriteBatch.End(); - return; - } - if (Game1.currentMinigame != null) - { - Game1.currentMinigame.draw(Game1.spriteBatch); - if (Game1.globalFade && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha)); - Game1.spriteBatch.End(); - } - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; - } - if (Game1.showingEndOfNightStuff) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - try - { - Game1.activeClickableMenu?.draw(Game1.spriteBatch); - } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); - } - Game1.spriteBatch.End(); - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; - } - if (Game1.gameMode == 6) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - string text = ""; - int num = 0; - while (num < gameTime.TotalGameTime.TotalMilliseconds % 999.0 / 333.0) - { - text += "."; - num++; - } - SpriteText.drawString(Game1.spriteBatch, "Loading" + text, 64, Game1.graphics.GraphicsDevice.Viewport.Height - 64, 999, -1, 999, 1f, 1f, false, 0, "Loading..."); - Game1.spriteBatch.End(); - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - return; - } - if (Game1.gameMode == 0) - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - else - { - if (Game1.drawLighting) - { - this.GraphicsDevice.SetRenderTarget(Game1.lightmap); - this.GraphicsDevice.Clear(Color.White * 0f); - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null); - Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, Game1.currentLocation.name.Equals("UndergroundMine") ? Game1.mine.getLightingColor(gameTime) : ((!Game1.ambientLight.Equals(Color.White) && (!Game1.isRaining || !Game1.currentLocation.isOutdoors)) ? Game1.ambientLight : Game1.outdoorLight)); - for (int i = 0; i < Game1.currentLightSources.Count; i++) - { - if (Utility.isOnScreen(Game1.currentLightSources.ElementAt(i).position, (int)(Game1.currentLightSources.ElementAt(i).radius * Game1.tileSize * 4f))) - Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(i).lightTexture, Game1.GlobalToLocal(Game1.viewport, Game1.currentLightSources.ElementAt(i).position) / Game1.options.lightingQuality, Game1.currentLightSources.ElementAt(i).lightTexture.Bounds, Game1.currentLightSources.ElementAt(i).color, 0f, new Vector2(Game1.currentLightSources.ElementAt(i).lightTexture.Bounds.Center.X, Game1.currentLightSources.ElementAt(i).lightTexture.Bounds.Center.Y), Game1.currentLightSources.ElementAt(i).radius / Game1.options.lightingQuality, SpriteEffects.None, 0.9f); - } - Game1.spriteBatch.End(); - this.GraphicsDevice.SetRenderTarget(this.ZoomLevelIsOne ? null : this.screenWrapper); - } - if (Game1.bloomDay) - Game1.bloom?.BeginDraw(); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - GraphicsEvents.InvokeOnPreRenderEvent(this.Monitor); - Game1.background?.draw(Game1.spriteBatch); - Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); - Game1.currentLocation.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.currentLocation.drawWater(Game1.spriteBatch); - if (Game1.CurrentEvent == null) - { - using (List.Enumerator enumerator = Game1.currentLocation.characters.GetEnumerator()) - { - while (enumerator.MoveNext()) - { - NPC current = enumerator.Current; - if (current != null && !current.swimming && !current.hideShadow && !current.IsMonster && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current.position + new Vector2(current.sprite.spriteWidth * Game1.pixelZoom / 2f, current.GetBoundingBox().Height + (current.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current.yJumpOffset / 40f) * current.scale, SpriteEffects.None, Math.Max(0f, current.getStandingY() / 10000f) - 1E-06f); - } - goto IL_B30; - } - } - foreach (NPC current2 in Game1.CurrentEvent.actors) - { - if (!current2.swimming && !current2.hideShadow && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current2.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current2.position + new Vector2(current2.sprite.spriteWidth * Game1.pixelZoom / 2f, current2.GetBoundingBox().Height + (current2.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current2.yJumpOffset / 40f) * current2.scale, SpriteEffects.None, Math.Max(0f, current2.getStandingY() / 10000f) - 1E-06f); - } - IL_B30: - if (!Game1.player.swimming && !Game1.player.isRidingHorse() && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((Game1.player.running || Game1.player.usingTool) && Game1.player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, 0f); - Game1.currentLocation.Map.GetLayer("Buildings").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.mapDisplayDevice.EndScene(); - Game1.spriteBatch.End(); - Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.CurrentEvent == null) - { - using (List.Enumerator enumerator3 = Game1.currentLocation.characters.GetEnumerator()) - { - while (enumerator3.MoveNext()) - { - NPC current3 = enumerator3.Current; - if (current3 != null && !current3.swimming && !current3.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current3.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current3.position + new Vector2(current3.sprite.spriteWidth * Game1.pixelZoom / 2f, current3.GetBoundingBox().Height + (current3.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current3.yJumpOffset / 40f) * current3.scale, SpriteEffects.None, Math.Max(0f, current3.getStandingY() / 10000f) - 1E-06f); - } - goto IL_F5F; - } - } - foreach (NPC current4 in Game1.CurrentEvent.actors) - { - if (!current4.swimming && !current4.hideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(current4.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, current4.position + new Vector2(current4.sprite.spriteWidth * Game1.pixelZoom / 2f, current4.GetBoundingBox().Height + (current4.IsMonster ? 0 : (Game1.pixelZoom * 3)))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), (Game1.pixelZoom + current4.yJumpOffset / 40f) * current4.scale, SpriteEffects.None, Math.Max(0f, current4.getStandingY() / 10000f) - 1E-06f); - } - IL_F5F: - if (!Game1.player.swimming && !Game1.player.isRidingHorse() && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(Game1.player.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.player.position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((Game1.player.running || Game1.player.usingTool) && Game1.player.FarmerSprite.indexInCurrentAnimation > 1) ? (Math.Abs(FarmerRenderer.featureYOffsetPerFrame[Game1.player.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, Math.Max(0.0001f, Game1.player.getStandingY() / 10000f + 0.00011f) - 0.0001f); - if (Game1.displayFarmer) - Game1.player.draw(Game1.spriteBatch); - if ((Game1.eventUp || Game1.killScreen) && !Game1.killScreen) - Game1.currentLocation.currentEvent?.draw(Game1.spriteBatch); - if (Game1.player.currentUpgrade != null && Game1.player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && Game1.currentLocation.Name.Equals("Farm")) - Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), Game1.player.currentUpgrade.getSourceRectangle(), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, (Game1.player.currentUpgrade.positionOfCarpenter.Y + Game1.tileSize * 3 / 4) / 10000f); - Game1.currentLocation.draw(Game1.spriteBatch); - if (Game1.eventUp && Game1.currentLocation.currentEvent?.messageToScreen != null) - Game1.drawWithBorder(Game1.currentLocation.currentEvent.messageToScreen, Color.Black, Color.White, new Vector2(Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width / 2 - Game1.borderFont.MeasureString(Game1.currentLocation.currentEvent.messageToScreen).X / 2f, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Height - Game1.tileSize), 0f, 1f, 0.999f); - if (Game1.player.ActiveObject == null && (Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && (!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool)) - Game1.drawTool(Game1.player); - if (Game1.currentLocation.Name.Equals("Farm")) - this.drawFarmBuildings(); - if (Game1.tvStation >= 0) - Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(6 * Game1.tileSize + Game1.tileSize / 4, 2 * Game1.tileSize + Game1.tileSize / 2)), new Rectangle(Game1.tvStation * 24, 0, 24, 15), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f); - if (Game1.panMode) - { - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle((int)Math.Floor((Game1.getOldMouseX() + Game1.viewport.X) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.X, (int)Math.Floor((Game1.getOldMouseY() + Game1.viewport.Y) / (double)Game1.tileSize) * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Lime * 0.75f); - foreach (Warp current5 in Game1.currentLocation.warps) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle(current5.X * Game1.tileSize - Game1.viewport.X, current5.Y * Game1.tileSize - Game1.viewport.Y, Game1.tileSize, Game1.tileSize), Color.Red * 0.75f); - } - Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); - Game1.currentLocation.Map.GetLayer("Front").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.mapDisplayDevice.EndScene(); - Game1.currentLocation.drawAboveFrontLayer(Game1.spriteBatch); - Game1.spriteBatch.End(); - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.currentLocation.Name.Equals("Farm") && Game1.stats.SeedsSown >= 200u) - { - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(3 * Game1.tileSize + Game1.tileSize / 4, Game1.tileSize + Game1.tileSize / 3)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize + Game1.tileSize, 2 * Game1.tileSize + Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(5 * Game1.tileSize, 2 * Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(3 * Game1.tileSize + Game1.tileSize / 2, 3 * Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(5 * Game1.tileSize - Game1.tileSize / 4, Game1.tileSize)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize, 3 * Game1.tileSize + Game1.tileSize / 6)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - Game1.spriteBatch.Draw(Game1.debrisSpriteSheet, Game1.GlobalToLocal(Game1.viewport, new Vector2(4 * Game1.tileSize + Game1.tileSize / 5, 2 * Game1.tileSize + Game1.tileSize / 3)), Game1.getSourceRectForStandardTileSheet(Game1.debrisSpriteSheet, 16), Color.White); - } - if (Game1.displayFarmer && Game1.player.ActiveObject != null && Game1.player.ActiveObject.bigCraftable && this.checkBigCraftableBoundariesForFrontLayer() && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) - Game1.drawPlayerHeldObject(Game1.player); - else if (Game1.displayFarmer && Game1.player.ActiveObject != null && ((Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.position.X, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")) || (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")))) - Game1.drawPlayerHeldObject(Game1.player); - if ((Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && (!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool) && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), (int)Game1.player.position.Y - Game1.tileSize * 3 / 5), Game1.viewport.Size) != null && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) - Game1.drawTool(Game1.player); - if (Game1.currentLocation.Map.GetLayer("AlwaysFront") != null) - { - Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); - Game1.currentLocation.Map.GetLayer("AlwaysFront").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom); - Game1.mapDisplayDevice.EndScene(); - } - if (Game1.toolHold > 400f && Game1.player.CurrentTool.UpgradeLevel >= 1 && Game1.player.canReleaseTool) - { - Color color = Color.White; - switch ((int)(Game1.toolHold / 600f) + 2) - { - case 1: - color = Tool.copperColor; - break; - case 2: - color = Tool.steelColor; - break; - case 3: - color = Tool.goldColor; - break; - case 4: - color = Tool.iridiumColor; - break; - } - Game1.spriteBatch.Draw(Game1.littleEffect, new Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize) - 2, (int)(Game1.toolHold % 600f * 0.08f) + 4, Game1.tileSize / 8 + 4), Color.Black); - Game1.spriteBatch.Draw(Game1.littleEffect, new Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : Game1.tileSize), (int)(Game1.toolHold % 600f * 0.08f), Game1.tileSize / 8), color); - } - if (Game1.isDebrisWeather && Game1.currentLocation.IsOutdoors && !Game1.currentLocation.ignoreDebrisWeather && !Game1.currentLocation.Name.Equals("Desert") && Game1.viewport.X > -10) - { - foreach (WeatherDebris current6 in Game1.debrisWeather) - current6.draw(Game1.spriteBatch); - } - Game1.farmEvent?.draw(Game1.spriteBatch); - if (Game1.currentLocation.LightLevel > 0f && Game1.timeOfDay < 2000) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * Game1.currentLocation.LightLevel); - if (Game1.screenGlow) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Game1.screenGlowColor * Game1.screenGlowAlpha); - Game1.currentLocation.drawAboveAlwaysFrontLayer(Game1.spriteBatch); - if (Game1.player.CurrentTool is FishingRod && ((Game1.player.CurrentTool as FishingRod).isTimingCast || (Game1.player.CurrentTool as FishingRod).castingChosenCountdown > 0f || (Game1.player.CurrentTool as FishingRod).fishCaught || (Game1.player.CurrentTool as FishingRod).showingTreasure)) - Game1.player.CurrentTool.draw(Game1.spriteBatch); - if (Game1.isRaining && Game1.currentLocation.IsOutdoors && !Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit) && (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2(Game1.viewport.X / Game1.tileSize, Game1.viewport.Y / Game1.tileSize)))) - { - for (int j = 0; j < Game1.rainDrops.Length; j++) - Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[j].position, Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[j].frame), Color.White); - } - - Game1.spriteBatch.End(); - - //base.Draw(gameTime); - - Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.eventUp && Game1.currentLocation.currentEvent != null) - { - foreach (NPC current7 in Game1.currentLocation.currentEvent.actors) - { - if (current7.isEmoting) - { - Vector2 localPosition = current7.getLocalPosition(Game1.viewport); - localPosition.Y -= Game1.tileSize * 2 + Game1.pixelZoom * 3; - if (current7.age == 2) - localPosition.Y += Game1.tileSize / 2; - else if (current7.gender == 1) - localPosition.Y += Game1.tileSize / 6; - Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, localPosition, new Rectangle(current7.CurrentEmoteIndex * (Game1.tileSize / 4) % Game1.emoteSpriteSheet.Width, current7.CurrentEmoteIndex * (Game1.tileSize / 4) / Game1.emoteSpriteSheet.Width * (Game1.tileSize / 4), Game1.tileSize / 4, Game1.tileSize / 4), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, current7.getStandingY() / 10000f); - } - } - } - Game1.spriteBatch.End(); - if (Game1.drawLighting) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, new BlendState - { - ColorBlendFunction = BlendFunction.ReverseSubtract, - ColorDestinationBlend = Blend.One, - ColorSourceBlend = Blend.SourceColor - }, SamplerState.LinearClamp, null, null); - Game1.spriteBatch.Draw(Game1.lightmap, Vector2.Zero, Game1.lightmap.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.lightingQuality, SpriteEffects.None, 1f); - if (Game1.isRaining && Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert)) - { - Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.OrangeRed * 0.45f); - } - Game1.spriteBatch.End(); - } - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - if (Game1.drawGrid) - { - int num2 = -Game1.viewport.X % Game1.tileSize; - float num3 = -(float)Game1.viewport.Y % Game1.tileSize; - for (int k = num2; k < Game1.graphics.GraphicsDevice.Viewport.Width; k += Game1.tileSize) - Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(k, (int)num3, 1, Game1.graphics.GraphicsDevice.Viewport.Height), Color.Red * 0.5f); - for (float num4 = num3; num4 < (float)Game1.graphics.GraphicsDevice.Viewport.Height; num4 += (float)Game1.tileSize) - Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(num2, (int)num4, Game1.graphics.GraphicsDevice.Viewport.Width, 1), Color.Red * 0.5f); - } - if (Game1.currentBillboard != 0) - this.drawBillboard(); - - if ((Game1.displayHUD || Game1.eventUp) && Game1.currentBillboard == 0 && Game1.gameMode == 3 && !Game1.freezeControls && !Game1.panMode) - { - GraphicsEvents.InvokeOnPreRenderHudEvent(this.Monitor); - this.drawHUD(); - GraphicsEvents.InvokeOnPostRenderHudEvent(this.Monitor); - } - else if (Game1.activeClickableMenu == null && Game1.farmEvent == null) - Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2(Game1.getOldMouseX(), Game1.getOldMouseY()), Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16), Color.White, 0f, Vector2.Zero, 4f + Game1.dialogueButtonScale / 150f, SpriteEffects.None, 1f); - - if (Game1.hudMessages.Any() && (!Game1.eventUp || Game1.isFestival())) - { - for (int l = Game1.hudMessages.Count - 1; l >= 0; l--) - Game1.hudMessages[l].draw(Game1.spriteBatch, l); - } - } - Game1.farmEvent?.draw(Game1.spriteBatch); - if (Game1.dialogueUp && !Game1.nameSelectUp && !Game1.messagePause && !(Game1.activeClickableMenu is DialogueBox)) - this.drawDialogueBox(); - if (Game1.progressBar) - { - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle((Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - Game1.tileSize * 2, Game1.dialogueWidth, Game1.tileSize / 2), Color.LightGray); - Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle((Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - Game1.tileSize * 2, (int)(Game1.pauseAccumulator / Game1.pauseTime * Game1.dialogueWidth), Game1.tileSize / 2), Color.DimGray); - } - if (Game1.eventUp) - Game1.currentLocation.currentEvent?.drawAfterMap(Game1.spriteBatch); - if (Game1.isRaining && Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert)) - Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Blue * 0.2f); - if ((Game1.fadeToBlack || Game1.globalFade) && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha)); - else if (Game1.flashAlpha > 0f) - { - if (Game1.options.screenFlash) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.White * Math.Min(1f, Game1.flashAlpha)); - Game1.flashAlpha -= 0.1f; - } - if ((Game1.messagePause || Game1.globalFade) && Game1.dialogueUp) - this.drawDialogueBox(); - foreach (TemporaryAnimatedSprite current8 in Game1.screenOverlayTempSprites) - current8.draw(Game1.spriteBatch, true); - if (Game1.debugMode) - { - Game1.spriteBatch.DrawString(Game1.smallFont, string.Concat(new object[] - { - Game1.panMode ? ((Game1.getOldMouseX() + Game1.viewport.X) / Game1.tileSize + "," + (Game1.getOldMouseY() + Game1.viewport.Y) / Game1.tileSize) : string.Concat("aplayer: ", Game1.player.getStandingX() / Game1.tileSize, ", ", Game1.player.getStandingY() / Game1.tileSize), - Environment.NewLine, - "debugOutput: ", - Game1.debugOutput - }), new Vector2(this.GraphicsDevice.Viewport.TitleSafeArea.X, this.GraphicsDevice.Viewport.TitleSafeArea.Y), Color.Red, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); - } - /*if (inputMode) - { - spriteBatch.DrawString(smallFont, "Input: " + debugInput, new Vector2(tileSize, tileSize * 3), Color.Purple); - }*/ - if (Game1.showKeyHelp) - Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(Game1.tileSize, Game1.viewport.Height - Game1.tileSize - (Game1.dialogueUp ? (Game1.tileSize * 3 + (Game1.isQuestion ? (Game1.questionChoices.Count * Game1.tileSize) : 0)) : 0) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Color.LightGray, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); - - if (Game1.activeClickableMenu != null) - { - GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor); - try - { - Game1.activeClickableMenu.draw(Game1.spriteBatch); - } - catch (Exception ex) - { - this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); - Game1.activeClickableMenu.exitThisMenu(); - } - GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor); - } - else - Game1.farmEvent?.drawAboveEverything(Game1.spriteBatch); - - GraphicsEvents.InvokeOnPostRenderEvent(this.Monitor); - Game1.spriteBatch.End(); - - if (!this.ZoomLevelIsOne) - { - this.GraphicsDevice.SetRenderTarget(null); - this.GraphicsDevice.Clear(this.bgColor); - Game1.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw(this.screenWrapper, Vector2.Zero, this.screenWrapper.Bounds, Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); - Game1.spriteBatch.End(); - } - } - catch (Exception ex) - { - this.Monitor.Log($"An error occured in the overridden draw loop: {ex.GetLogSummary()}", LogLevel.Error); - } - } -#endif /**** ** Methods @@ -1502,7 +1063,6 @@ namespace StardewModdingAPI.Framework /// Detect changes since the last update ticket and trigger mod events. private void UpdateEventCalls() { -#if SDV_1_2 // content locale changed event if (this.PreviousLocale != LocalizedContentManager.CurrentLanguageCode) { @@ -1513,14 +1073,9 @@ namespace StardewModdingAPI.Framework ContentEvents.InvokeAfterLocaleChanged(this.Monitor, oldValue.ToString(), newValue.ToString()); this.PreviousLocale = newValue; } -#endif // save loaded event - if (Constants.IsSaveLoaded -#if SDV_1_2 - && !SaveGame.IsProcessing/*still loading save*/ -#endif - && this.AfterLoadTimer >= 0) + if (Constants.IsSaveLoaded && !SaveGame.IsProcessing/*still loading save*/ && this.AfterLoadTimer >= 0) { if (this.AfterLoadTimer == 0) { diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 424e1727..db4fbfc0 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -16,7 +16,6 @@ using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.Logging; using StardewModdingAPI.Framework.Models; using StardewModdingAPI.Framework.Serialisation; -using StardewValley; using Monitor = StardewModdingAPI.Framework.Monitor; namespace StardewModdingAPI @@ -141,14 +140,7 @@ namespace StardewModdingAPI // override game this.GameInstance = new SGame(this.Monitor); -#if SDV_1_2 StardewValley.Program.gamePtr = this.GameInstance; -#else - { - Type type = typeof(Game1).Assembly.GetType("StardewValley.Program", true); - type.GetField("gamePtr").SetValue(null, this.GameInstance); - } -#endif // hook into game events #if SMAPI_FOR_WINDOWS diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json index ba698d35..9438c621 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.config.json +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -27,10 +27,6 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha * Changing this field is not recommended and may destabilise your game. */ "ModCompatibility": [ - - /**** - ** Stardew Valley 1.2+ only - ****/ { "Name": "AccessChestAnywhere", "ID": "AccessChestAnywhere", @@ -38,94 +34,9 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/257", "UnofficialUpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "Chests Anywhere", - "ID": "ChestsAnywhere", - "UpperVersion": "1.8.2", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "Crashes with 'Method not found: Void StardewValley.Menus.TextBox.set_Highlighted(Boolean)'.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "Chests Anywhere", - "ID": "Pathoschild.ChestsAnywhere", - "UpperVersion": "1.9-beta", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "ID changed in 1.9. Crashes with InvalidOperationException: 'The menu doesn't seem to have a player inventory'.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "CJB Automation", - "ID": "CJBAutomation", - "UpperVersion": "1.4", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/211", - "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "Cooking Skill", - "ID": "CookingSkill", - "UpperVersion": "1.0.3", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/522", - "Notes": "Crashes with 'Method not found: Void StardewValley.Buff..ctor(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, System.String)'.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "Extended Fridge", - "ID": "Mystra007ExtendedFridge", - "UpperVersion": "1.0", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/485", - "Notes": "Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest. Crashes with 'Field not found: StardewValley.Game1.mouseCursorTransparency'.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "Get Dressed", - "ID": "GetDressed.dll", - "UpperVersion": "3.2", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/331", - "Notes": "Crashes with NullReferenceException in GameEvents.UpdateTick.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "Lookup Anything", - "ID": "LookupAnything", - "UpperVersion": "1.10", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", - "Notes": "Crashes with FormatException when looking up NPCs.", - "OnlyStardewValleyBeta": true - }, - { - "Name": "Lookup Anything", - "ID": "Pathoschild.LookupAnything", - "UpperVersion": "1.10.1", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", - "Notes": "ID changed in 1.10.1. Crashes with FormatException when looking up NPCs.", - "OnlyStardewValleyBeta": true + "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." }, { - "Name": "Teleporter", - "ID": "Teleporter", - "UpperVersion": "1.0.2", - "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/resources/4374", - "Notes": "Crashes with 'InvalidOperationException: The StardewValley.Menus.MapPage object doesn't have a private 'points' instance field'.", - "OnlyStardewValleyBeta": true - }, - - /**** - ** Any version of Stardew Valley - ****/ { "Name": "Almighty Tool", "ID": "AlmightyTool.dll", "UpperVersion": "1.1.1", @@ -157,6 +68,30 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/242", "Notes": "Not compatible with Stardew Valley 1.1+" }, + { + "Name": "Chests Anywhere", + "ID": "ChestsAnywhere", + "UpperVersion": "1.8.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "Notes": "Crashes with 'Method not found: Void StardewValley.Menus.TextBox.set_Highlighted(Boolean)'." + }, + { + "Name": "Chests Anywhere", + "ID": "Pathoschild.ChestsAnywhere", + "UpperVersion": "1.9-beta", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", + "Notes": "ID changed in 1.9. Crashes with InvalidOperationException: 'The menu doesn't seem to have a player inventory'." + }, + { + "Name": "CJB Automation", + "ID": "CJBAutomation", + "UpperVersion": "1.4", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/211", + "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." + }, { "Name": "CJB Cheats Menu", "ID": "CJBCheatsMenu", @@ -179,6 +114,14 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", "Notes": "Uses SMAPI's internal SGame class." }, + { + "Name": "Cooking Skill", + "ID": "CookingSkill", + "UpperVersion": "1.0.3", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/522", + "Notes": "Crashes with 'Method not found: Void StardewValley.Buff..ctor(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, System.String)'." + }, { "Name": "Enemy Health Bars", "ID": "SPDHealthBar", @@ -195,6 +138,38 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://community.playstarbound.com/resources/4228", "Notes": "Uses obsolete StardewModdingAPI.Inheritance.SObject until 1.6.1; then crashes until 1.6.4 ('Entoarox Framework requested an immediate game shutdown: Fatal error attempting to update player tick properties System.NullReferenceException: Object reference not set to an instance of an object. at Entoarox.Framework.PlayerHelper.Update(Object s, EventArgs e)')." }, + { + "Name": "Extended Fridge", + "ID": "Mystra007ExtendedFridge", + "UpperVersion": "1.0", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/485", + "Notes": "Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest. Crashes with 'Field not found: StardewValley.Game1.mouseCursorTransparency'." + }, + { + "Name": "Get Dressed", + "ID": "GetDressed.dll", + "UpperVersion": "3.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/331", + "Notes": "Crashes with NullReferenceException in GameEvents.UpdateTick." + }, + { + "Name": "Lookup Anything", + "ID": "LookupAnything", + "UpperVersion": "1.10", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", + "Notes": "Crashes with FormatException when looking up NPCs." + }, + { + "Name": "Lookup Anything", + "ID": "Pathoschild.LookupAnything", + "UpperVersion": "1.10.1", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", + "Notes": "ID changed in 1.10.1. Crashes with FormatException when looking up NPCs." + }, { "Name": "Makeshift Multiplayer", "ID": "StardewValleyMP", @@ -252,6 +227,14 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/683", "Notes": "Crashes with 'Method not found: Void StardewModdingAPI.Command.CallCommand(System.String)'." }, + { + "Name": "Teleporter", + "ID": "Teleporter", + "UpperVersion": "1.0.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/resources/4374", + "Notes": "Crashes with 'InvalidOperationException: The StardewValley.Menus.MapPage object doesn't have a private 'points' instance field'." + }, { "Name": "Zoryn's Better RNG", "ID": "76b6d1e1-f7ba-4d72-8c32-5a1e6d2716f6", -- cgit From fee89a99da3295c6bb35d6543a112db8924057de Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 24 Apr 2017 12:39:06 -0400 Subject: remove new manifest field for minimum game version (#264) This was added to support parallel releases for SDV 1.11 + 1.2-beta, but SDV 1.2 is now out of beta. Mods should specify the minimum SMAPI version instead if needed. --- release-notes.md | 1 - src/StardewModdingAPI/Framework/Manifest.cs | 3 --- src/StardewModdingAPI/IManifest.cs | 3 --- src/StardewModdingAPI/Program.cs | 19 ------------------- 4 files changed, 26 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 1dd1fa6b..d600db57 100644 --- a/release-notes.md +++ b/release-notes.md @@ -25,7 +25,6 @@ For players: For mod developers: * Mods are now initialised after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method. -* Mods can now specify a minimum game version in their `manifest.json`. * Added `IsBetween` and string overloads to the `ISemanticVersion` methods. * Fixed mouse-changed event never updating prior mouse position. * Fixed `monitor.ExitGameImmediately` not working correctly. diff --git a/src/StardewModdingAPI/Framework/Manifest.cs b/src/StardewModdingAPI/Framework/Manifest.cs index f9c90ff6..189da9a8 100644 --- a/src/StardewModdingAPI/Framework/Manifest.cs +++ b/src/StardewModdingAPI/Framework/Manifest.cs @@ -26,9 +26,6 @@ namespace StardewModdingAPI.Framework /// The minimum SMAPI version required by this mod, if any. public string MinimumApiVersion { get; set; } - /// The minimum game version required by this mod, if any. - public string MinimumGameVersion { get; set; } - /// The name of the DLL in the directory that has the method. public string EntryDll { get; set; } diff --git a/src/StardewModdingAPI/IManifest.cs b/src/StardewModdingAPI/IManifest.cs index f73b0c8f..3e4b7513 100644 --- a/src/StardewModdingAPI/IManifest.cs +++ b/src/StardewModdingAPI/IManifest.cs @@ -18,9 +18,6 @@ /// The minimum SMAPI version required by this mod, if any. string MinimumApiVersion { get; set; } - /// The minimum game version required by this mod, if any. - string MinimumGameVersion { get; set; } - /// The unique mod ID. string UniqueID { get; set; } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index db4fbfc0..31aeb3a6 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -460,25 +460,6 @@ namespace StardewModdingAPI } } - // validate game version - if (!string.IsNullOrWhiteSpace(manifest.MinimumGameVersion)) - { - try - { - ISemanticVersion minVersion = new SemanticVersion(manifest.MinimumGameVersion); - if (minVersion.IsNewerThan(Constants.GameVersion)) - { - this.Monitor.Log($"{skippedPrefix} because it needs Stardew Valley {minVersion} or later. Please update Stardew Valley to the latest version to use this mod.", LogLevel.Error); - continue; - } - } - catch (FormatException ex) when (ex.Message.Contains("not a valid semantic version")) - { - this.Monitor.Log($"{skippedPrefix} because it has an invalid minimum game version '{manifest.MinimumApiVersion}'. This should be a semantic version number like {Constants.GameVersion}.", LogLevel.Error); - continue; - } - } - // create per-save directory if (manifest.PerSaveConfigs) { -- cgit