2022-07-20 17:50:01 +08:00
|
|
|
|
using Lidgren.Network;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
using RageCoop.Core;
|
2022-07-20 17:50:01 +08:00
|
|
|
|
using System;
|
2022-07-29 21:15:23 +08:00
|
|
|
|
using System.Collections.Generic;
|
2022-07-19 17:15:53 +08:00
|
|
|
|
using System.Security.Cryptography;
|
2022-07-20 17:50:01 +08:00
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
|
|
|
|
namespace RageCoop.Client
|
|
|
|
|
{
|
2022-05-25 10:09:59 +08:00
|
|
|
|
internal static partial class Networking
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-08-11 16:25:38 +08:00
|
|
|
|
public static CoopPeer Peer;
|
2022-08-08 17:03:41 +08:00
|
|
|
|
public static float Latency => ServerConnection.AverageRoundtripTime/2;
|
2022-05-23 16:59:49 +08:00
|
|
|
|
public static bool ShowNetworkInfo = false;
|
2022-08-06 12:32:04 +08:00
|
|
|
|
public static Security Security;
|
|
|
|
|
public static NetConnection ServerConnection;
|
2022-07-29 21:15:23 +08:00
|
|
|
|
private static readonly Dictionary<int, Action<PacketType, byte[]>> PendingResponses = new Dictionary<int, Action<PacketType, byte[]>>();
|
|
|
|
|
internal static readonly Dictionary<PacketType, Func<byte[], Packet>> RequestHandlers = new Dictionary<PacketType, Func<byte[], Packet>>();
|
2022-08-04 17:14:07 +08:00
|
|
|
|
internal static float SimulatedLatency=0;
|
2022-07-31 20:47:04 +08:00
|
|
|
|
public static bool IsConnecting { get; private set; }
|
2022-06-11 18:41:10 +08:00
|
|
|
|
static Networking()
|
|
|
|
|
{
|
2022-06-24 10:33:36 +08:00
|
|
|
|
Security=new Security(Main.Logger);
|
2022-06-11 18:41:10 +08:00
|
|
|
|
}
|
2022-05-23 16:59:49 +08:00
|
|
|
|
|
2022-07-20 17:50:01 +08:00
|
|
|
|
public static void ToggleConnection(string address, string username = null, string password = null)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-08-11 18:25:01 +08:00
|
|
|
|
Peer?.Shutdown("Bye");
|
2022-05-25 11:32:34 +08:00
|
|
|
|
if (IsOnServer)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-08-11 14:59:09 +02:00
|
|
|
|
// ?
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-07-31 20:47:04 +08:00
|
|
|
|
else if (IsConnecting) {
|
|
|
|
|
_publicKeyReceived.Set();
|
|
|
|
|
IsConnecting = false;
|
|
|
|
|
GTA.UI.Notification.Show("Connection has been canceled");
|
|
|
|
|
}
|
2022-05-22 15:55:26 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2022-08-11 18:25:01 +08:00
|
|
|
|
Peer?.Dispose();
|
|
|
|
|
|
2022-07-31 20:47:04 +08:00
|
|
|
|
IsConnecting = true;
|
2022-06-24 10:33:36 +08:00
|
|
|
|
password = password ?? Main.Settings.Password;
|
2022-06-24 16:49:59 +08:00
|
|
|
|
username=username ?? Main.Settings.Username;
|
2022-08-04 17:14:07 +08:00
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
|
|
|
|
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
|
|
|
|
{
|
2022-08-02 17:43:18 +08:00
|
|
|
|
AutoFlushSendQueue = false,
|
2022-08-04 17:14:07 +08:00
|
|
|
|
SimulatedMinimumLatency =SimulatedLatency,
|
2022-08-08 17:03:41 +08:00
|
|
|
|
AcceptIncomingConnections = true,
|
|
|
|
|
MaximumConnections = 32,
|
|
|
|
|
PingInterval = 5
|
2022-05-22 15:55:26 +08:00
|
|
|
|
};
|
|
|
|
|
|
2022-06-24 10:33:36 +08:00
|
|
|
|
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
2022-08-06 12:32:04 +08:00
|
|
|
|
config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
|
|
|
|
string[] ip = new string[2];
|
|
|
|
|
|
|
|
|
|
int idx = address.LastIndexOf(':');
|
|
|
|
|
if (idx != -1)
|
|
|
|
|
{
|
|
|
|
|
ip[0] = address.Substring(0, idx);
|
|
|
|
|
ip[1] = address.Substring(idx + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ip.Length != 2)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Malformed URL");
|
|
|
|
|
}
|
2022-06-06 17:37:11 +08:00
|
|
|
|
|
2022-07-29 20:35:39 +08:00
|
|
|
|
PlayerList.Cleanup();
|
2022-05-22 15:55:26 +08:00
|
|
|
|
EntityPool.AddPlayer();
|
2022-06-24 10:33:36 +08:00
|
|
|
|
Task.Run(() =>
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-02 17:14:56 +08:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
DownloadManager.Cleanup();
|
2022-08-11 16:25:38 +08:00
|
|
|
|
Peer = new CoopPeer(config);
|
|
|
|
|
Peer.OnMessageReceived+= (s, m) =>
|
|
|
|
|
{
|
|
|
|
|
try { ProcessMessage(m); }
|
|
|
|
|
catch (Exception ex) { Main.Logger.Error(ex); }
|
|
|
|
|
};
|
2022-07-02 17:14:56 +08:00
|
|
|
|
Main.QueueAction(() => { GTA.UI.Notification.Show($"~y~Trying to connect..."); });
|
2022-07-11 11:06:31 +08:00
|
|
|
|
Menus.CoopMenu._serverConnectItem.Enabled=false;
|
2022-07-02 17:14:56 +08:00
|
|
|
|
Security.Regen();
|
2022-07-20 17:50:01 +08:00
|
|
|
|
if (!GetServerPublicKey(address))
|
2022-07-11 11:06:31 +08:00
|
|
|
|
{
|
|
|
|
|
Menus.CoopMenu._serverConnectItem.Enabled=true;
|
|
|
|
|
throw new TimeoutException("Failed to retrive server's public key");
|
|
|
|
|
}
|
2022-07-20 17:50:01 +08:00
|
|
|
|
|
2022-07-02 17:14:56 +08:00
|
|
|
|
// Send HandshakePacket
|
2022-08-06 12:32:04 +08:00
|
|
|
|
NetOutgoingMessage outgoingMessage = Peer.CreateMessage();
|
2022-07-02 17:14:56 +08:00
|
|
|
|
var handshake = new Packets.Handshake()
|
|
|
|
|
{
|
|
|
|
|
PedID = Main.LocalPlayerID,
|
|
|
|
|
Username =username,
|
|
|
|
|
ModVersion = Main.CurrentVersion,
|
2022-08-06 12:32:04 +08:00
|
|
|
|
PasswordEncrypted=Security.Encrypt(password.GetBytes()),
|
2022-08-11 16:25:38 +08:00
|
|
|
|
InternalEndPoint = new System.Net.IPEndPoint(CoreUtils.GetLocalAddress(ip[0]), Peer.Port)
|
2022-07-02 17:14:56 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Security.GetSymmetricKeysCrypted(out handshake.AesKeyCrypted, out handshake.AesIVCrypted);
|
|
|
|
|
handshake.Pack(outgoingMessage);
|
2022-08-06 12:32:04 +08:00
|
|
|
|
ServerConnection = Peer.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
2022-06-24 10:33:36 +08:00
|
|
|
|
|
2022-07-02 17:14:56 +08:00
|
|
|
|
}
|
2022-07-20 17:50:01 +08:00
|
|
|
|
catch (Exception ex)
|
2022-06-24 10:33:36 +08:00
|
|
|
|
{
|
2022-07-11 11:06:31 +08:00
|
|
|
|
Main.Logger.Error("Cannot connect to server: ", ex);
|
|
|
|
|
Main.QueueAction(() => GTA.UI.Notification.Show("Cannot connect to server: "+ex.Message));
|
2022-07-02 17:14:56 +08:00
|
|
|
|
}
|
2022-07-31 20:47:04 +08:00
|
|
|
|
IsConnecting=false;
|
2022-06-24 10:33:36 +08:00
|
|
|
|
});
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-11 14:59:09 +02:00
|
|
|
|
public static bool IsOnServer { get => ServerConnection?.Status == NetConnectionStatus.Connected; }
|
2022-07-20 17:50:01 +08:00
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
#region -- PLAYER --
|
2022-05-23 16:59:49 +08:00
|
|
|
|
private static void PlayerConnect(Packets.PlayerConnect packet)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-08-08 17:03:41 +08:00
|
|
|
|
var p = new Player
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
|
|
|
|
PedID = packet.PedID,
|
|
|
|
|
Username= packet.Username,
|
|
|
|
|
};
|
2022-05-23 16:59:49 +08:00
|
|
|
|
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
|
|
|
|
Main.Logger.Debug($"player connected:{p.Username}");
|
2022-08-10 20:42:47 +08:00
|
|
|
|
Main.QueueAction(() =>
|
|
|
|
|
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected."));
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-05-23 16:59:49 +08:00
|
|
|
|
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-08-11 15:38:19 +08:00
|
|
|
|
var player = PlayerList.GetPlayer(packet.PedID);
|
|
|
|
|
if (player==null) { return; }
|
2022-05-23 16:59:49 +08:00
|
|
|
|
PlayerList.RemovePlayer(packet.PedID);
|
2022-08-11 15:38:19 +08:00
|
|
|
|
Main.QueueAction(() => {
|
|
|
|
|
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
|
|
|
|
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");
|
|
|
|
|
});
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion // -- PLAYER --
|
2022-07-29 20:35:39 +08:00
|
|
|
|
#region -- GET --
|
2022-07-20 17:50:01 +08:00
|
|
|
|
private static bool GetServerPublicKey(string address, int timeout = 10000)
|
2022-06-24 10:33:36 +08:00
|
|
|
|
{
|
2022-07-31 20:47:04 +08:00
|
|
|
|
Security.ServerRSA=null;
|
2022-08-06 12:32:04 +08:00
|
|
|
|
var msg = Peer.CreateMessage();
|
2022-07-20 17:50:01 +08:00
|
|
|
|
new Packets.PublicKeyRequest().Pack(msg);
|
|
|
|
|
var adds = address.Split(':');
|
2022-08-06 12:32:04 +08:00
|
|
|
|
Peer.SendUnconnectedMessage(msg, adds[0], int.Parse(adds[1]));
|
2022-07-31 20:47:04 +08:00
|
|
|
|
return _publicKeyReceived.WaitOne(timeout) && Security.ServerRSA!=null;
|
2022-06-24 10:33:36 +08:00
|
|
|
|
}
|
2022-07-29 20:35:39 +08:00
|
|
|
|
|
|
|
|
|
public static void GetResponse<T>(Packet request, Action<T> callback, ConnectionChannel channel = ConnectionChannel.RequestResponse) where T : Packet, new()
|
2022-07-19 17:15:53 +08:00
|
|
|
|
{
|
|
|
|
|
var received = new AutoResetEvent(false);
|
|
|
|
|
var id = NewRequestID();
|
|
|
|
|
PendingResponses.Add(id, (type, p) =>
|
|
|
|
|
{
|
|
|
|
|
var result = new T();
|
2022-08-06 10:43:24 +08:00
|
|
|
|
result.Deserialize(p);
|
2022-07-19 17:15:53 +08:00
|
|
|
|
callback(result);
|
|
|
|
|
});
|
2022-08-06 12:32:04 +08:00
|
|
|
|
var msg = Peer.CreateMessage();
|
2022-07-19 17:15:53 +08:00
|
|
|
|
msg.Write((byte)PacketType.Request);
|
|
|
|
|
msg.Write(id);
|
|
|
|
|
request.Pack(msg);
|
2022-08-06 12:32:04 +08:00
|
|
|
|
Peer.SendMessage(msg,ServerConnection, NetDeliveryMethod.ReliableOrdered, (int)channel);
|
2022-07-19 17:15:53 +08:00
|
|
|
|
}
|
2022-07-29 20:35:39 +08:00
|
|
|
|
|
|
|
|
|
#endregion
|
2022-07-19 17:15:53 +08:00
|
|
|
|
private static int NewRequestID()
|
|
|
|
|
{
|
|
|
|
|
int ID = 0;
|
2022-08-11 14:59:09 +02:00
|
|
|
|
while ((ID==0) || PendingResponses.ContainsKey(ID))
|
2022-07-19 17:15:53 +08:00
|
|
|
|
{
|
|
|
|
|
byte[] rngBytes = new byte[4];
|
|
|
|
|
|
|
|
|
|
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
|
|
|
|
|
|
|
|
|
// Convert the bytes into an integer
|
|
|
|
|
ID = BitConverter.ToInt32(rngBytes, 0);
|
|
|
|
|
}
|
|
|
|
|
return ID;
|
|
|
|
|
}
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|