コード例 #1
0
ファイル: SMultiplayer.cs プロジェクト: pgsvox/SMAPI
        /// <summary>Process an incoming network message as a farmhand.</summary>
        /// <param name="message">The message to process.</param>
        /// <param name="sendMessage">Send an arbitrary message through the client.</param>
        /// <param name="resume">Resume processing the message using the game's default logic.</param>
        /// <returns>Returns whether the message was handled.</returns>
        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);
            }

            switch (message.MessageType)
            {
            // mod context sync (step 4)
            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);

                // store peer
                MultiplayerPeer peer = new MultiplayerPeer(message.FarmerID, model, 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);
                    return;
                }
コード例 #2
0
ファイル: SMultiplayer.cs プロジェクト: pgsvox/SMAPI
        /// <summary>Process an incoming network message as the host player.</summary>
        /// <param name="message">The message to process.</param>
        /// <param name="sendMessage">A method which sends the given message to the client.</param>
        /// <param name="resume">Process the message using the game's default logic.</param>
        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);
            }

            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 = new MultiplayerPeer(message.FarmerID, model, 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);
                    this.Peers.Remove(message.FarmerID);
                    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 = new MultiplayerPeer(message.FarmerID, null, sendMessage, isHost: false);
                    this.AddPeer(peer, canBeHost: false);
                }

                resume();
                break;

            // handle mod message
            case (byte)MessageType.ModMessage:
                this.ReceiveModMessage(message);
                break;

            default:
                resume();
                break;
            }
        }