Console support

This commit is contained in:
yangzhi 2019-05-06 09:49:38 +08:00
parent 0a17a0e6fd
commit c14ceff074
14 changed files with 1401 additions and 1084 deletions

File diff suppressed because it is too large Load Diff

View File

@ -14,20 +14,9 @@ namespace DllRewrite
{
MethodPatcher mp = new MethodPatcher();
AssemblyDefinition StardewValley = mp.InsertModHooks();
TypeDefinition typeModHooksObject = StardewValley.MainModule.GetType("StardewValley.ModHooks");
TypeDefinition typeObject = StardewValley.MainModule.GetType("StardewValley.Object");
//foreach (MethodDefinition method in typeObject.Methods) {
// if(!method.IsConstructor && method.HasBody)
// {
// var processor = method.Body.GetILProcessor();
// var hook = typeModHooksObject.Methods.FirstOrDefault(m => m.Name == "OnObject_xxx");
// var newInstruction = processor.Create(OpCodes.Callvirt, hook);
// var firstInstruction = method.Body.Instructions[0];
// processor.InsertBefore(firstInstruction, newInstruction);
// }
//}
StardewValley.Write("./StardewValley.dll");
//AssemblyDefinition MonoFramework = mp.InsertMonoHooks();
//MonoFramework.Write("./MonoGame.Framework.dll");
}
}
}

118
src/GameConsole.cs Normal file
View File

@ -0,0 +1,118 @@
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Internal.ConsoleWriting;
using StardewValley;
using StardewValley.Menus;
namespace StardewModdingAPI
{
class GameConsole : IClickableMenu
{
public static GameConsole Instance;
public bool IsVisible;
private readonly LinkedList<KeyValuePair<ConsoleLogLevel, string>> _consoleMessageQueue = new LinkedList<KeyValuePair<ConsoleLogLevel, string>>();
private readonly TextBox Textbox;
private Rectangle TextboxBounds;
private SpriteFont _smallFont;
internal GameConsole()
{
Instance = this;
this.IsVisible = true;
this.Textbox = new TextBox(null, null, Game1.dialogueFont, Game1.textColor)
{
X = 0,
Y = 0,
Width = 1280,
Height = 320
};
this.TextboxBounds = new Rectangle(this.Textbox.X, this.Textbox.Y, this.Textbox.Width, this.Textbox.Height);
}
internal void InitContent(LocalizedContentManager content)
{
this._smallFont = content.Load<SpriteFont>(@"Fonts\SmallFont");
}
public void Show()
{
Game1.activeClickableMenu = this;
this.IsVisible = true;
}
public override void receiveLeftClick(int x, int y, bool playSound = true)
{
if (this.TextboxBounds.Contains(x, y))
{
this.Textbox.OnEnterPressed += sender => { SGame.instance.CommandQueue.Enqueue(sender.Text); this.Textbox.Text = ""; };
Game1.keyboardDispatcher.Subscriber = this.Textbox;
typeof(TextBox).GetMethod("ShowAndroidKeyboard", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(this.Textbox, new object[] { });
}
else
{
Game1.activeClickableMenu = null;
this.IsVisible = false;
}
}
public void WriteLine(string consoleMessage, ConsoleLogLevel level)
{
lock (this._consoleMessageQueue)
{
this._consoleMessageQueue.AddFirst(new KeyValuePair<ConsoleLogLevel, string>(level, consoleMessage));
if (this._consoleMessageQueue.Count > 2000)
{
this._consoleMessageQueue.RemoveLast();
}
}
}
public override void draw(SpriteBatch spriteBatch)
{
Vector2 size = this._smallFont.MeasureString("aA");
float y = Game1.game1.screen.Height - size.Y * 2;
lock (this._consoleMessageQueue)
{
foreach (var log in this._consoleMessageQueue)
{
string text = log.Value;
switch (log.Key)
{
case ConsoleLogLevel.Critical:
case ConsoleLogLevel.Error:
spriteBatch.DrawString(this._smallFont, text, new Vector2(16, y), Color.Red);
break;
case ConsoleLogLevel.Alert:
case ConsoleLogLevel.Warn:
spriteBatch.DrawString(this._smallFont, text, new Vector2(16, y), Color.Orange);
break;
case ConsoleLogLevel.Info:
case ConsoleLogLevel.Success:
spriteBatch.DrawString(this._smallFont, text, new Vector2(16, y), Color.AntiqueWhite);
break;
case ConsoleLogLevel.Debug:
case ConsoleLogLevel.Trace:
spriteBatch.DrawString(this._smallFont, text, new Vector2(16, y), Color.LightGray);
break;
default:
spriteBatch.DrawString(this._smallFont, text, new Vector2(16, y), Color.LightGray);
break;
}
size = this._smallFont.MeasureString(text);
if (y < 0)
{
break;
}
y -= size.Y;
}
}
}
}
}

View File

@ -426,6 +426,7 @@
<Compile Include="Newtonsoft.Json\Utilities\TypeExtensions.cs" />
<Compile Include="Newtonsoft.Json\Utilities\ValidationUtils.cs" />
<Compile Include="Newtonsoft.Json\WriteState.cs" />
<Compile Include="GameConsole.cs" />
<Compile Include="Options\ModOptionsCheckbox.cs" />
<Compile Include="Options\ModOptionsSlider.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -5,6 +5,7 @@ using StardewModdingAPI.Framework;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using StardewModdingAPI;
using StardewValley.Menus;
using StardewValley.Buildings;
using StardewValley.Objects;
@ -21,9 +22,16 @@ namespace SMDroid
/// <summary>SMAPI's content manager.</summary>
private ContentCoordinator ContentCore { get; set; }
public static bool ContextInitialize = true;
public static ModEntry Instance;
public static bool IsHalt = false;
public ModEntry()
{
Instance = this;
new GameConsole();
this.core = new SCore(Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "SMDroid/Mods"), false);
}
public override bool OnGame1_CreateContentManager_Prefix(Game1 game1, IServiceProvider serviceProvider, string rootDirectory, ref LocalizedContentManager __result)
@ -35,7 +43,8 @@ namespace SMDroid
this.ContentCore = new ContentCoordinator(serviceProvider, rootDirectory, Thread.CurrentThread.CurrentUICulture, SGame.ConstructorHack.Monitor, SGame.ConstructorHack.Reflection, SGame.ConstructorHack.JsonHelper, SGame.OnLoadingFirstAsset ?? SGame.ConstructorHack?.OnLoadingFirstAsset);
this.NextContentManagerIsMain = true;
__result = this.ContentCore.CreateGameContentManager("Game1._temporaryContent");
this.core.RunInteractively(this.ContentCore);
ContextInitialize = true;
this.core.RunInteractively(this.ContentCore, __result);
return false;
}
// Game1.content initialising from LoadContent
@ -43,6 +52,8 @@ namespace SMDroid
{
this.NextContentManagerIsMain = false;
__result = this.ContentCore.MainContentManager;
GameConsole.Instance.InitContent(__result);
ContextInitialize = false;
return false;
}

