summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-02-02 14:20:41 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-02-02 14:20:41 -0500
commit0a2b15d3c36a0a5db4d8fb6e48b592507dc74c14 (patch)
tree484acd37e5e9ba097425231452aeb6442d620172 /src/SMAPI/Framework
parentbd959442ea4d349ea710a163f2dd23140f360fe0 (diff)
downloadSMAPI-0a2b15d3c36a0a5db4d8fb6e48b592507dc74c14.tar.gz
SMAPI-0a2b15d3c36a0a5db4d8fb6e48b592507dc74c14.tar.bz2
SMAPI-0a2b15d3c36a0a5db4d8fb6e48b592507dc74c14.zip
add support for self-broadcasts, optimize network messages
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r--src/SMAPI/Framework/Networking/ModMessageModel.cs2
-rw-r--r--src/SMAPI/Framework/SMultiplayer.cs84
2 files changed, 58 insertions, 28 deletions
diff --git a/src/SMAPI/Framework/Networking/ModMessageModel.cs b/src/SMAPI/Framework/Networking/ModMessageModel.cs
index 7ee39863..4f694f9c 100644
--- a/src/SMAPI/Framework/Networking/ModMessageModel.cs
+++ b/src/SMAPI/Framework/Networking/ModMessageModel.cs
@@ -21,7 +21,7 @@ namespace StardewModdingAPI.Framework.Networking
/****
** Destination
****/
- /// <summary>The players who should receive the message, or <c>null</c> for all players.</summary>
+ /// <summary>The players who should receive the message.</summary>
public long[] ToPlayerIDs { get; set; }
/// <summary>The mods which should receive the message, or <c>null</c> for all mods.</summary>
diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs
index e04205c8..821c343f 100644
--- a/src/SMAPI/Framework/SMultiplayer.cs
+++ b/src/SMAPI/Framework/SMultiplayer.cs
@@ -338,64 +338,94 @@ namespace StardewModdingAPI.Framework
/// <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)
{
- // validate
+ // validate input
if (message == null)
throw new ArgumentNullException(nameof(message));
if (string.IsNullOrWhiteSpace(messageType))
throw new ArgumentNullException(nameof(messageType));
if (string.IsNullOrWhiteSpace(fromModID))
throw new ArgumentNullException(nameof(fromModID));
- if (!this.Peers.Any())
+
+ // get target players
+ long curPlayerId = Game1.player.UniqueMultiplayerID;
+ bool sendToSelf = false;
+ List<MultiplayerPeer> sendToPeers = new List<MultiplayerPeer>();
+ if (toPlayerIDs == null)
{
- this.Monitor.VerboseLog($"Ignored '{messageType}' broadcast from mod {fromModID}: not connected to any players.");
- return;
+ sendToSelf = true;
+ sendToPeers.AddRange(this.Peers.Values);
}
-
- // filter player IDs
- HashSet<long> playerIDs = null;
- if (toPlayerIDs != null && toPlayerIDs.Any())
+ else
{
- playerIDs = new HashSet<long>(toPlayerIDs);
- playerIDs.RemoveWhere(id => !this.Peers.ContainsKey(id));
- if (!playerIDs.Any())
+ foreach (long id in toPlayerIDs.Distinct())
{
- this.Monitor.VerboseLog($"Ignored '{messageType}' broadcast from mod {fromModID}: none of the specified player IDs are connected.");
- return;
+ if (id == curPlayerId)
+ sendToSelf = true;
+ else if (this.Peers.TryGetValue(id, out MultiplayerPeer peer) && peer.HasSmapi)
+ sendToPeers.Add(peer);
}
}
+ // filter by mod ID
+ if (toModIDs != null)
+ {
+ HashSet<string> sendToMods = new HashSet<string>(toModIDs, StringComparer.InvariantCultureIgnoreCase);
+ if (sendToSelf && toModIDs.All(id => this.ModRegistry.Get(id) == null))
+ sendToSelf = false;
+
+ sendToPeers.RemoveAll(peer => peer.Mods.All(mod => !sendToMods.Contains(mod.ID)));
+ }
+
+ // validate recipients
+ if (!sendToSelf && !sendToPeers.Any())
+ {
+ this.Monitor.VerboseLog($"Ignored '{messageType}' broadcast from mod {fromModID}: none of the specified player IDs can receive this message.");
+ return;
+ }
+
// get data to send
ModMessageModel model = new ModMessageModel(
fromPlayerID: Game1.player.UniqueMultiplayerID,
fromModID: fromModID,
toModIDs: toModIDs,
- toPlayerIDs: playerIDs?.ToArray(),
+ toPlayerIDs: sendToPeers.Select(p => p.PlayerID).ToArray(),
type: messageType,
data: JToken.FromObject(message)
);
string data = JsonConvert.SerializeObject(model, Formatting.None);
- // log message
- if (this.LogNetworkTraffic)
- this.Monitor.Log($"Broadcasting '{messageType}' message: {data}.", LogLevel.Trace);
+ // send self-message
+ if (sendToSelf)
+ {
+ if (this.LogNetworkTraffic)
+ this.Monitor.Log($"Broadcasting '{messageType}' message to self: {data}.", LogLevel.Trace);
+
+ this.OnModMessageReceived(model);
+ }
- // send message
- if (Context.IsMainPlayer)
+ // send message to peers
+ if (sendToPeers.Any())
{
- foreach (MultiplayerPeer peer in this.Peers.Values)
+ if (Context.IsMainPlayer)
{
- if (playerIDs == null || playerIDs.Contains(peer.PlayerID))
+ foreach (MultiplayerPeer peer in sendToPeers)
{
- model.ToPlayerIDs = new[] { peer.PlayerID };
+ if (this.LogNetworkTraffic)
+ this.Monitor.Log($"Broadcasting '{messageType}' message to farmhand {peer.PlayerID}: {data}.", LogLevel.Trace);
+
peer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, peer.PlayerID, data));
}
}
- }
- else if (this.HostPeer != null && this.HostPeer.HasSmapi)
- this.HostPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, this.HostPeer.PlayerID, data));
- else
- this.Monitor.VerboseLog(" Can't send message because no valid connections were found.");
+ else if (this.HostPeer?.HasSmapi == true)
+ {
+ if (this.LogNetworkTraffic)
+ this.Monitor.Log($"Broadcasting '{messageType}' message to host {this.HostPeer.PlayerID}: {data}.", LogLevel.Trace);
+ this.HostPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, this.HostPeer.PlayerID, data));
+ }
+ else
+ this.Monitor.VerboseLog(" Can't send message because no valid connections were found.");
+ }
}