From 2e8c7e06c5c46834b570b667cb7497fe4cc408ac Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 20 Dec 2020 22:34:59 -0500 Subject: update for split-screen mode This includes splitting GameRunner (the main game instance) from Game1 (now a per-screen game state), adding a PerScreen utility to simplify per-screen values, adding separate per-screen input handling and events, adding new Context fields for split-screen, and logging the screen ID in split-screen mode to distinguish log entries. --- src/SMAPI/Utilities/PerScreen.cs | 79 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/SMAPI/Utilities/PerScreen.cs (limited to 'src/SMAPI/Utilities') diff --git a/src/SMAPI/Utilities/PerScreen.cs b/src/SMAPI/Utilities/PerScreen.cs new file mode 100644 index 00000000..55dae0d8 --- /dev/null +++ b/src/SMAPI/Utilities/PerScreen.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace StardewModdingAPI.Utilities +{ + /// Manages a separate value for each player in split-screen mode. This can safely be used in non-split-screen mode too, it'll just have a single state in that case. + /// The state class. + public class PerScreen + { + /********* + ** Fields + *********/ + /// Create the initial value for a player. + private readonly Func CreateNewState; + + /// The tracked values for each player. + private readonly IDictionary States = new Dictionary(); + + /// The last value for which this instance was updated. + private int LastRemovedScreenId; + + + /********* + ** Accessors + *********/ + /// The value for the current player. + /// The value is initialized the first time it's requested for that player, unless it's set manually first. + public T Value + { + get + { + this.RemoveDeadPlayers(); + return this.States.TryGetValue(Context.ScreenId, out T state) + ? state + : this.States[Context.ScreenId] = this.CreateNewState(); + } + set + { + this.RemoveDeadPlayers(); + this.States[Context.ScreenId] = value; + } + } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public PerScreen() + : this(null) { } + + /// Construct an instance. + /// Create the initial state for a player screen. + public PerScreen(Func createNewState) + { + this.CreateNewState = createNewState ?? (() => default); + } + + + /********* + ** Private methods + *********/ + /// Remove players who are no longer have a split-screen index. + /// Returns whether any players were removed. + private void RemoveDeadPlayers() + { + if (this.LastRemovedScreenId == Context.LastRemovedScreenId) + return; + + this.LastRemovedScreenId = Context.LastRemovedScreenId; + foreach (int id in this.States.Keys.ToArray()) + { + if (!Context.HasScreenId(id)) + this.States.Remove(id); + } + } + } +} -- cgit