blob: aa4ecf351a162fd93da239256b27e2d55d67cb0b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
using System.Collections.Generic;
using StardewModdingAPI.Enums;
using StardewModdingAPI.Events;
using StardewModdingAPI.Utilities;
using StardewValley;
using StardewValley.Menus;
namespace StardewModdingAPI
{
/// <summary>Provides information about the current game state.</summary>
public static class Context
{
/*********
** Fields
*********/
/// <summary>Whether the player has loaded a save and the world has finished initializing.</summary>
private static readonly PerScreen<bool> IsWorldReadyForScreen = new();
/// <summary>The current stage in the game's loading process.</summary>
private static readonly PerScreen<LoadStage> LoadStageForScreen = new();
/// <summary>Whether a player save has been loaded.</summary>
internal static bool IsSaveLoaded => Game1.hasLoadedGame && Game1.activeClickableMenu is not TitleMenu;
/// <summary>Whether the game is currently writing to the save file.</summary>
internal static bool IsSaving => Game1.activeClickableMenu is SaveGameMenu or ShippingMenu; // saving is performed by SaveGameMenu, but it's wrapped by ShippingMenu on days when the player shipping something
/// <summary>The active split-screen instance IDs.</summary>
internal static readonly ISet<int> ActiveScreenIds = new HashSet<int>();
/// <summary>The last screen ID that was removed from the game, used to synchronize <see cref="PerScreen{T}"/>.</summary>
internal static int LastRemovedScreenId = -1;
/// <summary>The current stage in the game's loading process.</summary>
internal static LoadStage LoadStage
{
get => Context.LoadStageForScreen.Value;
set => Context.LoadStageForScreen.Value = value;
}
/// <summary>Whether the in-game world is completely unloaded and not in the process of being loaded. The world may still exist in memory at this point, but should be ignored.</summary>
internal static bool IsWorldFullyUnloaded => Context.LoadStage is LoadStage.ReturningToTitle or LoadStage.None;
/*********
** Accessors
*********/
/****
** Game/player state
****/
/// <summary>Whether the game has performed core initialization. This becomes true right before the first update tick.</summary>
public static bool IsGameLaunched { get; internal set; }
/// <summary>Whether the player has loaded a save and the world has finished initializing.</summary>
public static bool IsWorldReady
{
get => Context.IsWorldReadyForScreen.Value;
set => Context.IsWorldReadyForScreen.Value = value;
}
/// <summary>Whether <see cref="IsWorldReady"/> is true and the player is free to act in the world (no menu is displayed, no cutscene is in progress, etc).</summary>
public static bool IsPlayerFree => Context.IsWorldReady && Game1.currentLocation != null && Game1.activeClickableMenu == null && !Game1.dialogueUp && (!Game1.eventUp || Game1.isFestival());
/// <summary>Whether <see cref="IsPlayerFree"/> is true and the player is free to move (e.g. not using a tool).</summary>
public static bool CanPlayerMove => Context.IsPlayerFree && Game1.player.CanMove;
/// <summary>Whether the game is currently running the draw loop. This isn't relevant to most mods, since you should use <see cref="IDisplayEvents"/> events to draw to the screen.</summary>
public static bool IsInDrawLoop { get; internal set; }
/****
** Multiplayer
****/
/// <summary>The unique ID of the current screen in split-screen mode. A screen is always assigned a new ID when it's opened (so a player who quits and rejoins has a new screen ID).</summary>
public static int ScreenId => Game1.game1?.instanceId ?? 0;
/// <summary>Whether the game is running in multiplayer or split-screen mode (regardless of whether any other players are connected). See <see cref="IsSplitScreen"/> and <see cref="HasRemotePlayers"/> for more specific checks.</summary>
public static bool IsMultiplayer => Context.IsSplitScreen || (Context.IsWorldReady && Game1.multiplayerMode != Game1.singlePlayer);
/// <summary>Whether this player is running on the main player's computer. This is true for both the main player and split-screen players.</summary>
public static bool IsOnHostComputer => Context.IsMainPlayer || Context.IsSplitScreen;
/// <summary>Whether the current player is playing in a split-screen. This is only applicable when <see cref="IsOnHostComputer"/> is true, since split-screen players on another computer are just regular remote players.</summary>
public static bool IsSplitScreen => LocalMultiplayer.IsLocalMultiplayer();
/// <summary>Whether there are players connected over the network.</summary>
public static bool HasRemotePlayers => Context.IsMultiplayer && !Game1.hasLocalClientsOnly;
/// <summary>Whether the current player is the main player. This is always true in single-player, and true when hosting in multiplayer.</summary>
public static bool IsMainPlayer => Game1.IsMasterGame && Context.ScreenId == 0 && TitleMenu.subMenu is not FarmhandMenu;
/*********
** Public methods
*********/
/// <summary>Get whether a screen ID is still active.</summary>
/// <param name="id">The screen ID.</param>
public static bool HasScreenId(int id)
{
return Context.ActiveScreenIds.Contains(id);
}
}
}
|