/// <summary>A callback raised when sending a network message as the host player.</summary> /// <param name="server">The server sending the message.</param> /// <param name="connection">The connection to which a message is being sent.</param> /// <param name="message">The message being sent.</param> /// <param name="resume">Send the underlying message.</param> protected void OnServerSendingMessage(SLidgrenServer server, NetConnection connection, OutgoingMessage message, Action resume) { if (this.Monitor.IsVerbose) { this.Monitor.Log($"SERVER SEND {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace); } resume(); }
/// <summary>Process an incoming network message as the host player.</summary> /// <param name="server">The server instance that received the connection.</param> /// <param name="rawMessage">The raw network message that was received.</param> /// <param name="message">The message to process.</param> /// <param name="resume">Process the message using the game's default logic.</param> public void OnServerProcessingMessage(SLidgrenServer server, NetIncomingMessage rawMessage, IncomingMessage message, Action resume) { if (this.Monitor.IsVerbose) { this.Monitor.Log($"SERVER RECV {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace); } switch (message.MessageType) { // sync mod context (step 2) 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); // store peer MultiplayerPeer newPeer = MultiplayerPeer.ForConnectionToFarmhand(message.FarmerID, model, server, rawMessage.SenderConnection); if (this.Peers.ContainsKey(message.FarmerID)) { this.Monitor.Log($"Rejected mod context from farmhand {message.FarmerID}: already received context for that player.", LogLevel.Error); return; } this.AddPeer(newPeer, canBeHost: false, raiseEvent: false); // reply with own context this.Monitor.VerboseLog(" Replying with host context..."); newPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModContext, Game1.player.UniqueMultiplayerID, this.GetContextSyncMessageFields())); // reply with other players' context foreach (MultiplayerPeer otherPeer in this.Peers.Values.Where(p => p.PlayerID != newPeer.PlayerID)) { this.Monitor.VerboseLog($" Replying with context for player {otherPeer.PlayerID}..."); newPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModContext, otherPeer.PlayerID, this.GetContextSyncMessageFields(otherPeer))); } // forward to other peers if (this.Peers.Count > 1) { object[] fields = this.GetContextSyncMessageFields(newPeer); foreach (MultiplayerPeer otherPeer in this.Peers.Values.Where(p => p.PlayerID != newPeer.PlayerID)) { this.Monitor.VerboseLog($" Forwarding context to player {otherPeer.PlayerID}..."); otherPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModContext, newPeer.PlayerID, fields)); } } // raise event this.EventManager.PeerContextReceived.Raise(new PeerContextReceivedEventArgs(newPeer)); } break; // handle player intro case (byte)MessageType.PlayerIntroduction: // store peer if new if (!this.Peers.ContainsKey(message.FarmerID)) { this.Monitor.Log($"Received connection for vanilla player {message.FarmerID}.", LogLevel.Trace); MultiplayerPeer peer = MultiplayerPeer.ForConnectionToFarmhand(message.FarmerID, null, server, rawMessage.SenderConnection); this.AddPeer(peer, canBeHost: false); } resume(); break; // handle mod message case (byte)MessageType.ModMessage: this.ReceiveModMessage(message); break; default: resume(); break; } }