summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/Networking/MultiplayerPeer.cs
blob: e97e36bc2534afc0394a48327e803838407d9926 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using System;
using System.Collections.Generic;
using System.Linq;
using Lidgren.Network;
using StardewValley;
using StardewValley.Network;

namespace StardewModdingAPI.Framework.Networking
{
    /// <summary>Metadata about a connected player.</summary>
    internal class MultiplayerPeer : IMultiplayerPeer
    {
        /*********
        ** Properties
        *********/
        /// <summary>The server through which to send messages, if this is an incoming farmhand.</summary>
        private readonly SLidgrenServer Server;

        /// <summary>The client through which to send messages, if this is the host player.</summary>
        private readonly SLidgrenClient Client;

        /// <summary>The network connection to the player.</summary>
        private readonly NetConnection ServerConnection;


        /*********
        ** Accessors
        *********/
        /// <summary>The player's unique ID.</summary>
        public long PlayerID { get; }

        /// <summary>Whether this is a connection to the host player.</summary>
        public bool IsHostPlayer => this.PlayerID == Game1.MasterPlayer.UniqueMultiplayerID;

        /// <summary>Whether the player has SMAPI installed.</summary>
        public bool HasSmapi => this.ApiVersion != null;

        /// <summary>The player's OS platform, if <see cref="HasSmapi"/> is true.</summary>
        public GamePlatform? Platform { get; }

        /// <summary>The installed version of Stardew Valley, if <see cref="HasSmapi"/> is true.</summary>
        public ISemanticVersion GameVersion { get; }

        /// <summary>The installed version of SMAPI, if <see cref="HasSmapi"/> is true.</summary>
        public ISemanticVersion ApiVersion { get; }

        /// <summary>The installed mods, if <see cref="HasSmapi"/> is true.</summary>
        public IEnumerable<IMultiplayerPeerMod> Mods { get; }


        /*********
        ** Public methods
        *********/
        /// <summary>Construct an instance.</summary>
        /// <param name="playerID">The player's unique ID.</param>
        /// <param name="model">The metadata to copy.</param>
        /// <param name="server">The server through which to send messages.</param>
        /// <param name="serverConnection">The server connection through which to send messages.</param>
        /// <param name="client">The client through which to send messages.</param>
        public MultiplayerPeer(long playerID, RemoteContextModel model, SLidgrenServer server, NetConnection serverConnection, SLidgrenClient client)
        {
            this.PlayerID = playerID;
            if (model != null)
            {
                this.Platform = model.Platform;
                this.GameVersion = model.GameVersion;
                this.ApiVersion = model.ApiVersion;
                this.Mods = model.Mods.Select(mod => new MultiplayerPeerMod(mod)).ToArray();
            }
            this.Server = server;
            this.ServerConnection = serverConnection;
            this.Client = client;
        }

        /// <summary>Construct an instance for a connection to an incoming farmhand.</summary>
        /// <param name="playerID">The player's unique ID.</param>
        /// <param name="model">The metadata to copy, if available.</param>
        /// <param name="server">The server through which to send messages.</param>
        /// <param name="serverConnection">The server connection through which to send messages.</param>
        public static MultiplayerPeer ForConnectionToFarmhand(long playerID, RemoteContextModel model, SLidgrenServer server, NetConnection serverConnection)
        {
            return new MultiplayerPeer(
                playerID: playerID,
                model: model,
                server: server,
                serverConnection: serverConnection,
                client: null
            );
        }

        /// <summary>Construct an instance for a connection to the host player.</summary>
        /// <param name="playerID">The player's unique ID.</param>
        /// <param name="model">The metadata to copy.</param>
        /// <param name="client">The client through which to send messages.</param>
        public static MultiplayerPeer ForConnectionToHost(long playerID, RemoteContextModel model, SLidgrenClient client)
        {
            return new MultiplayerPeer(
                playerID: playerID,
                model: model,
                server: null,
                serverConnection: null,
                client: client
            );
        }

        /// <summary>Get metadata for a mod installed by the player.</summary>
        /// <param name="id">The unique mod ID.</param>
        /// <returns>Returns the mod info, or <c>null</c> if the player doesn't have that mod.</returns>
        public IMultiplayerPeerMod GetMod(string id)
        {
            if (string.IsNullOrWhiteSpace(id))
                return null;

            id = id.Trim();
            return this.Mods.FirstOrDefault(mod => mod.ID != null && mod.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase));
        }

        /// <summary>Send a message to the given peer, bypassing the game's normal validation to allow messages before the connection is approved.</summary>
        /// <param name="message">The message to send.</param>
        public void SendMessage(OutgoingMessage message)
        {
            if (this.IsHostPlayer)
                this.Client.sendMessage(message);
            else
                this.Server.SendMessage(this.ServerConnection, message);
        }
    }
}