From 0a50cdb162d7ba1c9219d1982dccbb5828b070c3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 14 Nov 2018 18:18:32 -0500 Subject: update multiplayer code for Stardew Valley 1.3.22 (#480) --- src/SMAPI/Framework/Networking/SGalaxyNetServer.cs | 63 ++++++++++++++++++++++ src/SMAPI/Framework/Networking/SLidgrenServer.cs | 59 ++++---------------- 2 files changed, 74 insertions(+), 48 deletions(-) create mode 100644 src/SMAPI/Framework/Networking/SGalaxyNetServer.cs (limited to 'src/SMAPI/Framework/Networking') diff --git a/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs new file mode 100644 index 00000000..2fc92737 --- /dev/null +++ b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs @@ -0,0 +1,63 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Galaxy.Api; +using StardewValley.Network; +using StardewValley.SDKs; + +namespace StardewModdingAPI.Framework.Networking +{ + /// A multiplayer server used to connect to an incoming player. This is an implementation of that adds support for SMAPI's metadata context exchange. + internal class SGalaxyNetServer : GalaxyNetServer + { + /********* + ** Properties + *********/ + /// A callback to raise when receiving a message. This receives the incoming message, a method to send a message, and a callback to run the default logic. + private readonly Action, Action> OnProcessingMessage; + + /// SMAPI's implementation of the game's core multiplayer logic. + private readonly SMultiplayer Multiplayer; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The underlying game server. + /// SMAPI's implementation of the game's core multiplayer logic. + /// A callback to raise when receiving a message. This receives the incoming message, a method to send a message, and a callback to run the default logic. + public SGalaxyNetServer(IGameServer gameServer, SMultiplayer multiplayer, Action, Action> onProcessingMessage) + : base(gameServer) + { + this.Multiplayer = multiplayer; + this.OnProcessingMessage = onProcessingMessage; + } + + /// Read and process a message from the client. + /// The Galaxy peer ID. + /// The data to process. + [SuppressMessage("ReSharper", "AccessToDisposedClosure", Justification = "The callback is invoked synchronously.")] + protected override void onReceiveMessage(GalaxyID peer, Stream messageStream) + { + using (IncomingMessage message = new IncomingMessage()) + using (BinaryReader reader = new BinaryReader(messageStream)) + { + message.Read(reader); + this.OnProcessingMessage(message, outgoing => this.sendMessage(peer, outgoing), () => + { + if (this.peers.ContainsLeft(message.FarmerID) && (long)this.peers[message.FarmerID] == (long)peer.ToUint64()) + { + this.gameServer.processIncomingMessage(message); + } + else if (message.MessageType == StardewValley.Multiplayer.playerIntroduction) + { + NetFarmerRoot farmer = this.Multiplayer.readFarmer(message.Reader); + GalaxyID capturedPeer = new GalaxyID(peer.ToUint64()); + this.gameServer.checkFarmhandRequest(Convert.ToString(peer.ToUint64()), farmer, msg => this.sendMessage(capturedPeer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = capturedPeer.ToUint64()); + } + }); + } + } + } +} diff --git a/src/SMAPI/Framework/Networking/SLidgrenServer.cs b/src/SMAPI/Framework/Networking/SLidgrenServer.cs index 36f96bc3..37e546a1 100644 --- a/src/SMAPI/Framework/Networking/SLidgrenServer.cs +++ b/src/SMAPI/Framework/Networking/SLidgrenServer.cs @@ -1,11 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Reflection; using Lidgren.Network; -using StardewModdingAPI.Framework.Reflection; -using StardewModdingAPI.Patches; -using StardewValley; using StardewValley.Network; namespace StardewModdingAPI.Framework.Networking @@ -16,46 +12,36 @@ namespace StardewModdingAPI.Framework.Networking /********* ** Properties *********/ - - /// The constructor for the internal NetBufferReadStream type. - private readonly ConstructorInfo NetBufferReadStreamConstructor = SLidgrenServer.GetNetBufferReadStreamConstructor(); - - /// A method which reads farmer data from the given binary reader. - private readonly Func ReadFarmer; + /// SMAPI's implementation of the game's core multiplayer logic. + private readonly SMultiplayer Multiplayer; /// A callback to raise when receiving a message. This receives the incoming message, a method to send a message, and a callback to run the default logic. private readonly Action, Action> OnProcessingMessage; - /// The peer connections. - private readonly Bimap Peers; - /********* ** Public methods *********/ /// Construct an instance. + /// SMAPI's implementation of the game's core multiplayer logic. /// The underlying game server. - /// Simplifies access to private code. - /// A method which reads farmer data from the given binary reader. /// A callback to raise when receiving a message. This receives the incoming message, a method to send a message, and a callback to run the default logic. - public SLidgrenServer(IGameServer gameServer, Reflector reflection, Func readFarmer, Action, Action> onProcessingMessage) + public SLidgrenServer(IGameServer gameServer, SMultiplayer multiplayer, Action, Action> onProcessingMessage) : base(gameServer) { - this.ReadFarmer = readFarmer; + this.Multiplayer = multiplayer; this.OnProcessingMessage = onProcessingMessage; - this.Peers = reflection.GetField>(this, "peers").GetValue(); } /// Parse a data message from a client. /// The raw network message to parse. - /// This is an implementation of which calls . This method is invoked via . [SuppressMessage("ReSharper", "AccessToDisposedClosure", Justification = "The callback is invoked synchronously.")] - public bool ParseDataMessageFromClient(NetIncomingMessage rawMessage) + protected override void parseDataMessageFromClient(NetIncomingMessage rawMessage) { // add hook to call multiplayer core NetConnection peer = rawMessage.SenderConnection; using (IncomingMessage message = new IncomingMessage()) - using (Stream readStream = (Stream)this.NetBufferReadStreamConstructor.Invoke(new object[] { rawMessage })) + using (Stream readStream = new NetBufferReadStream(rawMessage)) using (BinaryReader reader = new BinaryReader(readStream)) { while (rawMessage.LengthBits - rawMessage.Position >= 8) @@ -63,39 +49,16 @@ namespace StardewModdingAPI.Framework.Networking message.Read(reader); this.OnProcessingMessage(message, outgoing => this.sendMessage(rawMessage.SenderConnection, outgoing), () => { - if (this.Peers.ContainsLeft(message.FarmerID) && this.Peers[message.FarmerID] == peer) + if (this.peers.ContainsLeft(message.FarmerID) && this.peers[message.FarmerID] == peer) this.gameServer.processIncomingMessage(message); - else if (message.MessageType == Multiplayer.playerIntroduction) + else if (message.MessageType == StardewValley.Multiplayer.playerIntroduction) { - NetFarmerRoot farmer = this.ReadFarmer(message.Reader); - this.gameServer.checkFarmhandRequest("", farmer, msg => this.sendMessage(peer, msg), () => this.Peers[farmer.Value.UniqueMultiplayerID] = peer); + NetFarmerRoot farmer = this.Multiplayer.readFarmer(message.Reader); + this.gameServer.checkFarmhandRequest("", farmer, msg => this.sendMessage(peer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = peer); } }); } } - - return false; - } - - - /********* - ** Private methods - *********/ - /// Get the constructor for the internal NetBufferReadStream type. - private static ConstructorInfo GetNetBufferReadStreamConstructor() - { - // get type - string typeName = $"StardewValley.Network.NetBufferReadStream, {Constants.GameAssemblyName}"; - Type type = Type.GetType(typeName); - if (type == null) - throw new InvalidOperationException($"Can't find type: {typeName}"); - - // get constructor - ConstructorInfo constructor = type.GetConstructor(new[] { typeof(NetBuffer) }); - if (constructor == null) - throw new InvalidOperationException($"Can't find constructor for type: {typeName}"); - - return constructor; } } } -- cgit