using System.Net; using System.Net.Sockets; using Prospect.Unreal.Core; using Prospect.Unreal.Exceptions; using Prospect.Unreal.Net.Packets.Control; namespace Prospect.Unreal.Net; public class UIpConnection : UNetConnection { public const int IpHeaderSize = 20; public const int UdpHeaderSize = IpHeaderSize + 8; /// /// Cached time of the first send socket error that will be used to compute disconnect delay. /// private double _socketErrorSendDelayStartTime; /// /// Cached time of the first recv socket error that will be used to compute disconnect delay. /// private double _socketErrorRecvDelayStartTime; public UdpClient? Socket { get; private set; } public override void InitBase(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) { base.InitBase(inDriver, inSocket, inURL, inState, (inMaxPacket == 0 || inMaxPacket > MaxPacketSize) ? MaxPacketSize : inMaxPacket, inPacketOverhead == 0 ? UdpHeaderSize : inPacketOverhead); Socket = inSocket; } public override void InitRemoteConnection(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, IPEndPoint inRemoteAddr, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) { InitBase(inDriver, inSocket, inURL, inState, (inMaxPacket == 0 || inMaxPacket > MaxPacketSize) ? MaxPacketSize : inMaxPacket, inPacketOverhead == 0 ? UdpHeaderSize : inPacketOverhead); RemoteAddr = inRemoteAddr; Url.Host = RemoteAddr.Address; // Initialize our send bunch InitSendBuffer(); // This is for a client that needs to log in, setup ClientLoginState and ExpectedClientLoginMsgType to reflect that SetClientLoginState(EClientLoginState.LoggingIn); SetExpectedClientLoginMsgType(NMT.Hello); // TODO: NMT_HELLO } public override void InitLocalConnection(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) { InitBase(inDriver, inSocket, inURL, inState, // Use the default packet size/overhead unless overridden by a child class (inMaxPacket == 0 || inMaxPacket > MaxPacketSize) ? MaxPacketSize : inMaxPacket, inPacketOverhead == 0 ? inMaxPacket : inPacketOverhead); //RemoteAddr = new IPEndPoint(inURL.Host, inURL.Port); InitSendBuffer(); } public override void LowLevelSend(byte[] data, int countBits, FOutPacketTraits traits) { // TODO: Improve according to UE4 var dataToSend = data; // Process any packet modifiers if (Handler != null && !Handler.GetRawSend()) { var processedData = Handler.Outgoing(data, countBits, traits); if (!processedData.Error) { dataToSend = processedData.Data; countBits = processedData.CountBits; } else { countBits = 0; } } var countBytes = FMath.DivideAndRoundUp(countBits, 8); if (countBits > 0) { if (Socket == null) { throw new UnrealNetException(); } // can't send remote addr if client is already set. receive is called before now too, so need to establish socket before then. if (RemoteAddr.Address.GetAddressBytes().All(a => a == 0xff)) Socket.Send(dataToSend, countBytes); else Socket.Send(dataToSend, countBytes, RemoteAddr); } } public override string LowLevelGetRemoteAddress(bool bAppendPort = false) { if (RemoteAddr != null) { // TODO: Remove port return RemoteAddr.ToString(); } return string.Empty; } public override string LowLevelDescribe() { throw new NotImplementedException(); } public override void CleanUp() { throw new NotImplementedException(); } public override void ReceivedRawPacket(FReceivedPacketView packetView) { _socketErrorRecvDelayStartTime = 0; base.ReceivedRawPacket(packetView); } public override float GetTimeoutValue() { throw new NotImplementedException(); } }