diff options
Diffstat (limited to 'src/SMAPI/Framework/SMultiplayer.cs')
-rw-r--r-- | src/SMAPI/Framework/SMultiplayer.cs | 89 |
1 files changed, 43 insertions, 46 deletions
diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index de3c25a5..e41e7edc 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using System.IO; @@ -61,7 +59,7 @@ namespace StardewModdingAPI.Framework private readonly PerScreen<IDictionary<long, MultiplayerPeer>> PeersImpl = new(() => new Dictionary<long, MultiplayerPeer>()); /// <summary>The backing field for <see cref="HostPeer"/>.</summary> - private readonly PerScreen<MultiplayerPeer> HostPeerImpl = new(); + private readonly PerScreen<MultiplayerPeer?> HostPeerImpl = new(); /********* @@ -71,7 +69,7 @@ namespace StardewModdingAPI.Framework public IDictionary<long, MultiplayerPeer> Peers => this.PeersImpl.Value; /// <summary>The metadata for the host player, if the current player is a farmhand.</summary> - public MultiplayerPeer HostPeer + public MultiplayerPeer? HostPeer { get => this.HostPeerImpl.Value; private set => this.HostPeerImpl.Value = value; @@ -115,13 +113,13 @@ namespace StardewModdingAPI.Framework { case LidgrenClient: { - string address = this.Reflection.GetField<string>(client, "address").GetValue(); + string address = this.Reflection.GetField<string?>(client, "address").GetValue() ?? throw new InvalidOperationException("Can't initialize base networking client: no valid address found."); return new SLidgrenClient(address, this.OnClientProcessingMessage, this.OnClientSendingMessage); } case GalaxyNetClient: { - GalaxyID address = this.Reflection.GetField<GalaxyID>(client, "lobbyId").GetValue(); + GalaxyID address = this.Reflection.GetField<GalaxyID?>(client, "lobbyId").GetValue() ?? throw new InvalidOperationException("Can't initialize GOG networking client: no valid address found."); return new SGalaxyNetClient(address, this.OnClientProcessingMessage, this.OnClientSendingMessage); } @@ -139,13 +137,13 @@ namespace StardewModdingAPI.Framework { case LidgrenServer: { - IGameServer gameServer = this.Reflection.GetField<IGameServer>(server, "gameServer").GetValue(); + IGameServer gameServer = this.Reflection.GetField<IGameServer?>(server, "gameServer").GetValue() ?? throw new InvalidOperationException("Can't initialize base networking client: the required 'gameServer' field wasn't found."); return new SLidgrenServer(gameServer, this, this.OnServerProcessingMessage); } case GalaxyNetServer: { - IGameServer gameServer = this.Reflection.GetField<IGameServer>(server, "gameServer").GetValue(); + IGameServer gameServer = this.Reflection.GetField<IGameServer?>(server, "gameServer").GetValue() ?? throw new InvalidOperationException("Can't initialize GOG networking client: the required 'gameServer' field wasn't found."); return new SGalaxyNetServer(gameServer, this, this.OnServerProcessingMessage); } @@ -194,7 +192,7 @@ namespace StardewModdingAPI.Framework case (byte)MessageType.ModContext: { // parse message - RemoteContextModel model = this.ReadContext(message.Reader); + RemoteContextModel? model = this.ReadContext(message.Reader); this.Monitor.Log($"Received context for farmhand {message.FarmerID} running {(model != null ? $"SMAPI {model.ApiVersion} with {model.Mods.Length} mods" : "vanilla")}."); // store peer @@ -290,7 +288,7 @@ namespace StardewModdingAPI.Framework case (byte)MessageType.ModContext: { // parse message - RemoteContextModel model = this.ReadContext(message.Reader); + RemoteContextModel? model = this.ReadContext(message.Reader); 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")}."); // store peer @@ -334,7 +332,7 @@ namespace StardewModdingAPI.Framework case (byte)MessageType.PlayerIntroduction: { // store peer - if (!this.Peers.TryGetValue(message.FarmerID, out MultiplayerPeer peer)) + if (!this.Peers.TryGetValue(message.FarmerID, out MultiplayerPeer? peer)) { peer = new MultiplayerPeer( playerID: message.FarmerID, @@ -367,7 +365,7 @@ namespace StardewModdingAPI.Framework { foreach (long playerID in this.disconnectingFarmers) { - if (this.Peers.TryGetValue(playerID, out MultiplayerPeer peer)) + if (this.Peers.TryGetValue(playerID, out MultiplayerPeer? peer)) { this.Monitor.Log($"Player quit: {playerID}"); this.Peers.Remove(playerID); @@ -384,7 +382,7 @@ namespace StardewModdingAPI.Framework /// <param name="fromModID">The unique ID of the mod sending the message.</param> /// <param name="toModIDs">The mod IDs which should receive the message on the destination computers, or <c>null</c> for all mods. Specifying mod IDs is recommended to improve performance, unless it's a general-purpose broadcast.</param> /// <param name="toPlayerIDs">The <see cref="Farmer.UniqueMultiplayerID" /> values for the players who should receive the message, or <c>null</c> for all players. If you don't need to broadcast to all players, specifying player IDs is recommended to reduce latency.</param> - public void BroadcastModMessage<TMessage>(TMessage message, string messageType, string fromModID, string[] toModIDs, long[] toPlayerIDs) + public void BroadcastModMessage<TMessage>(TMessage message, string messageType, string fromModID, string[]? toModIDs, long[]? toPlayerIDs) { // validate input if (message == null) @@ -488,13 +486,13 @@ namespace StardewModdingAPI.Framework /// <summary>Read the metadata context for a player.</summary> /// <param name="reader">The stream reader.</param> - private RemoteContextModel ReadContext(BinaryReader reader) + private RemoteContextModel? ReadContext(BinaryReader reader) { string data = reader.ReadString(); RemoteContextModel model = this.JsonHelper.Deserialize<RemoteContextModel>(data); return model.ApiVersion != null ? model - : null; // no data available for unmodded players + : null; // no data available for vanilla players } /// <summary>Receive a mod message sent from another player's mods.</summary> @@ -515,12 +513,15 @@ namespace StardewModdingAPI.Framework // forward to other players if (Context.IsMainPlayer && playerIDs.Any(p => p != Game1.player.UniqueMultiplayerID)) { - ModMessageModel newModel = new(model); foreach (long playerID in playerIDs) { - if (playerID != Game1.player.UniqueMultiplayerID && playerID != model.FromPlayerID && this.Peers.TryGetValue(playerID, out MultiplayerPeer peer)) + if (playerID != Game1.player.UniqueMultiplayerID && playerID != model.FromPlayerID && this.Peers.TryGetValue(playerID, out MultiplayerPeer? peer)) { - newModel.ToPlayerIDs = new[] { peer.PlayerID }; + ModMessageModel newModel = new(model) + { + ToPlayerIDs = new[] { peer.PlayerID } + }; + this.Monitor.VerboseLog($" Forwarding message to player {peer.PlayerID}."); peer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, peer.PlayerID, this.JsonHelper.Serialize(newModel, Formatting.None))); } @@ -546,22 +547,20 @@ namespace StardewModdingAPI.Framework /// <summary>Get the fields to include in a context sync message sent to other players.</summary> private object[] GetContextSyncMessageFields() { - RemoteContextModel model = new() - { - IsHost = Context.IsWorldReady && Context.IsMainPlayer, - Platform = Constants.TargetPlatform, - ApiVersion = Constants.ApiVersion, - GameVersion = Constants.GameVersion, - Mods = this.ModRegistry + RemoteContextModel model = new( + isHost: Context.IsWorldReady && Context.IsMainPlayer, + platform: Constants.TargetPlatform, + apiVersion: Constants.ApiVersion, + gameVersion: Constants.GameVersion, + mods: this.ModRegistry .GetAll() - .Select(mod => new RemoteContextModModel - { - ID = mod.Manifest.UniqueID, - Name = mod.Manifest.Name, - Version = mod.Manifest.Version - }) + .Select(mod => new RemoteContextModModel( + id: mod.Manifest.UniqueID, + name: mod.Manifest.Name, + version: mod.Manifest.Version + )) .ToArray() - }; + ); return new object[] { this.JsonHelper.Serialize(model, Formatting.None) }; } @@ -573,21 +572,19 @@ namespace StardewModdingAPI.Framework if (!peer.HasSmapi) return new object[] { "{}" }; - RemoteContextModel model = new() - { - IsHost = peer.IsHost, - Platform = peer.Platform.Value, - ApiVersion = peer.ApiVersion, - GameVersion = peer.GameVersion, - Mods = peer.Mods - .Select(mod => new RemoteContextModModel - { - ID = mod.ID, - Name = mod.Name, - Version = mod.Version - }) + RemoteContextModel model = new( + isHost: peer.IsHost, + platform: peer.Platform.Value, + apiVersion: peer.ApiVersion, + gameVersion: peer.GameVersion, + mods: peer.Mods + .Select(mod => new RemoteContextModModel( + id: mod.ID, + name: mod.Name, + version: mod.Version + )) .ToArray() - }; + ); return new object[] { this.JsonHelper.Serialize(model, Formatting.None) }; } |