View File

@ -62,7 +62,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
public override T Load<T>(string assetName, LanguageCode language)
{
// raise first-load callback
if (GameContentManager.IsFirstLoad)
if (!SMDroid.ModEntry.ContextInitialize && GameContentManager.IsFirstLoad)
{
GameContentManager.IsFirstLoad = false;
this.OnLoadingFirstAsset();

View File

@ -146,6 +146,10 @@ namespace StardewModdingAPI.Framework
this.ConsoleWriter.WriteLine(consoleMessage, level);
});
}
else if (this.ShowTraceInConsole || level != ConsoleLogLevel.Trace)
{
GameConsole.Instance.WriteLine(consoleMessage, level);
}
// write to log file
this.LogFile.WriteLine(fullMessage);

View File

@ -31,11 +31,5 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{
warpFarmer(locationName, tileX, tileY, facingDirectionAfterWarp, false, true, false);
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public static new void warpFarmer(string locationName, int tileX, int tileY, int facingDirectionAfterWarp, bool isStructure)
{
warpFarmer(locationName, tileX, tileY, facingDirectionAfterWarp, isStructure, true, false);
}
}
}

View File

@ -11,10 +11,12 @@ using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
#if SMAPI_FOR_WINDOWS
using System.Windows.Forms;
#endif
using Newtonsoft.Json;
using SMDroid;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.Events;
using StardewModdingAPI.Framework.Exceptions;
@ -159,6 +161,7 @@ namespace StardewModdingAPI.Framework
// init logging
this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info);
this.Monitor.Log($"SMDroid 1.4.0 for Stardew Valley Android release {MainActivity.instance.GetBuild()}", LogLevel.Info);
this.Monitor.Log($"Mods go here: {modsPath}", LogLevel.Info);
if (modsPath != Constants.DefaultModsPath)
this.Monitor.Log("(Using custom --mods-path argument.)", LogLevel.Trace);
@ -181,7 +184,6 @@ namespace StardewModdingAPI.Framework
// add more leniant assembly resolvers
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => AssemblyLoader.ResolveAssembly(e.Name);
SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper, this.InitialiseBeforeFirstAssetLoaded);
// validate platform
//#if SMAPI_FOR_WINDOWS
// if (Constants.Platform != Platform.Windows)
@ -202,7 +204,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Launch SMAPI.</summary>
[HandleProcessCorruptedStateExceptions, SecurityCritical] // let try..catch handle corrupted state exceptions
public void RunInteractively(ContentCoordinator contentCore)
public void RunInteractively(ContentCoordinator contentCore, LocalizedContentManager contentManager)
{
// initialise SMAPI
try
@ -244,7 +246,6 @@ namespace StardewModdingAPI.Framework
new ObjectErrorPatch(),
new LoadForNewGamePatch(this.Reflection, this.GameInstance.OnLoadStageChanged)
);
//// add exit handler
//new Thread(() =>
//{
@ -309,8 +310,8 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log($"You have SMAPI for developers, so the console will be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info);
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);
//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);
this.Monitor.VerboseLog("Verbose logging enabled.");
// update window titles
@ -365,6 +366,9 @@ namespace StardewModdingAPI.Framework
return;
}
this.GameInstance.IsSuspended = true;
new Thread(() =>
{
// load mod data
ModToolkit toolkit = new ModToolkit();
ModDatabase modDatabase = toolkit.GetModDatabase(Constants.ApiMetadataPath);
@ -404,7 +408,9 @@ namespace StardewModdingAPI.Framework
// check for updates
//this.CheckForUpdatesAsync(mods);
}
GameConsole.Instance.IsVisible = false;
this.GameInstance.IsSuspended = false;
}).Start();
// update window titles
//int modsLoaded = this.ModRegistry.GetAll().Count();
//Game1.game1.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods";

