using System; using System.Collections.Generic; using System.Linq; using Lidgren.Network; using StardewValley.Network; namespace StardewModdingAPI.Framework.Networking { /// Metadata about a connected player. internal class MultiplayerPeer : IMultiplayerPeer { /********* ** Properties *********/ /// The server through which to send messages, if this is an incoming farmhand. private readonly SLidgrenServer Server; /// The client through which to send messages, if this is the host player. private readonly SLidgrenClient Client; /// The network connection to the player. private readonly NetConnection ServerConnection; /********* ** Accessors *********/ /// The player's unique ID. public long PlayerID { get; } /// Whether this is a connection to the host player. public bool IsHost { get; } /// Whether the player has SMAPI installed. public bool HasSmapi => this.ApiVersion != null; /// The player's OS platform, if is true. public GamePlatform? Platform { get; } /// The installed version of Stardew Valley, if is true. public ISemanticVersion GameVersion { get; } /// The installed version of SMAPI, if is true. public ISemanticVersion ApiVersion { get; } /// The installed mods, if is true. public IEnumerable Mods { get; } /********* ** Public methods *********/ /// Construct an instance. /// The player's unique ID. /// The metadata to copy. /// The server through which to send messages. /// The server connection through which to send messages. /// The client through which to send messages. /// Whether this is a connection to the host player. public MultiplayerPeer(long playerID, RemoteContextModel model, SLidgrenServer server, NetConnection serverConnection, SLidgrenClient client, bool isHost) { this.PlayerID = playerID; this.IsHost = isHost; 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; } /// Construct an instance for a connection to an incoming farmhand. /// The player's unique ID. /// The metadata to copy, if available. /// The server through which to send messages. /// The server connection through which to send messages. 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, isHost: false ); } /// Construct an instance for a connection to the host player. /// The player's unique ID. /// The metadata to copy. /// The client through which to send messages. /// Whether this connection is for the host player. public static MultiplayerPeer ForConnectionToHost(long playerID, RemoteContextModel model, SLidgrenClient client, bool isHost) { return new MultiplayerPeer( playerID: playerID, model: model, server: null, serverConnection: null, client: client, isHost: isHost ); } /// Get metadata for a mod installed by the player. /// The unique mod ID. /// Returns the mod info, or null if the player doesn't have that mod. 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)); } /// Send a message to the given peer, bypassing the game's normal validation to allow messages before the connection is approved. /// The message to send. public void SendMessage(OutgoingMessage message) { if (this.IsHost) this.Client.sendMessage(message); else this.Server.SendMessage(this.ServerConnection, message); } } }