diff options
Diffstat (limited to 'src/SMAPI/Framework/SMultiplayer.cs')
-rw-r--r-- | src/SMAPI/Framework/SMultiplayer.cs | 135 |
1 files changed, 67 insertions, 68 deletions
diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index 5956b63f..e41e7edc 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -56,10 +56,10 @@ namespace StardewModdingAPI.Framework private readonly bool LogNetworkTraffic; /// <summary>The backing field for <see cref="Peers"/>.</summary> - private readonly PerScreen<IDictionary<long, MultiplayerPeer>> PeersImpl = new PerScreen<IDictionary<long, MultiplayerPeer>>(() => new Dictionary<long, MultiplayerPeer>()); + 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 PerScreen<MultiplayerPeer>(); + private readonly PerScreen<MultiplayerPeer?> HostPeerImpl = new(); /********* @@ -69,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; @@ -111,20 +111,20 @@ namespace StardewModdingAPI.Framework { switch (client) { - case LidgrenClient _: + 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 _: + 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); } default: - this.Monitor.Log($"Unknown multiplayer client type: {client.GetType().AssemblyQualifiedName}", LogLevel.Trace); + this.Monitor.Log($"Unknown multiplayer client type: {client.GetType().AssemblyQualifiedName}"); return client; } } @@ -135,20 +135,20 @@ namespace StardewModdingAPI.Framework { switch (server) { - case LidgrenServer _: + 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 _: + 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); } default: - this.Monitor.Log($"Unknown multiplayer server type: {server.GetType().AssemblyQualifiedName}", LogLevel.Trace); + this.Monitor.Log($"Unknown multiplayer server type: {server.GetType().AssemblyQualifiedName}"); return server; } } @@ -160,7 +160,7 @@ namespace StardewModdingAPI.Framework protected void OnClientSendingMessage(OutgoingMessage message, Action<OutgoingMessage> sendMessage, Action resume) { if (this.LogNetworkTraffic) - this.Monitor.Log($"CLIENT SEND {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace); + this.Monitor.Log($"CLIENT SEND {(MessageType)message.MessageType} {message.FarmerID}"); switch (message.MessageType) { @@ -184,7 +184,7 @@ namespace StardewModdingAPI.Framework public void OnServerProcessingMessage(IncomingMessage message, Action<OutgoingMessage> sendMessage, Action resume) { if (this.LogNetworkTraffic) - this.Monitor.Log($"SERVER RECV {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace); + this.Monitor.Log($"SERVER RECV {(MessageType)message.MessageType} {message.FarmerID}"); switch (message.MessageType) { @@ -192,11 +192,11 @@ namespace StardewModdingAPI.Framework case (byte)MessageType.ModContext: { // parse message - 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")}.", LogLevel.Trace); + 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 - MultiplayerPeer newPeer = new MultiplayerPeer( + MultiplayerPeer newPeer = new( playerID: message.FarmerID, screenID: this.GetScreenId(message.FarmerID), model: model, @@ -243,8 +243,8 @@ namespace StardewModdingAPI.Framework // store peer if new if (!this.Peers.ContainsKey(message.FarmerID)) { - this.Monitor.Log($"Received connection for vanilla player {message.FarmerID}.", LogLevel.Trace); - MultiplayerPeer peer = new MultiplayerPeer( + this.Monitor.Log($"Received connection for vanilla player {message.FarmerID}."); + MultiplayerPeer peer = new( playerID: message.FarmerID, screenID: this.GetScreenId(message.FarmerID), model: null, @@ -280,7 +280,7 @@ namespace StardewModdingAPI.Framework public void OnClientProcessingMessage(IncomingMessage message, Action<OutgoingMessage> sendMessage, Action resume) { if (this.LogNetworkTraffic) - this.Monitor.Log($"CLIENT RECV {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace); + this.Monitor.Log($"CLIENT RECV {(MessageType)message.MessageType} {message.FarmerID}"); switch (message.MessageType) { @@ -288,11 +288,11 @@ namespace StardewModdingAPI.Framework case (byte)MessageType.ModContext: { // parse message - 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")}.", LogLevel.Trace); + 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 - MultiplayerPeer peer = new MultiplayerPeer( + MultiplayerPeer peer = new( playerID: message.FarmerID, screenID: this.GetScreenId(message.FarmerID), model: model, @@ -314,7 +314,7 @@ namespace StardewModdingAPI.Framework // store peer if (!this.Peers.ContainsKey(message.FarmerID) && this.HostPeer == null) { - this.Monitor.Log($"Received connection for vanilla host {message.FarmerID}.", LogLevel.Trace); + this.Monitor.Log($"Received connection for vanilla host {message.FarmerID}."); var peer = new MultiplayerPeer( playerID: message.FarmerID, screenID: this.GetScreenId(message.FarmerID), @@ -332,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, @@ -341,7 +341,7 @@ namespace StardewModdingAPI.Framework sendMessage: sendMessage, isHost: this.HostPeer == null ); - this.Monitor.Log($"Received connection for vanilla {(peer.IsHost ? "host" : "farmhand")} {message.FarmerID}.", LogLevel.Trace); + this.Monitor.Log($"Received connection for vanilla {(peer.IsHost ? "host" : "farmhand")} {message.FarmerID}."); this.AddPeer(peer, canBeHost: true); } @@ -365,9 +365,9 @@ 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}", LogLevel.Trace); + this.Monitor.Log($"Player quit: {playerID}"); this.Peers.Remove(playerID); this.EventManager.PeerDisconnected.Raise(new PeerDisconnectedEventArgs(peer)); } @@ -382,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) @@ -420,7 +420,7 @@ namespace StardewModdingAPI.Framework } // get data to send - ModMessageModel model = new ModMessageModel( + ModMessageModel model = new( fromPlayerID: Game1.player.UniqueMultiplayerID, fromModID: fromModID, toModIDs: toModIDs, @@ -434,7 +434,7 @@ namespace StardewModdingAPI.Framework if (sendToSelf) { if (this.LogNetworkTraffic) - this.Monitor.Log($"Broadcasting '{messageType}' message to self: {data}.", LogLevel.Trace); + this.Monitor.Log($"Broadcasting '{messageType}' message to self: {data}."); this.OnModMessageReceived(model); } @@ -447,7 +447,7 @@ namespace StardewModdingAPI.Framework foreach (MultiplayerPeer peer in sendToPeers) { if (this.LogNetworkTraffic) - this.Monitor.Log($"Broadcasting '{messageType}' message to farmhand {peer.PlayerID}: {data}.", LogLevel.Trace); + this.Monitor.Log($"Broadcasting '{messageType}' message to farmhand {peer.PlayerID}: {data}."); peer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, peer.PlayerID, data)); } @@ -455,7 +455,7 @@ namespace StardewModdingAPI.Framework else if (this.HostPeer?.HasSmapi == true) { if (this.LogNetworkTraffic) - this.Monitor.Log($"Broadcasting '{messageType}' message to host {this.HostPeer.PlayerID}: {data}.", LogLevel.Trace); + this.Monitor.Log($"Broadcasting '{messageType}' message to host {this.HostPeer.PlayerID}: {data}."); this.HostPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, this.HostPeer.PlayerID, data)); } @@ -486,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> @@ -504,7 +504,7 @@ namespace StardewModdingAPI.Framework ModMessageModel model = this.JsonHelper.Deserialize<ModMessageModel>(json); HashSet<long> playerIDs = new HashSet<long>(model.ToPlayerIDs ?? this.GetKnownPlayerIDs()); if (this.LogNetworkTraffic) - this.Monitor.Log($"Received message: {json}.", LogLevel.Trace); + this.Monitor.Log($"Received message: {json}."); // notify local mods if (playerIDs.Contains(Game1.player.UniqueMultiplayerID)) @@ -513,12 +513,15 @@ namespace StardewModdingAPI.Framework // forward to other players if (Context.IsMainPlayer && playerIDs.Any(p => p != Game1.player.UniqueMultiplayerID)) { - ModMessageModel newModel = new ModMessageModel(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))); } @@ -544,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 RemoteContextModel - { - 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) }; } @@ -571,21 +572,19 @@ namespace StardewModdingAPI.Framework if (!peer.HasSmapi) return new object[] { "{}" }; - RemoteContextModel model = new RemoteContextModel - { - 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) }; } |