View File

@ -14,6 +14,7 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endif
using Netcode;
using SMDroid;
using StardewModdingAPI.Enums;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.Events;
@ -96,6 +97,11 @@ namespace StardewModdingAPI.Framework
internal bool OnCommonStaticHook_Prefix(string hookName, ref object param1, ref object param2, ref object param3, ref object param4, ref object param5, ref object __result)
{
if (hookName == "StardewValley.Game1.saveWholeBackup" || hookName == "StardewValley.Game1.MakeFullBackup")
{
this.Events.Saving.RaiseEmpty();
return true;
}
foreach (IMod mod in this.HookReceiver)
{
if (!mod.OnCommonStaticHook_Prefix(hookName, ref param1, ref param2, ref param3, ref param4, ref param5, ref __result))
@ -108,6 +114,11 @@ namespace StardewModdingAPI.Framework
internal bool OnCommonStaticHook_Postfix(string hookName, ref object param1, ref object param2, ref object param3, ref object param4, ref object param5, ref bool __state, ref object __result)
{
if (hookName == "StardewValley.Game1.saveWholeBackup" || hookName == "StardewValley.Game1.MakeFullBackup")
{
this.Events.Saved.RaiseEmpty();
return true;
}
foreach (IMod mod in this.HookReceiver)
{
mod.OnCommonStaticHook_Postfix(hookName, ref param1, ref param2, ref param3, ref param4, ref param5, ref __state, ref __result);
@ -222,6 +233,7 @@ namespace StardewModdingAPI.Framework
public List<IMod> HookReceiver = new List<IMod>();
public bool IsSuspended;
/*********
@ -266,7 +278,7 @@ namespace StardewModdingAPI.Framework
//Game1.hooks = new SModHooks(this.OnNewDayAfterFade);
// init observables
//Game1.locations = new ObservableCollection<GameLocation>();
Game1.locations = new ObservableCollection<GameLocation>();
SGame.instance = this;
}
@ -307,16 +319,6 @@ namespace StardewModdingAPI.Framework
this.Events.DayEnding.RaiseEmpty();
}
public void Update_Postfix(GameTime time)
{
this.Events.UnvalidatedUpdateTicked.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_UnvalidatedUpdateTick.Raise();
#endif
if (this.validTicking)
this.Events.UpdateTicked.RaiseEmpty();
}
/// <summary>A callback invoked when a mod message is received.</summary>
/// <param name="message">The message to deliver to applicable mods.</param>
private void OnModMessageReceived(ModMessageModel message)
@ -384,6 +386,17 @@ namespace StardewModdingAPI.Framework
/// <param name="gameTime">A snapshot of the game timing state.</param>
public bool Update(GameTime gameTime)
{
if (this.IsSuspended)
{
if (Game1.graphics.GraphicsDevice != null)
{
this.Reflection.GetMethod(Game1.game1, "_updateAudioEngine").Invoke();
this.Reflection.GetMethod(Game1.game1, "_updateOptionsAndToggleFullScreen").Invoke();
this.Reflection.GetMethod(Game1.game1, "_updateInput").Invoke();
}
ModEntry.IsHalt = true;
return true;
}
var events = this.Events;
this.validTicking = false;
try
@ -810,6 +823,7 @@ namespace StardewModdingAPI.Framework
if (optionsPage != null)
{
List<OptionsElement> options = this.Reflection.GetField<List<OptionsElement>>(optionsPage, "options").GetValue();
options.Insert(0, new OptionsButton("Console", () => GameConsole.Instance.Show()));
foreach (IModMetadata modMetadata in this.ModRegistry.GetAll())
{
if(modMetadata.Mod != null)
@ -1081,6 +1095,20 @@ namespace StardewModdingAPI.Framework
return true;
}
public void Update_Postfix(GameTime time)
{
if (this.IsSuspended)
return;
if (ModEntry.IsHalt)
ModEntry.IsHalt = false;
this.Events.UnvalidatedUpdateTicked.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_UnvalidatedUpdateTick.Raise();
#endif
if (this.validTicking)
this.Events.UpdateTicked.RaiseEmpty();
}
/// <summary>The method called to draw everything to the screen.</summary>
/// <param name="gameTime">A snapshot of the game timing state.</param>
public bool Draw(GameTime gameTime, RenderTarget2D toBuffer)
@ -1088,6 +1116,19 @@ namespace StardewModdingAPI.Framework
Context.IsInDrawLoop = true;
try
{
if (GameConsole.Instance.IsVisible)
{
Game1.game1.GraphicsDevice.SetRenderTarget(Game1.game1.screen);
Game1.game1.GraphicsDevice.Clear(Color.Black);
Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, null);
GameConsole.Instance.draw(Game1.spriteBatch);
Game1.spriteBatch.End();
Game1.game1.GraphicsDevice.SetRenderTarget(null);
Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, null, null);
Game1.spriteBatch.Draw(Game1.game1.screen, Vector2.Zero, new Rectangle?(Game1.game1.screen.Bounds), Color.White, 0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f);
Game1.spriteBatch.End();
return false;
}
this._draw(gameTime, null);
this.DrawCrashTimer.Reset();
}
@ -1187,6 +1228,8 @@ namespace StardewModdingAPI.Framework
SpriteText.drawStringWithScrollCenteredAt(Game1.spriteBatch, Game1.content.LoadString("Strings\\UI:please_wait"), Game1.game1.GraphicsDevice.Viewport.Width / 2, Game1.game1.GraphicsDevice.Viewport.Height / 2, "", 1f, -1, 0, 0.088f, false);
Game1.spriteBatch.End();
}
return;
}
else
{
@ -1277,15 +1320,14 @@ namespace StardewModdingAPI.Framework
_spriteBatchEnd.Invoke();
Game1.RestoreViewportAndZoom();
}
return;
}
else
{
Game1.game1.GraphicsDevice.Clear(bgColor.GetValue());
if (((Game1.activeClickableMenu != null) && Game1.options.showMenuBackground) && Game1.activeClickableMenu.showWithoutTransparencyIfOptionIsSet())
{
Matrix matrix = Matrix.CreateScale((float)1f);
Matrix value = Matrix.CreateScale(1f);
Game1.SetSpriteBatchBeginNextID("C");
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, new Matrix?(matrix));
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, new Matrix?(value));
events.Rendering.RaiseEmpty();
try
{
@ -1320,28 +1362,25 @@ namespace StardewModdingAPI.Framework
Game1.overlayMenu.draw(Game1.spriteBatch);
_spriteBatchEnd.Invoke();
}
return;
}
else
{
Matrix? nullable;
if (Game1.emergencyLoading)
{
if (!Game1.SeenConcernedApeLogo)
{
Game1.SetSpriteBatchBeginNextID("E");
nullable = null;
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, nullable);
if (Game1.logoFadeTimer < 0x1388)
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, null);
if (Game1.logoFadeTimer < 5000)
{
Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(0, 0, Game1.viewport.Width, Game1.viewport.Height), Color.White);
}
if (Game1.logoFadeTimer > 0x1194)
if (Game1.logoFadeTimer > 4500)
{
float num = Math.Min((float)1f, (float)(((float)(Game1.logoFadeTimer - 0x1194)) / 500f));
Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(0, 0, Game1.viewport.Width, Game1.viewport.Height), Color.Black * num);
float scale = Math.Min((float)1f, (float)(((float)(Game1.logoFadeTimer - 4500)) / 500f));
Game1.spriteBatch.Draw(Game1.staminaRect, new Rectangle(0, 0, Game1.viewport.Width, Game1.viewport.Height), Color.Black * scale);
}
Game1.spriteBatch.Draw(Game1.titleButtonsTexture, new Vector2((float)(Game1.viewport.Width / 2), (float)((Game1.viewport.Height / 2) - 90)), new Rectangle(0xab + ((((Game1.logoFadeTimer / 100) % 2) == 0) ? 0x6f : 0), 0x137, 0x6f, 60), Color.White * ((Game1.logoFadeTimer < 500) ? (((float)Game1.logoFadeTimer) / 500f) : ((Game1.logoFadeTimer > 0x1194) ? (1f - (((float)(Game1.logoFadeTimer - 0x1194)) / 500f)) : 1f)), 0f, Vector2.Zero, (float)3f, SpriteEffects.None, 0.2f);
Game1.spriteBatch.Draw(Game1.titleButtonsTexture, new Vector2((float)((Game1.viewport.Width / 2) - 0x105), (float)((Game1.viewport.Height / 2) - 0x66)), new Rectangle((((Game1.logoFadeTimer / 100) % 2) == 0) ? 0x55 : 0, 0x132, 0x55, 0x45), Color.White * ((Game1.logoFadeTimer < 500) ? (((float)Game1.logoFadeTimer) / 500f) : ((Game1.logoFadeTimer > 0x1194) ? (1f - (((float)(Game1.logoFadeTimer - 0x1194)) / 500f)) : 1f)), 0f, Vector2.Zero, (float)3f, SpriteEffects.None, 0.2f);
Game1.spriteBatch.Draw(Game1.titleButtonsTexture, new Vector2((float)(Game1.viewport.Width / 2), (float)((Game1.viewport.Height / 2) - 90)), new Rectangle(171 + ((((Game1.logoFadeTimer / 100) % 2) == 0) ? 111 : 0), 311, 111, 60), Color.White * ((Game1.logoFadeTimer < 500) ? (((float)Game1.logoFadeTimer) / 500f) : ((Game1.logoFadeTimer > 4500) ? (1f - (((float)(Game1.logoFadeTimer - 0x1194)) / 500f)) : 1f)), 0f, Vector2.Zero, (float)3f, SpriteEffects.None, 0.2f);
Game1.spriteBatch.Draw(Game1.titleButtonsTexture, new Vector2((float)((Game1.viewport.Width / 2) - 261), (float)((Game1.viewport.Height / 2) - 102)), new Rectangle((((Game1.logoFadeTimer / 100) % 2) == 0) ? 85 : 0, 306, 85, 69), Color.White * ((Game1.logoFadeTimer < 500) ? (((float)Game1.logoFadeTimer) / 500f) : ((Game1.logoFadeTimer > 4500) ? (1f - (((float)(Game1.logoFadeTimer - 0x1194)) / 500f)) : 1f)), 0f, Vector2.Zero, (float)3f, SpriteEffects.None, 0.2f);
_spriteBatchEnd.Invoke();
}
Game1.logoFadeTimer -= gameTime.ElapsedGameTime.Milliseconds;
@ -1359,8 +1398,9 @@ namespace StardewModdingAPI.Framework
events.Legacy_OnPostRenderEvent.Raise();
#endif
_spriteBatchEnd.Invoke();
return;
}
else if (Game1.currentMinigame != null)
if (Game1.currentMinigame != null)
{
Game1.currentMinigame.draw(Game1.spriteBatch);
if ((Game1.globalFade && !Game1.menuUp) && (!Game1.nameSelectUp || Game1.messagePause))
@ -1375,16 +1415,36 @@ namespace StardewModdingAPI.Framework
this.RaisePostRender(needsNewBatch: true);
#endif
renderScreenBuffer.Invoke(BlendState.AlphaBlend);
if (((Game1.currentMinigame is FishingGame) || (Game1.currentMinigame is FantasyBoardGame)) && (Game1.activeClickableMenu != null))
if (Game1.currentMinigame is FishingGame && Game1.activeClickableMenu != null)
{
Game1.SetSpriteBatchBeginNextID("A-A");
SpriteBatchBegin.Invoke(1f);
Game1.activeClickableMenu.draw(Game1.spriteBatch);
_spriteBatchEnd.Invoke();
drawOverlays.Invoke(Game1.spriteBatch);
return;
}
if (Game1.currentMinigame is FantasyBoardGame && Game1.activeClickableMenu != null)
{
if (Game1.IsActiveClickableMenuNativeScaled)
{
Game1.BackupViewportAndZoom(true);
Game1.SetSpriteBatchBeginNextID("A1");
SpriteBatchBegin.Invoke(Game1.NativeZoomLevel);
Game1.activeClickableMenu.draw(Game1.spriteBatch);
_spriteBatchEnd.Invoke();
Game1.RestoreViewportAndZoom();
return;
}
Game1.BackupViewportAndZoom(false);
Game1.SetSpriteBatchBeginNextID("A2");
SpriteBatchBegin.Invoke(1f);
Game1.activeClickableMenu.draw(Game1.spriteBatch);
_spriteBatchEnd.Invoke();
Game1.RestoreViewportAndZoom();
}
}
else if (Game1.showingEndOfNightStuff)
if (Game1.showingEndOfNightStuff)
{
renderScreenBuffer.Invoke(BlendState.Opaque);
Game1.BackupViewportAndZoom(true);
@ -1418,8 +1478,9 @@ namespace StardewModdingAPI.Framework
_spriteBatchEnd.Invoke();
drawOverlays.Invoke(Game1.spriteBatch);
Game1.RestoreViewportAndZoom();
return;
}
else if ((Game1.gameMode == 6) || ((Game1.gameMode == 3) && (Game1.currentLocation == null)))
if ((Game1.gameMode == 6) || ((Game1.gameMode == 3) && (Game1.currentLocation == null)))
{
events.Rendering.RaiseEmpty();
DrawLoadingDotDotDot.Invoke(gameTime);
@ -1437,9 +1498,8 @@ namespace StardewModdingAPI.Framework
_spriteBatchEnd.Invoke();
}
//base.Draw(gameTime);
return;
}
else
{
byte batchOpens = 0; // used for rendering event
if (Game1.gameMode == 0)
{
@ -1462,8 +1522,7 @@ namespace StardewModdingAPI.Framework
Game1.game1.GraphicsDevice.SetRenderTarget(Game1.lightmap);
Game1.game1.GraphicsDevice.Clear(Color.White * 0f);
Game1.SetSpriteBatchBeginNextID("K");
nullable = null;
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, null, nullable);
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, null, null);
if (++batchOpens == 1)
events.Rendering.RaiseEmpty();
Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, Game1.currentLocation.Name.StartsWith("UndergroundMine") ? Game1.mine.getLightingColor(gameTime) : ((!Game1.ambientLight.Equals(Color.White) && (!RainManager.Instance.isRaining || (!Game1.currentLocation.IsOutdoors))) ? Game1.ambientLight : Game1.outdoorLight));
@ -1483,8 +1542,7 @@ namespace StardewModdingAPI.Framework
}
Game1.game1.GraphicsDevice.Clear(bgColor.GetValue());
Game1.SetSpriteBatchBeginNextID("L");
nullable = null;
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, nullable);
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, null);
if (++batchOpens == 1)
events.Rendering.RaiseEmpty();
events.RenderingWorld.RaiseEmpty();
@ -1495,13 +1553,13 @@ namespace StardewModdingAPI.Framework
Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch);
try
{
Game1.currentLocation.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, 4);
Game1.currentLocation?.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, 4);
}
catch (KeyNotFoundException exception)
{
CheckToReloadGameLocationAfterDrawFail.Invoke("Back", exception);
}
Game1.currentLocation.drawWater(Game1.spriteBatch);
Game1.currentLocation?.drawWater(Game1.spriteBatch);
_farmerShadows.GetValue().Clear();
if (((Game1.currentLocation.currentEvent != null) && !Game1.currentLocation.currentEvent.isFestival) && (Game1.currentLocation.currentEvent.farmerActors.Count > 0))
{
@ -1513,7 +1571,7 @@ namespace StardewModdingAPI.Framework
}
}
}
else
else if(Game1.currentLocation != null)
{
foreach (Farmer farmer2 in Game1.currentLocation.farmers)
{
@ -1523,7 +1581,7 @@ namespace StardewModdingAPI.Framework
}
}
}
if (!Game1.currentLocation.shouldHideCharacters())
if (Game1.currentLocation != null && !Game1.currentLocation.shouldHideCharacters())
{
if (Game1.CurrentEvent == null)
{
@ -1555,22 +1613,21 @@ namespace StardewModdingAPI.Framework
}
try
{
Game1.currentLocation.Map.GetLayer("Buildings").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, 4);
Game1.currentLocation?.Map.GetLayer("Buildings").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, 4);
}
catch (KeyNotFoundException exception2)
{
CheckToReloadGameLocationAfterDrawFail.Invoke("Buildings", exception2);
}
Game1.mapDisplayDevice.EndScene();
if (Game1.currentLocation.tapToMove.targetNPC != null)
if (Game1.currentLocation?.tapToMove.targetNPC != null)
{
Game1.spriteBatch.Draw(Game1.mouseCursors, Game1.GlobalToLocal(Game1.viewport, Game1.currentLocation.tapToMove.targetNPC.Position + new Vector2((((float)(Game1.currentLocation.tapToMove.targetNPC.Sprite.SpriteWidth * 4)) / 2f) - 32f, (float)((Game1.currentLocation.tapToMove.targetNPC.GetBoundingBox().Height + (Game1.currentLocation.tapToMove.targetNPC.IsMonster ? 0 : 12)) - 0x20))), new Rectangle(0xc2, 0x184, 0x10, 0x10), Color.White, 0f, Vector2.Zero, (float)4f, SpriteEffects.None, 0.58f);
}
_spriteBatchEnd.Invoke();
Game1.SetSpriteBatchBeginNextID("M");
nullable = null;
_spriteBatchBegin.Invoke(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, nullable);
if (!Game1.currentLocation.shouldHideCharacters())
_spriteBatchBegin.Invoke(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, null);
if (Game1.currentLocation != null && !Game1.currentLocation.shouldHideCharacters())
{
if (Game1.CurrentEvent == null)
{
@ -1600,6 +1657,9 @@ namespace StardewModdingAPI.Framework
}
}
}
if (Game1.currentLocation != null)
{
if ((Game1.eventUp || Game1.killScreen) && (!Game1.killScreen && (Game1.currentLocation.currentEvent != null)))
{
Game1.currentLocation.currentEvent.draw(Game1.spriteBatch);
@ -1644,10 +1704,12 @@ namespace StardewModdingAPI.Framework
{
DrawTapToMoveTarget.Invoke();
}
}
_spriteBatchEnd.Invoke();
Game1.SetSpriteBatchBeginNextID("N");
nullable = null;
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, nullable);
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, null);
if (Game1.currentLocation != null)
{
if (((Game1.displayFarmer && (Game1.player.ActiveObject != null)) && ((Game1.player.ActiveObject.bigCraftable != null) && Game1.game1.checkBigCraftableBoundariesForFrontLayer())) && (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null))
{
Game1.drawPlayerHeldObject(Game1.player);
@ -1722,11 +1784,11 @@ namespace StardewModdingAPI.Framework
{
RainManager.Instance.Draw(Game1.spriteBatch);
}
}
_spriteBatchEnd.Invoke();
Game1.SetSpriteBatchBeginNextID("O");
nullable = null;
_spriteBatchBegin.Invoke(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, nullable);
if (Game1.eventUp && (Game1.currentLocation.currentEvent != null))
_spriteBatchBegin.Invoke(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, null);
if (Game1.eventUp && (Game1.currentLocation?.currentEvent != null))
{
Game1.currentLocation.currentEvent.drawAboveAlwaysFrontLayer(Game1.spriteBatch);
foreach (NPC npc5 in Game1.currentLocation.currentEvent.actors)
@ -1748,11 +1810,10 @@ namespace StardewModdingAPI.Framework
}
}
_spriteBatchEnd.Invoke();
if (Game1.drawLighting)
if (Game1.drawLighting && Game1.currentLocation != null)
{
Game1.SetSpriteBatchBeginNextID("P");
nullable = null;
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, lightingBlend.GetValue(), SamplerState.LinearClamp, null, null, null, nullable);
_spriteBatchBegin.Invoke(SpriteSortMode.Deferred, lightingBlend.GetValue(), SamplerState.LinearClamp, null, null, null, null);
Game1.spriteBatch.Draw(Game1.lightmap, Vector2.Zero, new Rectangle?(Game1.lightmap.Bounds), Color.White, 0f, Vector2.Zero, (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 1f);
if ((RainManager.Instance.isRaining && (Game1.currentLocation.IsOutdoors)) && !(Game1.currentLocation is Desert))
{
@ -1779,7 +1840,7 @@ namespace StardewModdingAPI.Framework
if (((Game1.displayHUD || Game1.eventUp) && ((Game1.currentBillboard == 0) && (Game1.gameMode == 3))) && ((!Game1.freezeControls && !Game1.panMode) && !Game1.HostPaused))
{
_drawHUD.SetValue(true);
if (Game1.isOutdoorMapSmallerThanViewport())
if (Game1.isOutdoorMapSmallerThanViewport() && Game1.currentLocation != null)
{
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle(0, 0, -Math.Min(Game1.viewport.X, 0x1000), Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Rectangle(-Game1.viewport.X + (Game1.currentLocation.map.Layers[0].LayerWidth * 0x40), 0, Math.Min(0x1000, Game1.graphics.GraphicsDevice.Viewport.Width - (-Game1.viewport.X + (Game1.currentLocation.map.Layers[0].LayerWidth * 0x40))), Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
@ -1943,7 +2004,7 @@ namespace StardewModdingAPI.Framework
DrawHUDMessages.Invoke();
_spriteBatchEnd.Invoke();
}
if (((Game1.CurrentEvent != null) && Game1.CurrentEvent.skippable) && ((Game1.activeClickableMenu == null) || ((Game1.activeClickableMenu != null) && !(Game1.activeClickableMenu is MenuWithInventory))))
if (Game1.CurrentEvent != null && Game1.CurrentEvent.skippable && !Game1.CurrentEvent.skipped && (Game1.activeClickableMenu == null || (Game1.activeClickableMenu != null && !(Game1.activeClickableMenu is MenuWithInventory))))
{
Game1.SetSpriteBatchBeginNextID("A-G");
SpriteBatchBegin.Invoke(Game1.NativeZoomLevel);
@ -1954,9 +2015,6 @@ namespace StardewModdingAPI.Framework
}
}
}
}
}
}
#if !SMAPI_3_0_STRICT
/// <summary>Raise the <see cref="GraphicsEvents.OnPostRenderEvent"/> if there are any listeners.</summary>
/// <param name="needsNewBatch">Whether to create a new sprite batch.</param>

View File

@ -53,9 +53,9 @@ namespace StardewModdingAPI.Framework.StateTracking
/// <summary>Construct an instance.</summary>
/// <param name="locations">The game's list of locations.</param>
/// <param name="activeMineLocations">The game's list of active mine locations.</param>
public WorldLocationsTracker(List<GameLocation> locations, IList<MineShaft> activeMineLocations)
public WorldLocationsTracker(ObservableCollection<GameLocation> locations, IList<MineShaft> activeMineLocations)
{
this.LocationListWatcher = WatcherFactory.ForReferenceList(locations);
this.LocationListWatcher = WatcherFactory.ForObservableCollection(locations);
this.MineLocationListWatcher = WatcherFactory.ForReferenceList(activeMineLocations);
}

View File

@ -65,7 +65,7 @@ namespace StardewModdingAPI.Framework
this.WindowSizeWatcher = WatcherFactory.ForEquatable(() => new Point(Game1.viewport.Width, Game1.viewport.Height));
this.TimeWatcher = WatcherFactory.ForEquatable(() => Game1.timeOfDay);
this.ActiveMenuWatcher = WatcherFactory.ForReference(() => Game1.activeClickableMenu);
this.LocationsWatcher = new WorldLocationsTracker(Game1.locations, MineShaft.activeMines);
this.LocationsWatcher = new WorldLocationsTracker((ObservableCollection<GameLocation>) Game1.locations, MineShaft.activeMines);
this.LocaleWatcher = WatcherFactory.ForGenericEquality(() => LocalizedContentManager.CurrentLanguageCode);
this.Watchers.AddRange(new IWatcher[]
{

View File

@ -37,8 +37,6 @@ namespace StardewModdingAPI.Metadata
// rewrite for Stardew Valley 1.3
yield return new StaticFieldToConstantRewriter<int>(typeof(Game1), "tileSize", Game1.tileSize);
yield return new TypeReferenceRewriter("System.Collections.Generic.IList`1<StardewValley.GameLocation>", typeof(List<GameLocation>));
yield return new TypeReferenceRewriter("System.Collections.Generic.IList`1<StardewValley.Menus.IClickableMenu>", typeof(List<IClickableMenu>));
yield return new FieldToPropertyRewriter(typeof(Game1), "player");
@ -61,11 +59,11 @@ namespace StardewModdingAPI.Metadata
yield return new FieldToPropertyRewriter(typeof(Game1), "isDebrisWeather");
yield return new MethodParentRewriter(typeof(IClickableMenu), typeof(IClickableMenuMethods), onlyIfPlatformChanged: true);
yield return new MethodParentRewriter(typeof(IClickableMenu), typeof(IClickableMenuMethods));
yield return new MethodParentRewriter(typeof(Game1), typeof(Game1Methods), onlyIfPlatformChanged: true);
yield return new MethodParentRewriter(typeof(Game1), typeof(Game1Methods));
yield return new MethodParentRewriter(typeof(Farmer), typeof(FarmerMethods), onlyIfPlatformChanged: true);
yield return new MethodParentRewriter(typeof(Farmer), typeof(FarmerMethods));
/****
** detect mod issues

View File

@ -76,7 +76,7 @@ namespace StardewModdingAPI.Patches
if (LoadForNewGamePatch.IsCreating)
{
// raise CreatedBasicInfo after locations are cleared twice
List<GameLocation> locations = Game1.locations;
IList<GameLocation> locations = Game1.locations;
//locations.CollectionChanged += LoadForNewGamePatch.OnLocationListChanged;
}
@ -90,7 +90,7 @@ namespace StardewModdingAPI.Patches
if (LoadForNewGamePatch.IsCreating)
{
// clean up
List<GameLocation> locations = Game1.locations;
IList<GameLocation> locations = Game1.locations;
//locations.CollectionChanged -= LoadForNewGamePatch.OnLocationListChanged;
// raise stage changed