2021-07-07 13:36:25 +02:00
|
|
|
|
using System;
|
2021-12-17 19:50:47 +01:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Net;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Threading;
|
2021-08-14 21:49:23 +02:00
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.IO;
|
2021-12-07 08:18:29 +01:00
|
|
|
|
using System.Net.Http;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
using RageCoop.Core;
|
2022-04-19 05:33:18 +02:00
|
|
|
|
using Newtonsoft.Json;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
using Lidgren.Network;
|
2022-06-01 19:05:45 +08:00
|
|
|
|
using System.Timers;
|
2022-06-06 17:37:11 +08:00
|
|
|
|
using System.Security.Cryptography;
|
2022-06-04 18:09:42 +08:00
|
|
|
|
using RageCoop.Server.Scripting;
|
2022-06-11 18:41:10 +08:00
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Threading.Tasks;
|
2022-07-10 16:13:08 +08:00
|
|
|
|
using RageCoop.Core.Scripting;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
namespace RageCoop.Server
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-07-01 13:54:18 +08:00
|
|
|
|
internal struct IpInfo
|
2022-04-19 05:33:18 +02:00
|
|
|
|
{
|
|
|
|
|
[JsonProperty("ip")]
|
|
|
|
|
public string Address { get; set; }
|
2022-07-09 11:39:37 +08:00
|
|
|
|
|
|
|
|
|
[JsonProperty("country")]
|
|
|
|
|
public string Country { get; set; }
|
2022-04-19 05:33:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-01 13:54:18 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The instantiable RageCoop server class
|
|
|
|
|
/// </summary>
|
2022-06-24 16:49:59 +08:00
|
|
|
|
public class Server
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-07-01 13:54:18 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The API for controlling server and hooking events.
|
|
|
|
|
/// </summary>
|
2022-06-30 09:28:13 +08:00
|
|
|
|
public API API { get; private set; }
|
2022-07-12 17:16:28 +08:00
|
|
|
|
internal readonly BaseScript BaseScript;
|
2022-06-24 18:25:24 +08:00
|
|
|
|
internal readonly ServerSettings Settings;
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal NetServer MainNetServer;
|
2022-07-01 19:02:38 +08:00
|
|
|
|
internal ServerEntities Entities;
|
2022-06-23 14:10:16 +08:00
|
|
|
|
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal readonly Dictionary<Command, Action<CommandContext>> Commands = new();
|
|
|
|
|
internal readonly Dictionary<long,Client> Clients = new();
|
2022-07-09 19:32:11 +08:00
|
|
|
|
internal readonly Dictionary<string, Client> ClientsByName = new();
|
2022-07-10 16:13:08 +08:00
|
|
|
|
internal Client _hostClient;
|
2022-07-09 19:32:11 +08:00
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
|
|
|
|
private Resources Resources;
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal Logger Logger;
|
2022-06-24 10:33:36 +08:00
|
|
|
|
private Security Security;
|
2022-06-30 09:28:13 +08:00
|
|
|
|
private System.Timers.Timer _sendInfoTimer = new System.Timers.Timer(5000);
|
|
|
|
|
private bool _stopping = false;
|
2022-06-27 15:35:23 +08:00
|
|
|
|
private Thread _listenerThread;
|
|
|
|
|
private Thread _announceThread;
|
2022-06-30 09:28:13 +08:00
|
|
|
|
private Worker _worker;
|
2022-07-01 12:22:31 +08:00
|
|
|
|
private Dictionary<int,Action<PacketType,byte[]>> PendingResponses=new();
|
2022-07-19 17:15:53 +08:00
|
|
|
|
internal Dictionary<PacketType, Func<byte[],Client,Packet>> RequestHandlers=new();
|
2022-06-30 09:28:13 +08:00
|
|
|
|
private readonly string _compatibleVersion = "V0_5";
|
2022-07-01 13:54:18 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Instantiate a server.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="settings"></param>
|
|
|
|
|
/// <param name="logger"></param>
|
|
|
|
|
/// <exception cref="ArgumentNullException"></exception>
|
2022-06-24 18:25:24 +08:00
|
|
|
|
public Server(ServerSettings settings,Logger logger=null)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-24 18:25:24 +08:00
|
|
|
|
Settings = settings;
|
|
|
|
|
if (settings==null) { throw new ArgumentNullException("Server settings cannot be null!"); }
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger=logger;
|
2022-06-24 18:25:24 +08:00
|
|
|
|
if (Logger!=null) { Logger.LogLevel=Settings.LogLevel;}
|
2022-06-23 14:10:16 +08:00
|
|
|
|
API=new API(this);
|
|
|
|
|
Resources=new Resources(this);
|
2022-06-24 10:33:36 +08:00
|
|
|
|
Security=new Security(Logger);
|
2022-07-01 19:02:38 +08:00
|
|
|
|
Entities=new ServerEntities(this);
|
2022-07-12 17:16:28 +08:00
|
|
|
|
BaseScript=new BaseScript(this);
|
2022-06-27 15:35:23 +08:00
|
|
|
|
}
|
2022-07-01 13:54:18 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Spawn threads and start the server
|
|
|
|
|
/// </summary>
|
2022-06-27 15:35:23 +08:00
|
|
|
|
public void Start()
|
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info("================");
|
2022-06-24 18:25:24 +08:00
|
|
|
|
Logger?.Info($"Server bound to: 0.0.0.0:{Settings.Port}");
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
|
|
|
|
|
Logger?.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x");
|
|
|
|
|
Logger?.Info("================");
|
2021-09-28 16:51:16 +02:00
|
|
|
|
|
2022-04-06 02:18:24 +02:00
|
|
|
|
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
|
|
|
|
NetPeerConfiguration config = new("623c92c287cc392406e7aaaac1c0f3b0")
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-24 18:25:24 +08:00
|
|
|
|
Port = Settings.Port,
|
|
|
|
|
MaximumConnections = Settings.MaxPlayers,
|
2022-06-11 18:41:10 +08:00
|
|
|
|
EnableUPnP = false,
|
2022-06-24 16:49:59 +08:00
|
|
|
|
AutoFlushSendQueue = true
|
2021-07-07 13:36:25 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
2021-08-16 12:31:49 +02:00
|
|
|
|
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
2022-06-24 10:33:36 +08:00
|
|
|
|
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
|
|
|
|
MainNetServer = new NetServer(config);
|
|
|
|
|
MainNetServer.Start();
|
2022-07-01 12:22:31 +08:00
|
|
|
|
_worker=new Worker("ServerWorker",Logger);
|
2022-06-30 09:28:13 +08:00
|
|
|
|
_sendInfoTimer.Elapsed+=(s, e) => { SendPlayerInfos(); };
|
|
|
|
|
_sendInfoTimer.AutoReset=true;
|
|
|
|
|
_sendInfoTimer.Enabled=true;
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
|
2022-06-24 18:25:24 +08:00
|
|
|
|
if (Settings.AnnounceSelf)
|
2021-12-07 08:18:29 +01:00
|
|
|
|
{
|
2022-04-19 03:38:48 +02:00
|
|
|
|
|
|
|
|
|
#region -- MASTERSERVER --
|
2022-06-27 15:35:23 +08:00
|
|
|
|
_announceThread=new Thread(async () =>
|
2021-12-07 08:18:29 +01:00
|
|
|
|
{
|
2022-04-19 03:38:48 +02:00
|
|
|
|
try
|
2021-12-07 08:18:29 +01:00
|
|
|
|
{
|
2022-04-19 03:38:48 +02:00
|
|
|
|
// TLS only
|
|
|
|
|
ServicePointManager.Expect100Continue = true;
|
2022-07-13 11:08:11 +08:00
|
|
|
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 ;
|
2022-04-19 03:38:48 +02:00
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
2021-12-07 08:18:29 +01:00
|
|
|
|
|
2022-04-19 03:38:48 +02:00
|
|
|
|
HttpClient httpClient = new();
|
2021-12-07 08:18:29 +01:00
|
|
|
|
|
2022-04-19 05:33:18 +02:00
|
|
|
|
IpInfo info;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
HttpResponseMessage response = await httpClient.GetAsync("https://ipinfo.io/json");
|
2022-04-19 07:41:39 +02:00
|
|
|
|
if (response.StatusCode != HttpStatusCode.OK)
|
2022-04-19 05:33:18 +02:00
|
|
|
|
{
|
2022-04-19 07:41:39 +02:00
|
|
|
|
throw new Exception($"IPv4 request failed! [{(int)response.StatusCode}/{response.ReasonPhrase}]");
|
2022-04-19 05:33:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string content = await response.Content.ReadAsStringAsync();
|
|
|
|
|
info = JsonConvert.DeserializeObject<IpInfo>(content);
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info($"Your public IP is {info.Address}, announcing to master server...");
|
2022-04-19 05:33:18 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error(ex.InnerException?.Message ?? ex.Message);
|
2022-04-19 05:33:18 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-27 15:35:23 +08:00
|
|
|
|
while (!_stopping)
|
2022-04-19 03:38:48 +02:00
|
|
|
|
{
|
|
|
|
|
string msg =
|
|
|
|
|
"{ " +
|
2022-04-19 05:33:18 +02:00
|
|
|
|
"\"address\": \"" + info.Address + "\", " +
|
2022-06-24 18:25:24 +08:00
|
|
|
|
"\"port\": \"" + Settings.Port + "\", " +
|
2022-07-09 11:39:37 +08:00
|
|
|
|
"\"country\": \"" + info.Country + "\", " +
|
2022-06-24 18:25:24 +08:00
|
|
|
|
"\"name\": \"" + Settings.Name + "\", " +
|
2022-04-19 03:38:48 +02:00
|
|
|
|
"\"version\": \"" + _compatibleVersion.Replace("_", ".") + "\", " +
|
|
|
|
|
"\"players\": \"" + MainNetServer.ConnectionsCount + "\", " +
|
2022-07-09 11:36:04 +08:00
|
|
|
|
"\"maxPlayers\": \"" + Settings.MaxPlayers + "\", " +
|
|
|
|
|
"\"description\": \"" + Settings.Description + "\", " +
|
|
|
|
|
"\"website\": \"" + Settings.Website + "\", " +
|
|
|
|
|
"\"gameMode\": \"" + Settings.GameMode + "\", " +
|
|
|
|
|
"\"language\": \"" + Settings.Language + "\"" +
|
2022-04-19 03:38:48 +02:00
|
|
|
|
" }";
|
|
|
|
|
HttpResponseMessage response = null;
|
2021-12-07 08:18:29 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
2022-07-11 13:26:28 +08:00
|
|
|
|
var realUrl = Util.GetFinalRedirect(Settings.MasterServer);
|
|
|
|
|
response = await httpClient.PostAsync(realUrl, new StringContent(msg, Encoding.UTF8, "application/json"));
|
2021-12-07 08:18:29 +01:00
|
|
|
|
}
|
2022-04-19 03:38:48 +02:00
|
|
|
|
catch (Exception ex)
|
2021-12-07 08:18:29 +01:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error($"MasterServer: {ex.Message}");
|
2022-04-19 03:38:48 +02:00
|
|
|
|
|
|
|
|
|
// Sleep for 5s
|
|
|
|
|
Thread.Sleep(5000);
|
|
|
|
|
continue;
|
2021-12-07 08:18:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-19 03:38:48 +02:00
|
|
|
|
if (response == null)
|
2021-12-07 08:18:29 +01:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error("MasterServer: Something went wrong!");
|
2022-04-19 03:38:48 +02:00
|
|
|
|
}
|
|
|
|
|
else if (response.StatusCode != HttpStatusCode.OK)
|
|
|
|
|
{
|
|
|
|
|
if (response.StatusCode == HttpStatusCode.BadRequest)
|
2022-04-14 12:18:07 +02:00
|
|
|
|
{
|
2022-04-19 03:38:48 +02:00
|
|
|
|
string requestContent = await response.Content.ReadAsStringAsync();
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
|
2022-04-14 12:18:07 +02:00
|
|
|
|
}
|
2022-04-19 03:38:48 +02:00
|
|
|
|
else
|
2022-04-14 12:18:07 +02:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error($"MasterServer: [{(int)response.StatusCode}]");
|
|
|
|
|
Logger?.Error($"MasterServer: [{await response.Content.ReadAsStringAsync()}]");
|
2022-04-14 12:18:07 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-19 03:38:48 +02:00
|
|
|
|
|
|
|
|
|
// Sleep for 10s
|
2022-06-27 15:35:23 +08:00
|
|
|
|
for(int i = 0; i<10; i++)
|
|
|
|
|
{
|
|
|
|
|
if (_stopping)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Thread.Sleep(1000);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-07 08:18:29 +01:00
|
|
|
|
}
|
2022-04-19 03:38:48 +02:00
|
|
|
|
}
|
|
|
|
|
catch (HttpRequestException ex)
|
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error($"MasterServer: {ex.InnerException.Message}");
|
2022-04-19 03:38:48 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error($"MasterServer: {ex.Message}");
|
2022-04-19 03:38:48 +02:00
|
|
|
|
}
|
2022-06-27 15:35:23 +08:00
|
|
|
|
});
|
|
|
|
|
_announceThread.Start();
|
2022-04-19 03:38:48 +02:00
|
|
|
|
#endregion
|
2021-12-07 08:18:29 +01:00
|
|
|
|
}
|
2022-06-23 14:10:16 +08:00
|
|
|
|
BaseScript.API=API;
|
2022-06-22 14:18:20 +08:00
|
|
|
|
BaseScript.OnStart();
|
2022-06-11 18:41:10 +08:00
|
|
|
|
Resources.LoadAll();
|
2022-06-27 15:35:23 +08:00
|
|
|
|
_listenerThread=new Thread(() => Listen());
|
|
|
|
|
_listenerThread.Start();
|
2022-07-22 19:43:48 +08:00
|
|
|
|
Logger?.Info("Listening for clients");
|
2022-06-27 15:35:23 +08:00
|
|
|
|
}
|
2022-07-01 13:54:18 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Terminate threads and stop the server
|
|
|
|
|
/// </summary>
|
2022-06-27 15:35:23 +08:00
|
|
|
|
public void Stop()
|
|
|
|
|
{
|
|
|
|
|
_stopping = true;
|
2022-06-30 09:28:13 +08:00
|
|
|
|
_sendInfoTimer.Stop();
|
|
|
|
|
_sendInfoTimer.Enabled=false;
|
|
|
|
|
_sendInfoTimer.Dispose();
|
2022-06-27 15:35:23 +08:00
|
|
|
|
Logger?.Flush();
|
|
|
|
|
_listenerThread?.Join();
|
|
|
|
|
_announceThread?.Join();
|
2022-06-30 09:28:13 +08:00
|
|
|
|
_worker.Dispose();
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
private void Listen()
|
|
|
|
|
{
|
2022-07-19 17:15:53 +08:00
|
|
|
|
NetIncomingMessage msg=null;
|
2022-06-27 15:35:23 +08:00
|
|
|
|
while (!_stopping)
|
2022-06-04 14:13:08 +08:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
try
|
|
|
|
|
{
|
2022-07-19 17:15:53 +08:00
|
|
|
|
msg=MainNetServer.WaitMessage(200);
|
|
|
|
|
ProcessMessage(msg);
|
2022-06-23 14:10:16 +08:00
|
|
|
|
}
|
|
|
|
|
catch(Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Logger?.Error("Error processing message");
|
|
|
|
|
Logger?.Error(ex);
|
2022-07-19 17:15:53 +08:00
|
|
|
|
if (msg!=null)
|
|
|
|
|
{
|
|
|
|
|
DisconnectAndLog(msg.SenderConnection, PacketType.Unknown, ex);
|
|
|
|
|
}
|
2022-06-23 14:10:16 +08:00
|
|
|
|
}
|
2022-06-04 14:13:08 +08:00
|
|
|
|
}
|
2022-06-27 15:35:23 +08:00
|
|
|
|
Logger?.Info("Server is shutting down!");
|
2022-06-11 18:41:10 +08:00
|
|
|
|
MainNetServer.Shutdown("Server is shutting down!");
|
2022-06-22 14:18:20 +08:00
|
|
|
|
BaseScript.OnStop();
|
2022-07-01 12:22:31 +08:00
|
|
|
|
Resources.UnloadAll();
|
2022-06-04 14:13:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ProcessMessage(NetIncomingMessage message)
|
|
|
|
|
{
|
2022-06-24 10:33:36 +08:00
|
|
|
|
Client sender;
|
|
|
|
|
if (message == null) { return; }
|
2022-06-04 14:13:08 +08:00
|
|
|
|
switch (message.MessageType)
|
|
|
|
|
{
|
|
|
|
|
case NetIncomingMessageType.ConnectionApproval:
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info($"New incoming connection from: [{message.SenderConnection.RemoteEndPoint}]");
|
2022-07-01 12:22:31 +08:00
|
|
|
|
if (message.ReadByte() != (byte)PacketType.Handshake)
|
2022-06-04 14:13:08 +08:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: Wrong packet!");
|
2022-06-04 14:13:08 +08:00
|
|
|
|
message.SenderConnection.Deny("Wrong packet!");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
int len = message.ReadInt32();
|
|
|
|
|
byte[] data = message.ReadBytes(len);
|
|
|
|
|
|
|
|
|
|
Packets.Handshake packet = new();
|
|
|
|
|
packet.Unpack(data);
|
|
|
|
|
GetHandshake(message.SenderConnection, packet);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
|
2022-06-24 10:33:36 +08:00
|
|
|
|
Logger?.Error(e);
|
2022-06-04 14:13:08 +08:00
|
|
|
|
message.SenderConnection.Deny(e.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NetIncomingMessageType.StatusChanged:
|
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
// Get sender client
|
|
|
|
|
if (!Clients.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-06-04 14:13:08 +08:00
|
|
|
|
NetConnectionStatus status = (NetConnectionStatus)message.ReadByte();
|
|
|
|
|
|
|
|
|
|
if (status == NetConnectionStatus.Disconnected)
|
|
|
|
|
{
|
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
SendPlayerDisconnectPacket(sender);
|
2022-06-04 14:13:08 +08:00
|
|
|
|
}
|
|
|
|
|
else if (status == NetConnectionStatus.Connected)
|
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
SendPlayerConnectPacket(sender);
|
2022-07-01 12:22:31 +08:00
|
|
|
|
_worker.QueueJob(() => API.Events.InvokePlayerConnected(sender));
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Resources.SendTo(sender);
|
2022-06-04 14:13:08 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NetIncomingMessageType.Data:
|
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
|
|
|
|
|
// Get sender client
|
|
|
|
|
if (Clients.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
// Get packet type
|
|
|
|
|
var type = (PacketType)message.ReadByte();
|
2022-06-06 17:37:11 +08:00
|
|
|
|
switch (type)
|
2022-06-04 14:13:08 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
case PacketType.Response:
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
int id = message.ReadInt32();
|
|
|
|
|
if (PendingResponses.TryGetValue(id, out var callback))
|
|
|
|
|
{
|
|
|
|
|
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
|
|
|
|
|
PendingResponses.Remove(id);
|
|
|
|
|
}
|
2022-06-06 17:37:11 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
case PacketType.Request:
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
int id = message.ReadInt32();
|
|
|
|
|
if (RequestHandlers.TryGetValue((PacketType)message.ReadByte(), out var handler))
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
var response=MainNetServer.CreateMessage();
|
|
|
|
|
response.Write((byte)PacketType.Response);
|
|
|
|
|
response.Write(id);
|
2022-07-19 17:15:53 +08:00
|
|
|
|
handler(message.ReadBytes(message.ReadInt32()),sender).Pack(response);
|
2022-07-01 12:22:31 +08:00
|
|
|
|
MainNetServer.SendMessage(response,message.SenderConnection,NetDeliveryMethod.ReliableOrdered);
|
2022-06-06 17:37:11 +08:00
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
break;
|
2022-04-03 02:27:30 +02:00
|
|
|
|
}
|
2022-06-06 17:37:11 +08:00
|
|
|
|
default:
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
byte[] data = message.ReadBytes(message.ReadInt32());
|
|
|
|
|
if (type.IsSyncEvent())
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
// Sync Events
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var toSend = MainNetServer.Connections.Exclude(message.SenderConnection);
|
|
|
|
|
if (toSend.Count!=0)
|
|
|
|
|
{
|
|
|
|
|
var outgoingMessage = MainNetServer.CreateMessage();
|
|
|
|
|
outgoingMessage.Write((byte)type);
|
|
|
|
|
outgoingMessage.Write(data.Length);
|
|
|
|
|
outgoingMessage.Write(data);
|
|
|
|
|
MainNetServer.SendMessage(outgoingMessage, toSend, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.SyncEvents);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
DisconnectAndLog(message.SenderConnection, type, e);
|
2022-06-06 17:37:11 +08:00
|
|
|
|
}
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
else
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
HandlePacket(type, data, sender);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
break;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-06-04 14:13:08 +08:00
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
|
2022-06-06 17:37:11 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2022-06-04 14:13:08 +08:00
|
|
|
|
case NetIncomingMessageType.ConnectionLatencyUpdated:
|
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
// Get sender client
|
|
|
|
|
if (!Clients.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (sender != null)
|
2022-06-04 14:13:08 +08:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
sender.Latency = message.ReadFloat();
|
2022-06-04 14:13:08 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case NetIncomingMessageType.ErrorMessage:
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error(message.ReadString());
|
2022-06-04 14:13:08 +08:00
|
|
|
|
break;
|
|
|
|
|
case NetIncomingMessageType.WarningMessage:
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Warning(message.ReadString());
|
2022-06-04 14:13:08 +08:00
|
|
|
|
break;
|
|
|
|
|
case NetIncomingMessageType.DebugMessage:
|
|
|
|
|
case NetIncomingMessageType.VerboseDebugMessage:
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Debug(message.ReadString());
|
2022-06-04 14:13:08 +08:00
|
|
|
|
break;
|
2022-06-24 10:33:36 +08:00
|
|
|
|
case NetIncomingMessageType.UnconnectedData:
|
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
if (message.ReadByte()==(byte)PacketType.PublicKeyRequest)
|
2022-06-24 10:33:36 +08:00
|
|
|
|
{
|
|
|
|
|
var msg = MainNetServer.CreateMessage();
|
|
|
|
|
var p=new Packets.PublicKeyResponse();
|
|
|
|
|
Security.GetPublicKey(out p.Modulus,out p.Exponent);
|
|
|
|
|
p.Pack(msg);
|
|
|
|
|
Logger?.Debug($"Sending public key to {message.SenderEndPoint}, length:{msg.LengthBytes}");
|
|
|
|
|
MainNetServer.SendUnconnectedMessage(msg, message.SenderEndPoint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2022-06-04 14:13:08 +08:00
|
|
|
|
default:
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
|
2022-06-04 14:13:08 +08:00
|
|
|
|
break;
|
2021-12-08 13:45:00 +01:00
|
|
|
|
}
|
2021-12-08 14:46:07 +01:00
|
|
|
|
|
2022-06-04 14:13:08 +08:00
|
|
|
|
MainNetServer.Recycle(message);
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
internal void QueueJob(Action job)
|
|
|
|
|
{
|
|
|
|
|
_worker.QueueJob(job);
|
|
|
|
|
}
|
|
|
|
|
private void HandlePacket(PacketType type,byte[] data,Client sender)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
2022-07-17 11:59:37 +08:00
|
|
|
|
#region INTERVAL-SYNC
|
2022-07-01 12:22:31 +08:00
|
|
|
|
case PacketType.PedSync:
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Packets.PedSync packet = new();
|
|
|
|
|
packet.Unpack(data);
|
|
|
|
|
|
|
|
|
|
PedSync(packet, sender);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PacketType.VehicleSync:
|
|
|
|
|
{
|
|
|
|
|
Packets.VehicleSync packet = new();
|
|
|
|
|
packet.Unpack(data);
|
|
|
|
|
|
|
|
|
|
VehicleSync(packet, sender);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PacketType.ProjectileSync:
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Packets.ProjectileSync packet = new();
|
|
|
|
|
packet.Unpack(data);
|
|
|
|
|
ProjectileSync(packet, sender);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
case PacketType.ChatMessage:
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Packets.ChatMessage packet = new();
|
|
|
|
|
packet.Unpack(data);
|
|
|
|
|
|
2022-07-22 19:43:48 +08:00
|
|
|
|
ChatMessageReceived(packet.Username,packet.Message, sender);
|
2022-07-01 12:22:31 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PacketType.CustomEvent:
|
|
|
|
|
{
|
|
|
|
|
Packets.CustomEvent packet = new Packets.CustomEvent();
|
|
|
|
|
packet.Unpack(data);
|
|
|
|
|
_worker.QueueJob(() => API.Events.InvokeCustomEventReceived(packet, sender));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Logger?.Error("Unhandled Data / Packet type");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
DisconnectAndLog(sender.Connection, type, e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-23 14:10:16 +08:00
|
|
|
|
object _sendPlayersLock=new object();
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal void SendPlayerInfos()
|
2022-05-25 10:09:59 +08:00
|
|
|
|
{
|
2022-06-22 14:18:20 +08:00
|
|
|
|
lock (_sendPlayersLock)
|
2022-05-25 10:09:59 +08:00
|
|
|
|
{
|
2022-06-22 14:18:20 +08:00
|
|
|
|
foreach (Client c in Clients.Values)
|
2022-05-25 10:09:59 +08:00
|
|
|
|
{
|
2022-06-22 14:18:20 +08:00
|
|
|
|
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != c.NetID).ForEach(x =>
|
2022-05-25 10:09:59 +08:00
|
|
|
|
{
|
2022-06-22 14:18:20 +08:00
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
|
|
|
new Packets.PlayerInfoUpdate()
|
|
|
|
|
{
|
2022-07-01 13:54:18 +08:00
|
|
|
|
PedID=c.Player.ID,
|
2022-06-22 14:18:20 +08:00
|
|
|
|
Username=c.Username,
|
|
|
|
|
Latency=c.Latency,
|
|
|
|
|
}.Pack(outgoingMessage);
|
|
|
|
|
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-06-01 19:05:45 +08:00
|
|
|
|
|
2022-06-22 14:18:20 +08:00
|
|
|
|
}
|
2022-05-25 10:09:59 +08:00
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-07-01 12:22:31 +08:00
|
|
|
|
private void DisconnectAndLog(NetConnection senderConnection,PacketType type, Exception e)
|
2022-02-06 09:59:18 -07:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Error($"Error receiving a packet of type {type}");
|
|
|
|
|
Logger?.Error(e.Message);
|
|
|
|
|
Logger?.Error(e.StackTrace);
|
2022-02-06 09:59:18 -07:00
|
|
|
|
senderConnection.Disconnect(e.Message);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-06 17:37:11 +08:00
|
|
|
|
#region -- SYNC --
|
2021-07-07 13:36:25 +02:00
|
|
|
|
// Before we approve the connection, we must shake hands
|
2022-06-04 18:09:42 +08:00
|
|
|
|
private void GetHandshake(NetConnection connection, Packets.Handshake packet)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Debug("New handshake from: [Name: " + packet.Username + " | Address: " + connection.RemoteEndPoint.Address.ToString() + "]");
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-04-10 14:34:55 +02:00
|
|
|
|
if (!packet.ModVersion.StartsWith(_compatibleVersion))
|
2021-12-18 00:21:23 +01:00
|
|
|
|
{
|
2022-06-04 18:09:42 +08:00
|
|
|
|
connection.Deny($"RAGECOOP version {_compatibleVersion.Replace('_', '.')}.x required!");
|
2021-12-18 00:21:23 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
if (string.IsNullOrWhiteSpace(packet.Username))
|
|
|
|
|
{
|
2022-06-04 18:09:42 +08:00
|
|
|
|
connection.Deny("Username is empty or contains spaces!");
|
2021-07-07 13:36:25 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-02-17 14:42:54 -07:00
|
|
|
|
if (packet.Username.Any(p => !char.IsLetterOrDigit(p) && !(p == '_') && !(p=='-')))
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-04 18:09:42 +08:00
|
|
|
|
connection.Deny("Username contains special chars!");
|
2021-07-07 13:36:25 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-21 18:13:30 +08:00
|
|
|
|
if (Clients.Values.Any(x => x.Username.ToLower() == packet.Username.ToLower()))
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
connection.Deny("Username is already taken!");
|
2021-07-07 13:36:25 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-24 10:33:36 +08:00
|
|
|
|
string passhash;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Security.AddConnection(connection.RemoteEndPoint, packet.AesKeyCrypted,packet.AesIVCrypted);
|
2022-07-23 23:45:20 +08:00
|
|
|
|
passhash=Security.Decrypt(packet.PassHashEncrypted, connection.RemoteEndPoint).ToHexString();
|
2022-06-24 10:33:36 +08:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Logger?.Error($"Cannot process handshake packet from {connection.RemoteEndPoint}");
|
|
|
|
|
Logger?.Error(ex);
|
|
|
|
|
connection.Deny("Malformed handshak packet!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-11 18:41:10 +08:00
|
|
|
|
var args = new HandshakeEventArgs()
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
EndPoint=connection.RemoteEndPoint,
|
|
|
|
|
ID=packet.PedID,
|
2022-06-24 10:33:36 +08:00
|
|
|
|
Username=packet.Username,
|
|
|
|
|
PasswordHash=passhash,
|
2022-06-11 18:41:10 +08:00
|
|
|
|
};
|
|
|
|
|
API.Events.InvokePlayerHandshake(args);
|
|
|
|
|
if (args.Cancel)
|
2021-08-21 16:52:17 +02:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
connection.Deny(args.DenyReason);
|
2021-08-21 16:52:17 +02:00
|
|
|
|
return;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-11 18:41:10 +08:00
|
|
|
|
|
2022-06-24 10:33:36 +08:00
|
|
|
|
connection.Approve();
|
2021-07-09 00:20:09 +02:00
|
|
|
|
|
2021-11-25 16:32:04 +01:00
|
|
|
|
Client tmpClient;
|
|
|
|
|
|
2021-07-07 13:36:25 +02:00
|
|
|
|
// Add the player to Players
|
2021-11-25 16:32:04 +01:00
|
|
|
|
lock (Clients)
|
|
|
|
|
{
|
2022-07-04 09:41:00 +08:00
|
|
|
|
var player = new ServerPed(this)
|
2022-07-02 12:39:50 +08:00
|
|
|
|
{
|
|
|
|
|
ID= packet.PedID,
|
|
|
|
|
};
|
|
|
|
|
Entities.Add(player);
|
2022-06-04 18:09:42 +08:00
|
|
|
|
Clients.Add(connection.RemoteUniqueIdentifier,
|
2022-06-23 14:10:16 +08:00
|
|
|
|
tmpClient = new Client(this)
|
2021-08-26 17:01:32 +02:00
|
|
|
|
{
|
2022-06-04 18:09:42 +08:00
|
|
|
|
NetID = connection.RemoteUniqueIdentifier,
|
|
|
|
|
Connection=connection,
|
2022-06-21 18:13:30 +08:00
|
|
|
|
Username=packet.Username,
|
2022-07-02 12:39:50 +08:00
|
|
|
|
Player = player
|
2021-08-26 17:01:32 +02:00
|
|
|
|
}
|
2022-07-09 19:32:11 +08:00
|
|
|
|
);
|
|
|
|
|
ClientsByName.Add(packet.Username, tmpClient);
|
2022-07-10 16:13:08 +08:00
|
|
|
|
if (Clients.Count==1) {
|
|
|
|
|
_hostClient=tmpClient;
|
|
|
|
|
}
|
2021-11-25 16:32:04 +01:00
|
|
|
|
}
|
2022-06-04 18:09:42 +08:00
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
|
2022-06-24 10:33:36 +08:00
|
|
|
|
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The connection has been approved, now we need to send all other players to the new player and the new player to all players
|
2022-06-23 14:10:16 +08:00
|
|
|
|
private void SendPlayerConnectPacket(Client newClient)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-07-10 16:13:08 +08:00
|
|
|
|
if (newClient==_hostClient)
|
|
|
|
|
{
|
|
|
|
|
_hostClient.SendCustomEvent(CustomEvents.IsHost, true);
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
// Send other players to this client
|
|
|
|
|
Clients.Values.ForEach(target =>
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
if (target==newClient) { return; }
|
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
|
|
|
new Packets.PlayerConnect()
|
2021-11-25 16:32:04 +01:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
// NetHandle = targetNetHandle,
|
|
|
|
|
Username = target.Username,
|
2022-07-01 13:54:18 +08:00
|
|
|
|
PedID=target.Player.ID,
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
}.Pack(outgoingMessage);
|
|
|
|
|
MainNetServer.SendMessage(outgoingMessage, newClient.Connection, NetDeliveryMethod.ReliableOrdered, 0);
|
|
|
|
|
});
|
2022-07-02 17:14:56 +08:00
|
|
|
|
|
|
|
|
|
// Send all props to this player
|
2022-07-03 10:46:24 +08:00
|
|
|
|
BaseScript.SendServerPropsTo( new(Entities.ServerProps.Values), new() { newClient});
|
2022-07-03 15:28:28 +08:00
|
|
|
|
|
|
|
|
|
// Send all blips to this player
|
|
|
|
|
BaseScript.SendServerBlipsTo(new(Entities.Blips.Values), new() { newClient});
|
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
// Send new client to all players
|
|
|
|
|
var cons = MainNetServer.Connections.Exclude(newClient.Connection);
|
|
|
|
|
if (cons.Count!=0)
|
|
|
|
|
{
|
2021-07-07 13:36:25 +02:00
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
2022-01-01 03:07:18 +01:00
|
|
|
|
new Packets.PlayerConnect()
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-07-01 13:54:18 +08:00
|
|
|
|
PedID=newClient.Player.ID,
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Username = newClient.Username
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}.Pack(outgoingMessage);
|
2022-06-23 14:10:16 +08:00
|
|
|
|
|
|
|
|
|
MainNetServer.SendMessage(outgoingMessage,cons , NetDeliveryMethod.ReliableOrdered, 0);
|
|
|
|
|
|
2021-11-25 16:32:04 +01:00
|
|
|
|
}
|
2022-06-04 18:09:42 +08:00
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Info($"Player {newClient.Username} connected!");
|
2021-12-08 09:57:19 +01:00
|
|
|
|
|
2022-06-24 18:25:24 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(Settings.WelcomeMessage))
|
2021-12-08 09:57:19 +01:00
|
|
|
|
{
|
2022-07-22 19:43:48 +08:00
|
|
|
|
ChatMessageReceived("Server",Settings.WelcomeMessage , null);
|
2021-12-08 09:57:19 +01:00
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send all players a message that someone has left the server
|
2022-06-23 14:10:16 +08:00
|
|
|
|
private void SendPlayerDisconnectPacket(Client localClient)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-06-23 14:10:16 +08:00
|
|
|
|
var cons = MainNetServer.Connections.Exclude(localClient.Connection);
|
|
|
|
|
if (cons.Count!=0)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
2022-01-01 03:07:18 +01:00
|
|
|
|
new Packets.PlayerDisconnect()
|
2021-12-08 09:57:19 +01:00
|
|
|
|
{
|
2022-07-01 13:54:18 +08:00
|
|
|
|
PedID=localClient.Player.ID,
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
}.Pack(outgoingMessage);
|
|
|
|
|
MainNetServer.SendMessage(outgoingMessage,cons , NetDeliveryMethod.ReliableOrdered, 0);
|
2021-11-25 16:32:04 +01:00
|
|
|
|
}
|
2022-07-01 19:02:38 +08:00
|
|
|
|
Entities.CleanUp(localClient);
|
2022-06-30 09:28:13 +08:00
|
|
|
|
_worker.QueueJob(() => API.Events.InvokePlayerDisconnected(localClient));
|
2022-07-01 13:54:18 +08:00
|
|
|
|
Logger?.Info($"Player {localClient.Username} disconnected! ID:{localClient.Player.ID}");
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Clients.Remove(localClient.NetID);
|
2022-07-09 19:32:11 +08:00
|
|
|
|
ClientsByName.Remove(localClient.Username);
|
2022-07-10 16:13:08 +08:00
|
|
|
|
if (localClient==_hostClient)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
_hostClient = Clients.Values.FirstOrDefault();
|
|
|
|
|
_hostClient?.SendCustomEvent(CustomEvents.IsHost, true);
|
|
|
|
|
}
|
2022-06-27 13:02:31 +08:00
|
|
|
|
Security.RemoveConnection(localClient.Connection.RemoteEndPoint);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region SyncEntities
|
|
|
|
|
|
2022-06-23 14:10:16 +08:00
|
|
|
|
private void PedSync(Packets.PedSync packet, Client client)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-01 19:02:38 +08:00
|
|
|
|
_worker.QueueJob(() => Entities.Update(packet, client));
|
|
|
|
|
|
2022-07-01 13:54:18 +08:00
|
|
|
|
bool isPlayer = packet.ID==client.Player.ID;
|
2022-06-22 14:18:20 +08:00
|
|
|
|
if (isPlayer)
|
|
|
|
|
{
|
2022-06-30 09:28:13 +08:00
|
|
|
|
_worker.QueueJob(() => API.Events.InvokePlayerUpdate(client));
|
2022-06-22 14:18:20 +08:00
|
|
|
|
}
|
2022-06-06 17:37:11 +08:00
|
|
|
|
|
2022-05-30 14:32:38 +08:00
|
|
|
|
foreach (var c in Clients.Values)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-05-30 14:32:38 +08:00
|
|
|
|
|
2022-05-30 11:11:40 +08:00
|
|
|
|
// Don't send data back
|
2022-05-31 09:14:30 +08:00
|
|
|
|
if (c.NetID==client.NetID) { continue; }
|
2022-05-30 14:32:38 +08:00
|
|
|
|
|
|
|
|
|
// Check streaming distance
|
|
|
|
|
if (isPlayer)
|
|
|
|
|
{
|
2022-06-24 18:25:24 +08:00
|
|
|
|
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
|
2022-05-30 14:32:38 +08:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-24 18:25:24 +08:00
|
|
|
|
else if ((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
|
2022-05-30 14:32:38 +08:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-06-06 17:37:11 +08:00
|
|
|
|
|
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
|
|
|
packet.Pack(outgoingMessage);
|
2022-05-30 11:11:40 +08:00
|
|
|
|
MainNetServer.SendMessage(outgoingMessage,c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2022-06-23 14:10:16 +08:00
|
|
|
|
private void VehicleSync(Packets.VehicleSync packet, Client client)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-01 19:02:38 +08:00
|
|
|
|
_worker.QueueJob(() => Entities.Update(packet, client));
|
|
|
|
|
bool isPlayer = packet.ID==client.Player?.LastVehicle?.ID;
|
2022-05-30 11:11:40 +08:00
|
|
|
|
foreach (var c in Clients.Values)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-05-31 09:14:30 +08:00
|
|
|
|
if (c.NetID==client.NetID) { continue; }
|
2022-05-30 14:32:38 +08:00
|
|
|
|
if (isPlayer)
|
|
|
|
|
{
|
|
|
|
|
// Player's vehicle
|
2022-06-24 18:25:24 +08:00
|
|
|
|
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
|
2022-05-30 14:32:38 +08:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2022-06-24 18:25:24 +08:00
|
|
|
|
else if((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
|
2022-05-30 14:32:38 +08:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-05-22 15:55:26 +08:00
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
|
|
|
packet.Pack(outgoingMessage);
|
2022-05-30 11:11:40 +08:00
|
|
|
|
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
|
|
|
|
}
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-06-23 14:10:16 +08:00
|
|
|
|
private void ProjectileSync(Packets.ProjectileSync packet, Client client)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
|
|
|
|
|
2022-05-30 11:11:40 +08:00
|
|
|
|
foreach (var c in Clients.Values)
|
2021-08-26 17:01:32 +02:00
|
|
|
|
{
|
2022-05-31 09:14:30 +08:00
|
|
|
|
if (c.NetID==client.NetID) { continue; }
|
2021-08-26 17:01:32 +02:00
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
2022-05-25 10:09:59 +08:00
|
|
|
|
packet.Pack(outgoingMessage);
|
2022-05-30 11:11:40 +08:00
|
|
|
|
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
#endregion
|
2021-07-07 13:36:25 +02:00
|
|
|
|
// Send a message to targets or all players
|
2022-07-22 19:43:48 +08:00
|
|
|
|
internal void ChatMessageReceived(string name, string message,Client sender=null)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-07-22 19:43:48 +08:00
|
|
|
|
if (message.StartsWith('/'))
|
2021-08-15 07:54:25 +02:00
|
|
|
|
{
|
2022-07-22 19:43:48 +08:00
|
|
|
|
string[] cmdArgs = message.Split(" ");
|
2022-06-30 09:28:13 +08:00
|
|
|
|
string cmdName = cmdArgs[0].Remove(0, 1);
|
|
|
|
|
_worker.QueueJob(()=>API.Events.InvokeOnCommandReceived(cmdName, cmdArgs, sender));
|
2022-06-04 18:09:42 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-07-22 19:43:48 +08:00
|
|
|
|
message = message.Replace("~", "");
|
2022-07-29 01:08:34 +08:00
|
|
|
|
|
2022-07-29 01:13:32 +08:00
|
|
|
|
_worker.QueueJob(() => API.Events.InvokeOnChatMessage(message, sender));
|
2022-07-29 01:08:34 +08:00
|
|
|
|
|
2022-07-22 19:43:48 +08:00
|
|
|
|
var msg=MainNetServer.CreateMessage();
|
|
|
|
|
new Packets.ChatMessage()
|
|
|
|
|
{
|
|
|
|
|
Username=name,
|
|
|
|
|
Message=message
|
|
|
|
|
}.Pack(msg);
|
2021-12-23 22:03:01 +01:00
|
|
|
|
|
2022-07-28 17:50:41 +08:00
|
|
|
|
MainNetServer.SendToAll(msg, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
|
|
|
|
|
|
2022-07-22 19:43:48 +08:00
|
|
|
|
Logger?.Info(name + ": " + message);
|
2021-12-23 22:03:01 +01:00
|
|
|
|
}
|
2022-07-22 19:43:48 +08:00
|
|
|
|
internal void SendChatMessage(string name, string message, Client target)
|
2021-12-23 22:03:01 +01:00
|
|
|
|
{
|
2022-07-22 19:43:48 +08:00
|
|
|
|
var msg = MainNetServer.CreateMessage();
|
|
|
|
|
new Packets.ChatMessage()
|
|
|
|
|
{
|
|
|
|
|
Username= name,
|
|
|
|
|
Message=message,
|
|
|
|
|
}.Pack(msg);
|
|
|
|
|
MainNetServer.SendMessage(msg, target.Connection, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
|
2021-12-23 22:03:01 +01:00
|
|
|
|
}
|
2021-07-12 05:00:48 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
2021-08-18 11:47:59 +02:00
|
|
|
|
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
2021-12-02 23:05:22 +01:00
|
|
|
|
{
|
|
|
|
|
Command command = new(name) { Usage = usage, ArgsLength = argsLength };
|
|
|
|
|
|
|
|
|
|
if (Commands.ContainsKey(command))
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Command \"" + command.Name + "\" was already been registered!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Commands.Add(command, callback);
|
|
|
|
|
}
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal void RegisterCommand(string name, Action<CommandContext> callback)
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
2021-12-02 23:05:22 +01:00
|
|
|
|
Command command = new(name);
|
2021-08-18 11:47:59 +02:00
|
|
|
|
|
|
|
|
|
if (Commands.ContainsKey(command))
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Command \"" + command.Name + "\" was already been registered!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Commands.Add(command, callback);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal void RegisterCommands<T>()
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
2021-12-02 23:05:22 +01:00
|
|
|
|
IEnumerable<MethodInfo> commands = typeof(T).GetMethods().Where(method => method.GetCustomAttributes(typeof(Command), false).Any());
|
2021-08-18 11:47:59 +02:00
|
|
|
|
|
|
|
|
|
foreach (MethodInfo method in commands)
|
|
|
|
|
{
|
2021-12-02 23:05:22 +01:00
|
|
|
|
Command attribute = method.GetCustomAttribute<Command>(true);
|
2021-08-18 11:47:59 +02:00
|
|
|
|
|
2021-12-02 23:05:22 +01:00
|
|
|
|
RegisterCommand(attribute.Name, attribute.Usage, attribute.ArgsLength, (Action<CommandContext>)Delegate.CreateDelegate(typeof(Action<CommandContext>), method));
|
2021-08-18 11:47:59 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
internal T GetResponse<T>(Client client,Packet request, ConnectionChannel channel = ConnectionChannel.RequestResponse,int timeout=5000) where T:Packet, new()
|
|
|
|
|
{
|
|
|
|
|
if (Thread.CurrentThread==_listenerThread)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Cannot wait for response from the listener thread!");
|
|
|
|
|
}
|
|
|
|
|
var received=new AutoResetEvent(false);
|
|
|
|
|
byte[] response=null;
|
|
|
|
|
var id = NewRequestID();
|
|
|
|
|
PendingResponses.Add(id, (type,p) =>
|
|
|
|
|
{
|
|
|
|
|
response=p;
|
|
|
|
|
received.Set();
|
|
|
|
|
});
|
|
|
|
|
var msg = MainNetServer.CreateMessage();
|
|
|
|
|
msg.Write((byte)PacketType.Request);
|
|
|
|
|
msg.Write(id);
|
|
|
|
|
request.Pack(msg);
|
|
|
|
|
MainNetServer.SendMessage(msg,client.Connection,NetDeliveryMethod.ReliableOrdered,(int)channel);
|
|
|
|
|
if (received.WaitOne(timeout))
|
|
|
|
|
{
|
|
|
|
|
var p = new T();
|
|
|
|
|
p.Unpack(response);
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
|
2022-07-19 17:15:53 +08:00
|
|
|
|
{
|
|
|
|
|
SendFile(File.OpenRead(path), name,client,NewFileID(),updateCallback);
|
|
|
|
|
}
|
|
|
|
|
internal void SendFile(Stream stream, string name, Client client,int id=default, Action<float> updateCallback = null)
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
2022-07-01 12:22:31 +08:00
|
|
|
|
|
2022-07-19 17:15:53 +08:00
|
|
|
|
id = id ==default? NewFileID(): id ;
|
|
|
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
|
|
|
var total = stream.Length;
|
2022-07-01 12:22:31 +08:00
|
|
|
|
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferRequest()
|
|
|
|
|
{
|
|
|
|
|
FileLength= total,
|
|
|
|
|
Name=name,
|
|
|
|
|
ID=id,
|
2022-07-19 17:15:53 +08:00
|
|
|
|
}, ConnectionChannel.File)?.Response!=FileResponse.NeedToDownload)
|
2022-07-01 12:22:31 +08:00
|
|
|
|
{
|
|
|
|
|
Logger?.Info($"Skipping file transfer \"{name}\" to {client.Username}");
|
2022-07-19 17:15:53 +08:00
|
|
|
|
stream.Close();
|
|
|
|
|
stream.Dispose();
|
2022-07-01 12:22:31 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Debug($"Initiating file transfer:{name}, {total}");
|
2022-06-06 17:37:11 +08:00
|
|
|
|
FileTransfer transfer = new()
|
|
|
|
|
{
|
|
|
|
|
ID=id,
|
|
|
|
|
Name = name,
|
|
|
|
|
};
|
2022-07-01 12:22:31 +08:00
|
|
|
|
InProgressFileTransfers.Add(id, transfer);
|
2022-06-11 18:41:10 +08:00
|
|
|
|
int read = 0;
|
2022-07-01 12:22:31 +08:00
|
|
|
|
int thisRead;
|
2022-06-11 18:41:10 +08:00
|
|
|
|
do
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
|
|
|
|
// 4 KB chunk
|
|
|
|
|
byte[] chunk = new byte[4096];
|
2022-07-19 17:15:53 +08:00
|
|
|
|
read += thisRead=stream.Read(chunk, 0, 4096);
|
2022-06-11 18:41:10 +08:00
|
|
|
|
if (thisRead!=chunk.Length)
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
if (thisRead==0) { break; }
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Trace($"Purging chunk:{thisRead}");
|
2022-06-11 18:41:10 +08:00
|
|
|
|
Array.Resize(ref chunk, thisRead);
|
2022-06-06 17:37:11 +08:00
|
|
|
|
}
|
|
|
|
|
Send(
|
|
|
|
|
new Packets.FileTransferChunk()
|
|
|
|
|
{
|
|
|
|
|
ID=id,
|
|
|
|
|
FileChunk=chunk,
|
|
|
|
|
},
|
2022-06-11 18:41:10 +08:00
|
|
|
|
client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered);
|
2022-07-19 17:15:53 +08:00
|
|
|
|
transfer.Progress=read/stream.Length;
|
|
|
|
|
if (updateCallback!=null) { updateCallback(transfer.Progress); }
|
2022-06-11 18:41:10 +08:00
|
|
|
|
|
|
|
|
|
} while (thisRead>0);
|
2022-07-19 17:15:53 +08:00
|
|
|
|
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferComplete()
|
2022-07-01 12:22:31 +08:00
|
|
|
|
{
|
|
|
|
|
ID= id,
|
2022-07-19 17:15:53 +08:00
|
|
|
|
}, ConnectionChannel.File)?.Response!=FileResponse.Completed)
|
2022-07-01 12:22:31 +08:00
|
|
|
|
{
|
|
|
|
|
Logger.Warning($"File trasfer to {client.Username} failed: "+name);
|
2022-07-19 17:15:53 +08:00
|
|
|
|
}
|
|
|
|
|
stream.Close();
|
|
|
|
|
stream.Dispose();
|
2022-06-23 14:10:16 +08:00
|
|
|
|
Logger?.Debug($"All file chunks sent:{name}");
|
2022-06-06 17:37:11 +08:00
|
|
|
|
InProgressFileTransfers.Remove(id);
|
|
|
|
|
}
|
2022-07-19 17:15:53 +08:00
|
|
|
|
internal int NewFileID()
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
|
|
|
|
int ID = 0;
|
|
|
|
|
while ((ID==0)
|
|
|
|
|
|| InProgressFileTransfers.ContainsKey(ID))
|
|
|
|
|
{
|
|
|
|
|
byte[] rngBytes = new byte[4];
|
|
|
|
|
|
|
|
|
|
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
|
|
|
|
|
|
|
|
|
// Convert the bytes into an integer
|
|
|
|
|
ID = BitConverter.ToInt32(rngBytes, 0);
|
|
|
|
|
}
|
|
|
|
|
return ID;
|
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
private int NewRequestID()
|
|
|
|
|
{
|
|
|
|
|
int ID = 0;
|
|
|
|
|
while ((ID==0)
|
|
|
|
|
|| PendingResponses.ContainsKey(ID))
|
|
|
|
|
{
|
|
|
|
|
byte[] rngBytes = new byte[4];
|
|
|
|
|
|
|
|
|
|
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
|
|
|
|
|
|
|
|
|
// Convert the bytes into an integer
|
|
|
|
|
ID = BitConverter.ToInt32(rngBytes, 0);
|
|
|
|
|
}
|
|
|
|
|
return ID;
|
|
|
|
|
}
|
2022-06-24 16:49:59 +08:00
|
|
|
|
internal void Send(Packet p,Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
2022-06-06 17:37:11 +08:00
|
|
|
|
{
|
|
|
|
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
|
|
|
p.Pack(outgoingMessage);
|
|
|
|
|
MainNetServer.SendMessage(outgoingMessage, client.Connection,method,(int)channel);
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
}
|