(61d00a474) v0.9.7.1
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
abstract class ClientPeer
|
||||
{
|
||||
public delegate void MessageCallback(IReadMessage message);
|
||||
public delegate void DisconnectCallback();
|
||||
public delegate void DisconnectMessageCallback(string message);
|
||||
public delegate void PasswordCallback(int salt, int retries);
|
||||
public delegate void InitializationCompleteCallback();
|
||||
|
||||
public MessageCallback OnMessageReceived;
|
||||
public DisconnectCallback OnDisconnect;
|
||||
public DisconnectMessageCallback OnDisconnectMessageReceived;
|
||||
public PasswordCallback OnRequestPassword;
|
||||
public InitializationCompleteCallback OnInitializationComplete;
|
||||
|
||||
public string Name;
|
||||
|
||||
public string Version { get; protected set; }
|
||||
|
||||
public NetworkConnection ServerConnection { get; protected set; }
|
||||
|
||||
public abstract void Start(object endPoint, int ownerKey);
|
||||
public abstract void Close(string msg = null);
|
||||
public abstract void Update(float deltaTime);
|
||||
public abstract void Send(IWriteMessage msg, DeliveryMethod deliveryMethod);
|
||||
public abstract void SendPassword(string password);
|
||||
|
||||
#if DEBUG
|
||||
public abstract void ForceTimeOut();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using Barotrauma.Steam;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class LidgrenClientPeer : ClientPeer
|
||||
{
|
||||
private bool isActive;
|
||||
private NetClient netClient;
|
||||
private NetPeerConfiguration netPeerConfiguration;
|
||||
|
||||
private ConnectionInitialization initializationStep;
|
||||
private bool contentPackageOrderReceived;
|
||||
private int ownerKey;
|
||||
private int passwordSalt;
|
||||
private Steamworks.AuthTicket steamAuthTicket;
|
||||
List<NetIncomingMessage> incomingLidgrenMessages;
|
||||
|
||||
public LidgrenClientPeer(string name)
|
||||
{
|
||||
ServerConnection = null;
|
||||
|
||||
Name = name;
|
||||
|
||||
netClient = null;
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
public override void Start(object endPoint, int ownerKey)
|
||||
{
|
||||
if (isActive) { return; }
|
||||
|
||||
this.ownerKey = ownerKey;
|
||||
|
||||
contentPackageOrderReceived = false;
|
||||
|
||||
netPeerConfiguration = new NetPeerConfiguration("barotrauma");
|
||||
|
||||
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
|
||||
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
||||
|
||||
netClient = new NetClient(netPeerConfiguration);
|
||||
|
||||
if (SteamManager.IsInitialized)
|
||||
{
|
||||
steamAuthTicket = SteamManager.GetAuthSessionTicket();
|
||||
//TODO: wait for GetAuthSessionTicketResponse_t
|
||||
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
throw new Exception("GetAuthSessionTicket returned null");
|
||||
}
|
||||
}
|
||||
|
||||
incomingLidgrenMessages = new List<NetIncomingMessage>();
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
if (!(endPoint is IPEndPoint ipEndPoint))
|
||||
{
|
||||
throw new InvalidCastException("endPoint is not IPEndPoint");
|
||||
}
|
||||
if (ServerConnection != null)
|
||||
{
|
||||
throw new InvalidOperationException("ServerConnection is not null");
|
||||
}
|
||||
|
||||
netClient.Start();
|
||||
ServerConnection = new LidgrenConnection("Server", netClient.Connect(ipEndPoint), 0)
|
||||
{
|
||||
Status = NetworkConnectionStatus.Connected
|
||||
};
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
if (ownerKey != 0 && (ChildServerRelay.Process?.HasExited ?? true))
|
||||
{
|
||||
Close();
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), TextManager.Get("ServerProcessClosed"));
|
||||
msgBox.Buttons[0].OnClicked += (btn, obj) => { GameMain.MainMenuScreen.Select(); return false; };
|
||||
return;
|
||||
}
|
||||
|
||||
incomingLidgrenMessages.Clear();
|
||||
netClient.ReadMessages(incomingLidgrenMessages);
|
||||
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
|
||||
{
|
||||
if (inc.SenderConnection != (ServerConnection as LidgrenConnection).NetConnection) { continue; }
|
||||
|
||||
switch (inc.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.Data:
|
||||
HandleDataMessage(inc);
|
||||
break;
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
HandleStatusChanged(inc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDataMessage(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
|
||||
//Console.WriteLine(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte);
|
||||
|
||||
if (isConnectionInitializationStep && initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
ReadConnectionInitializationStep(inc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
OnInitializationComplete?.Invoke();
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, ServerConnection);
|
||||
OnMessageReceived?.Invoke(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStatusChanged(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte();
|
||||
switch (status)
|
||||
{
|
||||
case NetConnectionStatus.Disconnected:
|
||||
string disconnectMsg = inc.ReadString();
|
||||
Close(disconnectMsg);
|
||||
OnDisconnectMessageReceived?.Invoke(disconnectMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
|
||||
//Console.WriteLine(step + " " + initializationStep);
|
||||
NetOutgoingMessage outMsg; NetSendResult result;
|
||||
|
||||
switch (step)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
|
||||
outMsg = netClient.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
|
||||
outMsg.Write(Name);
|
||||
outMsg.Write(ownerKey);
|
||||
outMsg.Write(SteamManager.GetSteamID());
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
outMsg.Write((UInt16)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
|
||||
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
|
||||
}
|
||||
|
||||
outMsg.Write(GameMain.Version.ToString());
|
||||
|
||||
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
outMsg.WriteVariableInt32(mpContentPackages.Count());
|
||||
foreach (ContentPackage contentPackage in mpContentPackages)
|
||||
{
|
||||
outMsg.Write(contentPackage.Name);
|
||||
outMsg.Write(contentPackage.MD5hash.Hash);
|
||||
}
|
||||
|
||||
result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send "+initializationStep.ToString()+" message to host: " + result);
|
||||
}
|
||||
break;
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
|
||||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
|
||||
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
|
||||
outMsg = netClient.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
|
||||
|
||||
Int32 cpCount = inc.ReadVariableInt32();
|
||||
List<ContentPackage> serverContentPackages = new List<ContentPackage>();
|
||||
for (int i = 0; i < cpCount; i++)
|
||||
{
|
||||
string hash = inc.ReadString();
|
||||
serverContentPackages.Add(GameMain.Config.SelectedContentPackages.Find(cp => cp.MD5hash.Hash == hash));
|
||||
}
|
||||
|
||||
if (!contentPackageOrderReceived)
|
||||
{
|
||||
GameMain.Config.ReorderSelectedContentPackages(cp => serverContentPackages.Contains(cp) ?
|
||||
serverContentPackages.IndexOf(cp) :
|
||||
serverContentPackages.Count + GameMain.Config.SelectedContentPackages.IndexOf(cp));
|
||||
contentPackageOrderReceived = true;
|
||||
}
|
||||
|
||||
result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send " + initializationStep.ToString() + " message to host: " + result);
|
||||
}
|
||||
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
int retries = 0;
|
||||
if (incomingSalt)
|
||||
{
|
||||
passwordSalt = inc.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = inc.ReadInt32();
|
||||
}
|
||||
OnRequestPassword?.Invoke(passwordSalt, retries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SendPassword(string password)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
NetOutgoingMessage outMsg = netClient.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.Password);
|
||||
byte[] saltedPw = ServerSettings.SaltPassword(Encoding.UTF8.GetBytes(password), passwordSalt);
|
||||
outMsg.Write((byte)saltedPw.Length);
|
||||
outMsg.Write(saltedPw, 0, saltedPw.Length);
|
||||
NetSendResult result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send " + initializationStep.ToString() + " message to host: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
isActive = false;
|
||||
|
||||
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting"));
|
||||
netClient = null;
|
||||
steamAuthTicket?.Cancel(); steamAuthTicket = null;
|
||||
OnDisconnect?.Invoke();
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
NetDeliveryMethod lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Unreliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
break;
|
||||
case DeliveryMethod.Reliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableUnordered;
|
||||
break;
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
|
||||
break;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
netPeerConfiguration.SimulatedDuplicatesChance = GameMain.Client.SimulatedDuplicatesChance;
|
||||
netPeerConfiguration.SimulatedMinimumLatency = GameMain.Client.SimulatedMinimumLatency;
|
||||
netPeerConfiguration.SimulatedRandomLatency = GameMain.Client.SimulatedRandomLatency;
|
||||
netPeerConfiguration.SimulatedLoss = GameMain.Client.SimulatedLoss;
|
||||
#endif
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netClient.CreateMessage();
|
||||
byte[] msgData = new byte[msg.LengthBytes];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
lidgrenMsg.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
NetSendResult result = netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message to host: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public override void ForceTimeOut()
|
||||
{
|
||||
netClient?.ServerConnection?.ForceTimeOut();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+408
@@ -0,0 +1,408 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Barotrauma.Steam;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class SteamP2PClientPeer : ClientPeer
|
||||
{
|
||||
private bool isActive;
|
||||
private UInt64 hostSteamId;
|
||||
private ConnectionInitialization initializationStep;
|
||||
private bool contentPackageOrderReceived;
|
||||
private int passwordSalt;
|
||||
private Steamworks.AuthTicket steamAuthTicket;
|
||||
private double timeout;
|
||||
private double heartbeatTimer;
|
||||
|
||||
private List<IReadMessage> incomingInitializationMessages;
|
||||
private List<IReadMessage> incomingDataMessages;
|
||||
|
||||
public SteamP2PClientPeer(string name)
|
||||
{
|
||||
ServerConnection = null;
|
||||
|
||||
Name = name;
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
public override void Start(object endPoint, int ownerKey)
|
||||
{
|
||||
contentPackageOrderReceived = false;
|
||||
|
||||
steamAuthTicket = SteamManager.GetAuthSessionTicket();
|
||||
//TODO: wait for GetAuthSessionTicketResponse_t
|
||||
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
throw new Exception("GetAuthSessionTicket returned null");
|
||||
}
|
||||
|
||||
if (!(endPoint is UInt64 steamIdEndpoint))
|
||||
{
|
||||
throw new InvalidCastException("endPoint is not UInt64");
|
||||
}
|
||||
|
||||
hostSteamId = steamIdEndpoint;
|
||||
|
||||
Steamworks.SteamNetworking.ResetActions();
|
||||
Steamworks.SteamNetworking.OnP2PSessionRequest = OnIncomingConnection;
|
||||
|
||||
ServerConnection = new SteamP2PConnection("Server", hostSteamId);
|
||||
|
||||
incomingInitializationMessages = new List<IReadMessage>();
|
||||
incomingDataMessages = new List<IReadMessage>();
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.ConnectionStarted);
|
||||
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
timeout = NetworkConnection.TimeoutThreshold;
|
||||
heartbeatTimer = 1.0;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
private void OnIncomingConnection(Steamworks.SteamId steamId)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
if (steamId == hostSteamId) { Steamworks.SteamNetworking.AcceptP2PSessionWithUser(steamId); }
|
||||
}
|
||||
|
||||
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
if (steamId != hostSteamId) { return; }
|
||||
|
||||
timeout = Screen.Selected == GameMain.GameScreen ?
|
||||
NetworkConnection.TimeoutThresholdInGame :
|
||||
NetworkConnection.TimeoutThreshold;
|
||||
|
||||
byte incByte = data[0];
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
|
||||
if (!isServerMessage) { return; }
|
||||
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
ulong low = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8);
|
||||
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8+32);
|
||||
ulong lobbyId = low + (high << 32);
|
||||
|
||||
Steam.SteamManager.JoinLobby(lobbyId, false);
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 1+8, dataLength - 9, ServerConnection);
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
incomingInitializationMessages.Add(inc);
|
||||
}
|
||||
}
|
||||
else if (isHeartbeatMessage)
|
||||
{
|
||||
return; //TODO: implement heartbeats
|
||||
}
|
||||
else if (isDisconnectMessage)
|
||||
{
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 1, dataLength - 1, ServerConnection);
|
||||
string msg = inc.ReadString();
|
||||
Close(msg);
|
||||
OnDisconnectMessageReceived?.Invoke(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 length = data[1];
|
||||
length |= (UInt16)(((UInt32)data[2]) << 8);
|
||||
|
||||
IReadMessage inc = new ReadOnlyMessage(data, isCompressed, 3, length, ServerConnection);
|
||||
incomingDataMessages.Add(inc);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
timeout -= deltaTime;
|
||||
heartbeatTimer -= deltaTime;
|
||||
|
||||
while (Steamworks.SteamNetworking.IsP2PPacketAvailable())
|
||||
{
|
||||
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
|
||||
if (packet.HasValue)
|
||||
{
|
||||
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (heartbeatTimer < 0.0)
|
||||
{
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Unreliable);
|
||||
outMsg.Write((byte)PacketHeader.IsHeartbeatMessage);
|
||||
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Unreliable);
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
}
|
||||
|
||||
if (timeout < 0.0)
|
||||
{
|
||||
Close("Timed out");
|
||||
OnDisconnectMessageReceived?.Invoke("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
if (incomingDataMessages.Count > 0)
|
||||
{
|
||||
OnInitializationComplete?.Invoke();
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IReadMessage inc in incomingInitializationMessages)
|
||||
{
|
||||
ReadConnectionInitializationStep(inc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (initializationStep == ConnectionInitialization.Success)
|
||||
{
|
||||
foreach (IReadMessage inc in incomingDataMessages)
|
||||
{
|
||||
OnMessageReceived?.Invoke(inc);
|
||||
}
|
||||
}
|
||||
|
||||
incomingInitializationMessages.Clear();
|
||||
incomingDataMessages.Clear();
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(IReadMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
IWriteMessage outMsg;
|
||||
|
||||
//DebugConsole.NewMessage(step + " " + initializationStep);
|
||||
switch (step)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
|
||||
outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
|
||||
outMsg.Write(Name);
|
||||
outMsg.Write(SteamManager.GetSteamID());
|
||||
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
|
||||
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
|
||||
|
||||
outMsg.Write(GameMain.Version.ToString());
|
||||
|
||||
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count());
|
||||
foreach (ContentPackage contentPackage in mpContentPackages)
|
||||
{
|
||||
outMsg.Write(contentPackage.Name);
|
||||
outMsg.Write(contentPackage.MD5hash.Hash);
|
||||
}
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
break;
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
|
||||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
|
||||
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
|
||||
outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
|
||||
|
||||
UInt32 cpCount = inc.ReadVariableUInt32();
|
||||
List<ContentPackage> serverContentPackages = new List<ContentPackage>();
|
||||
for (int i = 0; i < cpCount; i++)
|
||||
{
|
||||
string hash = inc.ReadString();
|
||||
serverContentPackages.Add(GameMain.Config.SelectedContentPackages.Find(cp => cp.MD5hash.Hash == hash));
|
||||
}
|
||||
|
||||
if (!contentPackageOrderReceived)
|
||||
{
|
||||
GameMain.Config.ReorderSelectedContentPackages(cp => serverContentPackages.Contains(cp) ?
|
||||
serverContentPackages.IndexOf(cp) :
|
||||
serverContentPackages.Count + GameMain.Config.SelectedContentPackages.IndexOf(cp));
|
||||
contentPackageOrderReceived = true;
|
||||
}
|
||||
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
int retries = 0;
|
||||
if (incomingSalt)
|
||||
{
|
||||
passwordSalt = inc.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = inc.ReadInt32();
|
||||
}
|
||||
OnRequestPassword?.Invoke(passwordSalt, retries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
byte[] buf = new byte[msg.LengthBytes + 4];
|
||||
buf[0] = (byte)deliveryMethod;
|
||||
|
||||
byte[] bufAux = new byte[msg.LengthBytes];
|
||||
bool isCompressed; int length;
|
||||
msg.PrepareForSending(ref bufAux, out isCompressed, out length);
|
||||
|
||||
buf[1] = (byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None);
|
||||
|
||||
buf[2] = (byte)(length & 0xff);
|
||||
buf[3] = (byte)((length >> 8) & 0xff);
|
||||
|
||||
Array.Copy(bufAux, 0, buf, 4, length);
|
||||
|
||||
Steamworks.P2PSend sendType;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Reliable:
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
//the documentation seems to suggest that the Reliable send type
|
||||
//enforces packet order (TODO: verify)
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
break;
|
||||
default:
|
||||
sendType = Steamworks.P2PSend.Unreliable;
|
||||
break;
|
||||
}
|
||||
|
||||
if (length + 8 >= MsgConstants.MTU)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message length comes close to exceeding MTU, forcing reliable send (" + length.ToString() + " bytes)");
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
}
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
|
||||
#if DEBUG
|
||||
CoroutineManager.InvokeAfter(() =>
|
||||
{
|
||||
if (GameMain.Client == null) { return; }
|
||||
if (Rand.Range(0.0f, 1.0f) < GameMain.Client.SimulatedLoss && sendType != Steamworks.P2PSend.Reliable) { return; }
|
||||
int count = Rand.Range(0.0f, 1.0f) < GameMain.Client.SimulatedDuplicatesChance ? 2 : 1;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Send(buf, length + 4, sendType);
|
||||
}
|
||||
},
|
||||
GameMain.Client.SimulatedMinimumLatency + Rand.Range(0.0f, GameMain.Client.SimulatedRandomLatency));
|
||||
#else
|
||||
Send(buf, length + 4, sendType);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void Send(byte[] buf, int length, Steamworks.P2PSend sendType)
|
||||
{
|
||||
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
|
||||
if (!successSend)
|
||||
{
|
||||
if (sendType != Steamworks.P2PSend.Reliable)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + length.ToString() + " bytes)");
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
|
||||
}
|
||||
if (!successSend)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to send message to remote peer! (" + length.ToString() + " bytes)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void SendPassword(string password)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.Password);
|
||||
byte[] saltedPw = ServerSettings.SaltPassword(Encoding.UTF8.GetBytes(password), passwordSalt);
|
||||
outMsg.Write((byte)saltedPw.Length);
|
||||
outMsg.Write(saltedPw, 0, saltedPw.Length);
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
SteamManager.LeaveLobby();
|
||||
|
||||
isActive = false;
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsDisconnectMessage);
|
||||
outMsg.Write(msg ?? "Disconnected");
|
||||
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
Steamworks.SteamNetworking.ResetActions();
|
||||
|
||||
Steamworks.SteamNetworking.CloseP2PSessionWithUser(hostSteamId);
|
||||
|
||||
steamAuthTicket?.Cancel(); steamAuthTicket = null;
|
||||
hostSteamId = 0;
|
||||
|
||||
OnDisconnect?.Invoke();
|
||||
}
|
||||
|
||||
~SteamP2PClientPeer()
|
||||
{
|
||||
OnDisconnect = null;
|
||||
Close();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public override void ForceTimeOut()
|
||||
{
|
||||
timeout = 0.0f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+446
@@ -0,0 +1,446 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Barotrauma.Steam;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class SteamP2POwnerPeer : ClientPeer
|
||||
{
|
||||
private bool isActive;
|
||||
|
||||
private ConnectionInitialization initializationStep;
|
||||
private UInt64 selfSteamID;
|
||||
|
||||
class RemotePeer
|
||||
{
|
||||
public UInt64 SteamID;
|
||||
public double? DisconnectTime;
|
||||
public bool Authenticating;
|
||||
public bool Authenticated;
|
||||
|
||||
public class UnauthedMessage
|
||||
{
|
||||
public DeliveryMethod DeliveryMethod;
|
||||
public IWriteMessage Message;
|
||||
}
|
||||
public List<UnauthedMessage> UnauthedMessages;
|
||||
|
||||
public RemotePeer(UInt64 steamId)
|
||||
{
|
||||
SteamID = steamId;
|
||||
DisconnectTime = null;
|
||||
Authenticating = false;
|
||||
Authenticated = false;
|
||||
|
||||
UnauthedMessages = new List<UnauthedMessage>();
|
||||
}
|
||||
|
||||
}
|
||||
List<RemotePeer> remotePeers;
|
||||
|
||||
public SteamP2POwnerPeer(string name)
|
||||
{
|
||||
ServerConnection = null;
|
||||
|
||||
Name = name;
|
||||
|
||||
isActive = false;
|
||||
|
||||
selfSteamID = Steam.SteamManager.GetSteamID();
|
||||
}
|
||||
|
||||
public override void Start(object endPoint, int ownerKey)
|
||||
{
|
||||
if (isActive) { return; }
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
ServerConnection = new PipeConnection();
|
||||
ServerConnection.Status = NetworkConnectionStatus.Connected;
|
||||
|
||||
remotePeers = new List<RemotePeer>();
|
||||
|
||||
Steamworks.SteamNetworking.ResetActions();
|
||||
Steamworks.SteamNetworking.OnP2PSessionRequest = OnIncomingConnection;
|
||||
Steamworks.SteamUser.OnValidateAuthTicketResponse += OnAuthChange;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
private void OnAuthChange(Steamworks.SteamId steamID, Steamworks.SteamId ownerID, Steamworks.AuthResponse status)
|
||||
{
|
||||
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamID);
|
||||
DebugConsole.Log(steamID + " validation: " + status + ", " + (remotePeer != null));
|
||||
|
||||
if (remotePeer == null) { return; }
|
||||
|
||||
if (remotePeer.Authenticated)
|
||||
{
|
||||
if (status != Steamworks.AuthResponse.OK)
|
||||
{
|
||||
DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication status changed: " + status.ToString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == Steamworks.AuthResponse.OK)
|
||||
{
|
||||
remotePeer.Authenticated = true;
|
||||
remotePeer.Authenticating = false;
|
||||
foreach (var msg in remotePeer.UnauthedMessages)
|
||||
{
|
||||
byte[] msgToSend = (byte[])msg.Message.Buffer.Clone();
|
||||
Array.Resize(ref msgToSend, msg.Message.LengthBytes);
|
||||
ChildServerRelay.Write(msgToSend);
|
||||
}
|
||||
remotePeer.UnauthedMessages.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication failed: " + status.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIncomingConnection(Steamworks.SteamId steamId)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
if (!remotePeers.Any(p => p.SteamID == steamId))
|
||||
{
|
||||
remotePeers.Add(new RemotePeer(steamId));
|
||||
}
|
||||
|
||||
Steamworks.SteamNetworking.AcceptP2PSessionWithUser(steamId); //accept all connections, the server will figure things out later
|
||||
}
|
||||
|
||||
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamId);
|
||||
if (remotePeer == null || remotePeer.DisconnectTime != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write(steamId);
|
||||
outMsg.Write(data, 1, dataLength - 1);
|
||||
|
||||
DeliveryMethod deliveryMethod = (DeliveryMethod)data[0];
|
||||
|
||||
byte incByte = data[1];
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
|
||||
if (!remotePeer.Authenticated)
|
||||
{
|
||||
if (!remotePeer.Authenticating)
|
||||
{
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
remotePeer.DisconnectTime = null;
|
||||
|
||||
IReadMessage authMsg = new ReadOnlyMessage(data, isCompressed, 2, dataLength - 2, null);
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)authMsg.ReadByte();
|
||||
//Console.WriteLine("received init step from "+steamId.ToString()+" ("+initializationStep.ToString()+")");
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
|
||||
{
|
||||
remotePeer.Authenticating = true;
|
||||
|
||||
authMsg.ReadString(); //skip name
|
||||
authMsg.ReadUInt64(); //skip steamid
|
||||
UInt16 ticketLength = authMsg.ReadUInt16();
|
||||
byte[] ticket = authMsg.ReadBytes(ticketLength);
|
||||
|
||||
Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
|
||||
if (authSessionStartState != Steamworks.BeginAuthResult.OK)
|
||||
{
|
||||
DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam auth session failed to start: " + authSessionStartState.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remotePeer.Authenticating)
|
||||
{
|
||||
remotePeer.UnauthedMessages.Add(new RemotePeer.UnauthedMessage() { DeliveryMethod = deliveryMethod, Message = outMsg });
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
|
||||
Array.Resize(ref msgToSend, outMsg.LengthBytes);
|
||||
ChildServerRelay.Write(msgToSend);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
if (ChildServerRelay.HasShutDown || (ChildServerRelay.Process?.HasExited ?? true))
|
||||
{
|
||||
Close();
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), TextManager.Get("ServerProcessClosed"));
|
||||
msgBox.Buttons[0].OnClicked += (btn, obj) => { GameMain.MainMenuScreen.Select(); return false; };
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = remotePeers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (remotePeers[i].DisconnectTime != null && remotePeers[i].DisconnectTime < Timing.TotalTime)
|
||||
{
|
||||
ClosePeerSession(remotePeers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
while (Steamworks.SteamNetworking.IsP2PPacketAvailable())
|
||||
{
|
||||
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
|
||||
if (packet.HasValue)
|
||||
{
|
||||
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
while (ChildServerRelay.Read(out byte[] incBuf))
|
||||
{
|
||||
ChildServerRelay.DisposeLocalHandles();
|
||||
|
||||
IReadMessage inc = new ReadOnlyMessage(incBuf, false, 0, incBuf.Length, ServerConnection);
|
||||
|
||||
HandleDataMessage(inc);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDataMessage(IReadMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
UInt64 recipientSteamId = inc.ReadUInt64();
|
||||
DeliveryMethod deliveryMethod = (DeliveryMethod)inc.ReadByte();
|
||||
|
||||
int p2pDataStart = inc.BytePosition;
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
|
||||
if (recipientSteamId != selfSteamID)
|
||||
{
|
||||
if (!isServerMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received non-server message meant for remote peer");
|
||||
return;
|
||||
}
|
||||
|
||||
RemotePeer peer = remotePeers.Find(p => p.SteamID == recipientSteamId);
|
||||
|
||||
if (peer == null) { return; }
|
||||
|
||||
if (isDisconnectMessage)
|
||||
{
|
||||
DisconnectPeer(peer, inc.ReadString());
|
||||
return;
|
||||
}
|
||||
|
||||
Steamworks.P2PSend sendType;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Reliable:
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
//the documentation seems to suggest that the Reliable send type
|
||||
//enforces packet order (TODO: verify)
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
break;
|
||||
default:
|
||||
sendType = Steamworks.P2PSend.Unreliable;
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] p2pData;
|
||||
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
p2pData = new byte[inc.LengthBytes - p2pDataStart + 8];
|
||||
p2pData[0] = inc.Buffer[p2pDataStart];
|
||||
Lidgren.Network.NetBitWriter.WriteUInt64(SteamManager.CurrentLobbyID, 64, p2pData, 8);
|
||||
Array.Copy(inc.Buffer, p2pDataStart+1, p2pData, 9, inc.LengthBytes - p2pDataStart - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p2pData = new byte[inc.LengthBytes - p2pDataStart];
|
||||
Array.Copy(inc.Buffer, p2pDataStart, p2pData, 0, p2pData.Length);
|
||||
}
|
||||
|
||||
if (p2pData.Length + 4 >= MsgConstants.MTU)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message length comes close to exceeding MTU, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
}
|
||||
|
||||
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
|
||||
|
||||
if (!successSend)
|
||||
{
|
||||
if (sendType != Steamworks.P2PSend.Reliable)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
|
||||
}
|
||||
if (!successSend)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to send message to remote peer! (" + p2pData.Length.ToString() + " bytes)");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDisconnectMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received disconnect message from owned server");
|
||||
return;
|
||||
}
|
||||
if (!isServerMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received non-server message from owned server");
|
||||
return;
|
||||
}
|
||||
if (isHeartbeatMessage)
|
||||
{
|
||||
return; //timeout is handled by Lidgren, ignore this message
|
||||
}
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write(selfSteamID);
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep));
|
||||
outMsg.Write(Name);
|
||||
|
||||
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
|
||||
Array.Resize(ref msgToSend, outMsg.LengthBytes);
|
||||
ChildServerRelay.Write(msgToSend);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
OnInitializationComplete?.Invoke();
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, ServerConnection);
|
||||
OnMessageReceived?.Invoke(msg);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisconnectPeer(RemotePeer peer, string msg)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
if (peer.DisconnectTime == null)
|
||||
{
|
||||
peer.DisconnectTime = Timing.TotalTime + 1.0;
|
||||
}
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)(PacketHeader.IsServerMessage | PacketHeader.IsDisconnectMessage));
|
||||
outMsg.Write(msg);
|
||||
|
||||
Steamworks.SteamNetworking.SendP2PPacket(peer.SteamID, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClosePeerSession(peer);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClosePeerSession(RemotePeer peer)
|
||||
{
|
||||
Steamworks.SteamNetworking.CloseP2PSessionWithUser(peer.SteamID);
|
||||
remotePeers.Remove(peer);
|
||||
}
|
||||
|
||||
public override void SendPassword(string password)
|
||||
{
|
||||
return; //owner doesn't send passwords
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
isActive = false;
|
||||
|
||||
for (int i = remotePeers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
DisconnectPeer(remotePeers[i], msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
for (int i = remotePeers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
ClosePeerSession(remotePeers[i]);
|
||||
}
|
||||
|
||||
ChildServerRelay.ShutDown();
|
||||
|
||||
OnDisconnect?.Invoke();
|
||||
|
||||
SteamManager.LeaveLobby();
|
||||
Steamworks.SteamNetworking.ResetActions();
|
||||
Steamworks.SteamUser.OnValidateAuthTicketResponse -= OnAuthChange;
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
IWriteMessage msgToSend = new WriteOnlyMessage();
|
||||
byte[] msgData = new byte[msg.LengthBytes];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
msgToSend.Write(selfSteamID);
|
||||
msgToSend.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
|
||||
msgToSend.Write((UInt16)length);
|
||||
msgToSend.Write(msgData, 0, length);
|
||||
|
||||
byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
|
||||
Array.Resize(ref bufToSend, msgToSend.LengthBytes);
|
||||
ChildServerRelay.Write(bufToSend);
|
||||
}
|
||||
|
||||
~SteamP2POwnerPeer()
|
||||
{
|
||||
OnDisconnect = null;
|
||||
Close();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public override void ForceTimeOut()
|
||||
{
|
||||
//TODO: reimplement?
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user