From 56ca0f5e81b22eafeaec2c51085a82bda1188121 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 15 Jan 2021 18:48:32 -0500 Subject: add split-screen info to multiplayer peer --- src/SMAPI/Framework/SMultiplayer.cs | 48 +++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'src/SMAPI/Framework/SMultiplayer.cs') diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index 2f89fce9..b2257286 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -196,7 +196,13 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Received context for farmhand {message.FarmerID} running {(model != null ? $"SMAPI {model.ApiVersion} with {model.Mods.Length} mods" : "vanilla")}.", LogLevel.Trace); // store peer - MultiplayerPeer newPeer = new MultiplayerPeer(message.FarmerID, model, sendMessage, isHost: false); + MultiplayerPeer newPeer = new MultiplayerPeer( + playerID: message.FarmerID, + screenID: this.GetScreenId(message.FarmerID), + model: model, + sendMessage: sendMessage, + isHost: false + ); if (this.Peers.ContainsKey(message.FarmerID)) { this.Monitor.Log($"Received mod context from farmhand {message.FarmerID}, but the game didn't see them disconnect. This may indicate issues with the network connection.", LogLevel.Info); @@ -238,7 +244,13 @@ namespace StardewModdingAPI.Framework if (!this.Peers.ContainsKey(message.FarmerID)) { this.Monitor.Log($"Received connection for vanilla player {message.FarmerID}.", LogLevel.Trace); - MultiplayerPeer peer = new MultiplayerPeer(message.FarmerID, null, sendMessage, isHost: false); + MultiplayerPeer peer = new MultiplayerPeer( + playerID: message.FarmerID, + screenID: this.GetScreenId(message.FarmerID), + model: null, + sendMessage: sendMessage, + isHost: false + ); this.AddPeer(peer, canBeHost: false); } @@ -280,7 +292,13 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Received context for {(model?.IsHost == true ? "host" : "farmhand")} {message.FarmerID} running {(model != null ? $"SMAPI {model.ApiVersion} with {model.Mods.Length} mods" : "vanilla")}.", LogLevel.Trace); // store peer - MultiplayerPeer peer = new MultiplayerPeer(message.FarmerID, model, sendMessage, isHost: model?.IsHost ?? this.HostPeer == null); + MultiplayerPeer peer = new MultiplayerPeer( + playerID: message.FarmerID, + screenID: this.GetScreenId(message.FarmerID), + model: model, + sendMessage: sendMessage, + isHost: model?.IsHost ?? this.HostPeer == null + ); if (peer.IsHost && this.HostPeer != null) { this.Monitor.Log($"Rejected mod context from host player {peer.PlayerID}: already received host data from {(peer.PlayerID == this.HostPeer.PlayerID ? "that player" : $"player {peer.PlayerID}")}.", LogLevel.Error); @@ -297,7 +315,14 @@ namespace StardewModdingAPI.Framework if (!this.Peers.ContainsKey(message.FarmerID) && this.HostPeer == null) { this.Monitor.Log($"Received connection for vanilla host {message.FarmerID}.", LogLevel.Trace); - this.AddPeer(new MultiplayerPeer(message.FarmerID, null, sendMessage, isHost: true), canBeHost: false); + var peer = new MultiplayerPeer( + playerID: message.FarmerID, + screenID: this.GetScreenId(message.FarmerID), + model: null, + sendMessage: sendMessage, + isHost: true + ); + this.AddPeer(peer, canBeHost: false); } resume(); break; @@ -309,7 +334,13 @@ namespace StardewModdingAPI.Framework // store peer if (!this.Peers.TryGetValue(message.FarmerID, out MultiplayerPeer peer)) { - peer = new MultiplayerPeer(message.FarmerID, null, sendMessage, isHost: this.HostPeer == null); + peer = new MultiplayerPeer( + playerID: message.FarmerID, + screenID: this.GetScreenId(message.FarmerID), + model: null, + sendMessage: sendMessage, + isHost: this.HostPeer == null + ); this.Monitor.Log($"Received connection for vanilla {(peer.IsHost ? "host" : "farmhand")} {message.FarmerID}.", LogLevel.Trace); this.AddPeer(peer, canBeHost: true); } @@ -505,6 +536,13 @@ namespace StardewModdingAPI.Framework } } + /// Get the screen ID for a given player ID, if the player is local. + /// The player ID to check. + private int? GetScreenId(long playerId) + { + return SGameRunner.Instance.GetScreenId(playerId); + } + /// Get all connected player IDs, including the current player. private IEnumerable GetKnownPlayerIDs() { -- cgit From 516b2fc010ba9a794297ae74b4c5de321ffd0a70 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 17 Jan 2021 14:57:41 -0500 Subject: don't send multiplayer broadcasts to players without SMAPI --- docs/release-notes.md | 1 + src/SMAPI/Framework/SMultiplayer.cs | 34 ++++++++++++---------------------- 2 files changed, 13 insertions(+), 22 deletions(-) (limited to 'src/SMAPI/Framework/SMultiplayer.cs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 8fa1c330..d448c726 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -13,6 +13,7 @@ * Expanded player info received from multiplayer API/events with new `IsSplitScreen` and `ScreenID` fields. * Game errors shown in the chatbox are now logged. * Added an option to disable rewriting mods for compatibility (thanks to Bpendragon!). This may prevent older mods from loading, but bypasses a Visual Studio crash when debugging. + * Network messages through the multiplayer API are no longer sent to players who don't have SMAPI installed. This reduces unneeded network traffic (since they can't read it anyway) and avoids an error in some cases. * For the Error Handler mod: * Added in SMAPI 3.9. This has vanilla error-handling that was previously added by SMAPI directly. That simplifies the core SMAPI logic, and lets players or modders disable it if needed. diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index b2257286..8e18cc09 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -392,34 +392,24 @@ namespace StardewModdingAPI.Framework if (string.IsNullOrWhiteSpace(fromModID)) throw new ArgumentNullException(nameof(fromModID)); - // get target players - long curPlayerId = Game1.player.UniqueMultiplayerID; - bool sendToSelf = false; - List sendToPeers = new List(); - if (toPlayerIDs == null) - { - sendToSelf = true; - sendToPeers.AddRange(this.Peers.Values); - } - else + // get valid peers + var sendToPeers = this.Peers.Values.Where(p => p.HasSmapi).ToList(); + bool sendToSelf = true; + + // filter by player ID + if (toPlayerIDs != null) { - foreach (long id in toPlayerIDs.Distinct()) - { - if (id == curPlayerId) - sendToSelf = true; - else if (this.Peers.TryGetValue(id, out MultiplayerPeer peer) && peer.HasSmapi) - sendToPeers.Add(peer); - } + var ids = new HashSet(toPlayerIDs); + sendToPeers.RemoveAll(peer => !ids.Contains(peer.PlayerID)); + sendToSelf = ids.Contains(Game1.player.UniqueMultiplayerID); } // filter by mod ID if (toModIDs != null) { - HashSet sendToMods = new HashSet(toModIDs, StringComparer.OrdinalIgnoreCase); - if (sendToSelf && toModIDs.All(id => this.ModRegistry.Get(id) == null)) - sendToSelf = false; - - sendToPeers.RemoveAll(peer => peer.Mods.All(mod => !sendToMods.Contains(mod.ID))); + var ids = new HashSet(toModIDs, StringComparer.OrdinalIgnoreCase); + sendToPeers.RemoveAll(peer => peer.Mods.All(mod => !ids.Contains(mod.ID))); + sendToSelf = sendToSelf && toModIDs.Any(id => this.ModRegistry.Get(id) != null); } // validate recipients -- cgit From 342fc80394ac2d1bd67fb1b745b8ddec927fac49 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 20 Jan 2021 23:22:24 -0500 Subject: rewrite C# 9 code not supported in Linux build tools yet --- src/SMAPI.Toolkit/SemanticVersion.cs | 12 ++++++------ src/SMAPI/Framework/SCore.cs | 2 +- src/SMAPI/Framework/SMultiplayer.cs | 4 ++-- src/SMAPI/Framework/Serialization/KeybindConverter.cs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/SMAPI/Framework/SMultiplayer.cs') diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs index d58dce0c..2f3e282b 100644 --- a/src/SMAPI.Toolkit/SemanticVersion.cs +++ b/src/SMAPI.Toolkit/SemanticVersion.cs @@ -293,12 +293,12 @@ namespace StardewModdingAPI.Toolkit return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherPlatformRelease, otherTag).ToString(), StringComparison.OrdinalIgnoreCase); } - return CompareToRaw() switch - { - (< 0) => curOlder, - (> 0) => curNewer, - _ => same - }; + int result = CompareToRaw(); + if (result < 0) + return curOlder; + if (result > 0) + return curNewer; + return same; } /// Assert that the current version is valid. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 1ac361cd..cd094ff4 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -132,7 +132,7 @@ namespace StardewModdingAPI.Framework private readonly ConcurrentQueue RawCommandQueue = new ConcurrentQueue(); /// A list of commands to execute on each screen. - private readonly PerScreen>> ScreenCommandQueue = new(() => new()); + private readonly PerScreen>> ScreenCommandQueue = new PerScreen>>(() => new List>()); /********* diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index 8e18cc09..5956b63f 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -56,10 +56,10 @@ namespace StardewModdingAPI.Framework private readonly bool LogNetworkTraffic; /// The backing field for . - private readonly PerScreen> PeersImpl = new(() => new Dictionary()); + private readonly PerScreen> PeersImpl = new PerScreen>(() => new Dictionary()); /// The backing field for . - private readonly PerScreen HostPeerImpl = new(); + private readonly PerScreen HostPeerImpl = new PerScreen(); /********* diff --git a/src/SMAPI/Framework/Serialization/KeybindConverter.cs b/src/SMAPI/Framework/Serialization/KeybindConverter.cs index 7c5db3ad..93a274a8 100644 --- a/src/SMAPI/Framework/Serialization/KeybindConverter.cs +++ b/src/SMAPI/Framework/Serialization/KeybindConverter.cs @@ -44,7 +44,7 @@ namespace StardewModdingAPI.Framework.Serialization { case JsonToken.Null: return objectType == typeof(Keybind) - ? new Keybind() + ? (object)new Keybind() : new KeybindList(); case JsonToken.String: -- cgit