add ContextReceived event (#480)

This commit is contained in:
Jesse Plamondon-Willard 2018-11-04 22:41:31 -05:00
parent bfb4020279
commit 222265816d
6 changed files with 75 additions and 15 deletions

View File

@ -0,0 +1,25 @@
using System;
namespace StardewModdingAPI.Events
{
/// <summary>Event arguments for an <see cref="IMultiplayerEvents.ContextReceived"/> event.</summary>
public class ContextReceivedEventArgs : EventArgs
{
/*********
** Accessors
*********/
/// <summary>The player whose metadata was received.</summary>
public IMultiplayerPeer Peer { get; }
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
/// <param name="peer">The player to whom a connection is being established.</param>
internal ContextReceivedEventArgs(IMultiplayerPeer peer)
{
this.Peer = peer;
}
}
}

View File

@ -5,6 +5,9 @@ namespace StardewModdingAPI.Events
/// <summary>Events raised for multiplayer messages and connections.</summary>
public interface IMultiplayerEvents
{
/// <summary>Raised after the mod context for a player is received. This happens before the game approves the connection, so the player does not yet exist in the game. This is the earliest point where messages can be sent to the player via SMAPI.</summary>
event EventHandler<ContextReceivedEventArgs> ContextReceived;
/// <summary>Raised after a mod message is received over the network.</summary>
event EventHandler<ModMessageReceivedEventArgs> ModMessageReceived;
}

View File

@ -101,6 +101,9 @@ namespace StardewModdingAPI.Framework.Events
/****
** Multiplayer
****/
/// <summary>Raised after the mod context for a player is received. This happens before the game approves the connection, so the player does not yet exist in the game. This is the earliest point where messages can be sent to the player via SMAPI.</summary>
public readonly ManagedEvent<ContextReceivedEventArgs> ContextReceived;
/// <summary>Raised after a mod message is received over the network.</summary>
public readonly ManagedEvent<ModMessageReceivedEventArgs> ModMessageReceived;
@ -380,6 +383,7 @@ namespace StardewModdingAPI.Framework.Events
this.CursorMoved = ManageEventOf<CursorMovedEventArgs>(nameof(IModEvents.Input), nameof(IInputEvents.CursorMoved));
this.MouseWheelScrolled = ManageEventOf<MouseWheelScrolledEventArgs>(nameof(IModEvents.Input), nameof(IInputEvents.MouseWheelScrolled));
this.ContextReceived = ManageEventOf<ContextReceivedEventArgs>(nameof(IModEvents.Multiplayer), nameof(IMultiplayerEvents.ContextReceived));
this.ModMessageReceived = ManageEventOf<ModMessageReceivedEventArgs>(nameof(IModEvents.Multiplayer), nameof(IMultiplayerEvents.ModMessageReceived));
this.InventoryChanged = ManageEventOf<InventoryChangedEventArgs>(nameof(IModEvents.Player), nameof(IPlayerEvents.InventoryChanged));

View File

@ -16,6 +16,13 @@ namespace StardewModdingAPI.Framework.Events
remove => this.EventManager.ModMessageReceived.Remove(value);
}
/// <summary>Raised after the mod context for a player is received. This happens before the game approves the connection, so the player does not yet exist in the game. This is the earliest point where messages can be sent to the player via SMAPI.</summary>
public event EventHandler<ContextReceivedEventArgs> ContextReceived
{
add => this.EventManager.ContextReceived.Add(value);
remove => this.EventManager.ContextReceived.Remove(value);
}
/*********
** Public methods

View File

@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Lidgren.Network;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.Events;
using StardewModdingAPI.Framework.Networking;
using StardewModdingAPI.Framework.Reflection;
@ -186,7 +188,7 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log($"Rejected mod context from farmhand {message.FarmerID}: already received context for that player.", LogLevel.Error);
return;
}
this.Peers[message.FarmerID] = newPeer;
this.AddPeer(newPeer, canBeHost: false, raiseEvent: false);
// reply with own context
this.VerboseLog(" Replying with host context...");
@ -209,20 +211,23 @@ namespace StardewModdingAPI.Framework
otherPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModContext, newPeer.PlayerID, fields));
}
}
// raise event
this.EventManager.ContextReceived.Raise(new ContextReceivedEventArgs(newPeer));
}
break;
// handle player intro
case (byte)MessageType.PlayerIntroduction:
// store peer if new
if (!this.Peers.ContainsKey(message.FarmerID))
{
// get peer
if (!this.Peers.TryGetValue(message.FarmerID, out MultiplayerPeer peer))
{
this.Monitor.Log($"Received connection for vanilla player {message.FarmerID}.", LogLevel.Trace);
this.Peers[message.FarmerID] = peer = MultiplayerPeer.ForConnectionToFarmhand(message.FarmerID, null, server, rawMessage.SenderConnection);
}
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
@ -262,9 +267,7 @@ namespace StardewModdingAPI.Framework
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;
}
this.Peers[message.FarmerID] = peer;
if (peer.IsHost)
this.HostPeer = peer;
this.AddPeer(peer, canBeHost: true);
}
break;
@ -275,7 +278,7 @@ namespace StardewModdingAPI.Framework
if (!this.Peers.ContainsKey(message.FarmerID) && this.HostPeer == null)
{
this.Monitor.Log($"Received connection for vanilla host {message.FarmerID}.", LogLevel.Trace);
this.Peers[message.FarmerID] = MultiplayerPeer.ForConnectionToHost(message.FarmerID, null, client, isHost: true);
this.AddPeer(MultiplayerPeer.ForConnectionToHost(message.FarmerID, null, client, isHost: true), canBeHost: false);
}
resume();
break;
@ -289,10 +292,11 @@ namespace StardewModdingAPI.Framework
{
peer = MultiplayerPeer.ForConnectionToHost(message.FarmerID, null, client, isHost: this.HostPeer == null);
this.Monitor.Log($"Received connection for vanilla {(peer.IsHost ? "host" : "farmhand")} {message.FarmerID}.", LogLevel.Trace);
this.Peers[message.FarmerID] = peer;
if (peer.IsHost)
this.HostPeer = peer;
this.AddPeer(peer, canBeHost: true);
}
resume();
break;
}
// handle mod message
@ -390,6 +394,22 @@ namespace StardewModdingAPI.Framework
/*********
** Private methods
*********/
/// <summary>Save a received peer.</summary>
/// <param name="peer">The peer to add.</param>
/// <param name="canBeHost">Whether to track the peer as the host if applicable.</param>
/// <param name="raiseEvent">Whether to raise the <see cref="Events.EventManager.ContextReceived"/> event.</param>
private void AddPeer(MultiplayerPeer peer, bool canBeHost, bool raiseEvent = true)
{
// store
this.Peers[peer.PlayerID] = peer;
if (canBeHost && peer.IsHost)
this.HostPeer = peer;
// raise event
if (raiseEvent)
this.EventManager.ContextReceived.Raise(new ContextReceivedEventArgs(peer));
}
/// <summary>Read the metadata context for a player.</summary>
/// <param name="reader">The stream reader.</param>
private RemoteContextModel ReadContext(BinaryReader reader)

View File

@ -85,6 +85,7 @@
<Compile Include="Events\ButtonReleasedEventArgs.cs" />
<Compile Include="Events\ChangeType.cs" />
<Compile Include="Events\ContentEvents.cs" />
<Compile Include="Events\ContextReceivedEventArgs.cs" />
<Compile Include="Events\ControlEvents.cs" />
<Compile Include="Events\CursorMovedEventArgs.cs" />
<Compile Include="Events\DayEndingEventArgs.cs" />