From a1dda2ffa4f89cd61168e3565f23da9cd80e0d42 Mon Sep 17 00:00:00 2001 From: Sardelka Date: Mon, 6 Jun 2022 17:37:11 +0800 Subject: [PATCH] Fixed three players issue, some work on API and resources management. --- Client/COOPAPI.cs | 192 ------- Client/Main.cs | 2 +- Client/Networking/DownloadManager.cs | 16 +- Client/Networking/Networking.cs | 7 +- Client/Networking/Receive.cs | 21 +- Client/Networking/Send.cs | 2 +- Client/RageCoop.Client.csproj | 6 +- Client/Scripting/API.cs | 141 +++++ Client/Settings.cs | 5 - Client/Sync/Entities/SyncedPed.cs | 46 +- Client/packages.config | 4 + Core/Logging/Logger.cs | 2 +- .../{DownloadPackets.cs => FilePackets.cs} | 34 +- Core/Packets/Packets.cs | 61 +- RAGECOOP.sln | 15 - Resources/Base/ServerBase.cs | 14 +- Server/Allowlist.cs | 1 - Server/Client.cs | 8 +- Server/DownloadManager.cs | 5 +- Server/Entities.cs | 26 - Server/FileTransfer.cs | 16 + Server/Program.cs | 8 +- Server/RageCoop.Server.csproj | 4 + Server/Resources.cs | 47 ++ Server/Scripting/API.cs | 2 - Server/Scripting/Engine.cs | 2 +- Server/Server.cs | 521 +++++++++--------- Server/Util.cs | 4 +- 28 files changed, 559 insertions(+), 653 deletions(-) delete mode 100644 Client/COOPAPI.cs create mode 100644 Client/Scripting/API.cs create mode 100644 Client/packages.config rename Core/Packets/{DownloadPackets.cs => FilePackets.cs} (81%) delete mode 100644 Server/Allowlist.cs delete mode 100644 Server/Entities.cs create mode 100644 Server/FileTransfer.cs create mode 100644 Server/Resources.cs diff --git a/Client/COOPAPI.cs b/Client/COOPAPI.cs deleted file mode 100644 index ce0c57a..0000000 --- a/Client/COOPAPI.cs +++ /dev/null @@ -1,192 +0,0 @@ -#undef DEBUG -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using RageCoop.Core; - -namespace RageCoop.Client -{ - /// - /// ? - /// - public static class COOPAPI - { - - #region DELEGATES - /// - /// ? - /// - /// - /// The player's id - /// - public delegate void ConnectEvent(bool connected, int from, string reason = null); - /// - /// ? - /// - /// - /// The Lidgren-Network net handle - /// - public delegate void ChatMessage(string from, string message, CancelEventArgs args); - /// - /// ? - /// - /// The Lidgren-Network net handle - /// - /// - /// - public delegate void ModEvent(long from, string mod, byte customID, byte[] bytes); - #endregion - - #region EVENTS - /// - /// ? - /// - public static event ConnectEvent OnConnection; - /// - /// ? - /// - public static event ChatMessage OnChatMessage; - - public static void Connected() - { - OnConnection?.Invoke(true, GetPlayerID()); - } - - public static void Disconnected(string reason) - { - OnConnection?.Invoke(false, GetPlayerID(), reason); - } - - public static void Connected(int playerID) - { - OnConnection?.Invoke(true, playerID); - } - - public static void Disconnected(int playerID) - { - OnConnection?.Invoke(false, playerID); - } - - public static bool ChatMessageReceived(string from, string message) - { - CancelEventArgs args = new CancelEventArgs(false); - OnChatMessage?.Invoke(from, message, args); - return args.Cancel; - } - #endregion - - /// - /// Send a local chat message to this player - /// - /// Username of the player who sent this message - /// The player's message - public static void LocalChatMessage(string from, string message) - { - Main.MainChat.AddMessage(from, message); - } - - /// - /// Connect to any server - /// - /// The server address to connect. Example: 127.0.0.1:4499 - public static void Connect(string serverAddress) - { - Networking.ToggleConnection(serverAddress); - } - - /// - /// ? - /// - public static void Disconnect() - { - Networking.ToggleConnection(null); - } - - /// - /// Check if the player is already on a server - /// - public static bool IsOnServer() - { - return Networking.IsOnServer; - } - - /// - /// Get the local player's ID - /// - /// PlayerID - public static int GetPlayerID() - { - return Main.LocalPlayerID; - } - - /// - /// Check if a RAGECOOP menu is visible - /// - public static bool IsMenuVisible() - { -#if NON_INTERACTIVE - return false; -#else - return Menus.CoopMenu.MenuPool.AreAnyVisible; -#endif - } - - /// - /// Check if the RAGECOOP chat is visible - /// - public static bool IsChatFocused() - { - return Main.MainChat.Focused; - } - - /// - /// Check if the RAGECOOP list of players is visible - /// - public static bool IsPlayerListVisible() - { - return Util.GetTickCount64() - PlayerList.Pressed < 5000; - } - - /// - /// Get the version of RAGECOOP - /// - public static string GetCurrentVersion() - { - return Main.CurrentVersion; - } - - /// - /// Get that player's local username - /// - public static string GetUsername() - { - return Main.Settings.Username; - } - - /// - /// Set a new username for this player - /// - /// The new username - /// false if the player already joined a server or the username is null or empty otherwise true - public static bool SetUsername(string username) - { - if (IsOnServer() || string.IsNullOrEmpty(username)) - { - return false; - } - - Main.Settings.Username = username; - - return true; - } - - /// - /// Get or set the client's settings. - /// - /// The client's settings, you should NEVER change settings without notifying the player. - public static Settings Settings() - { - return Main.Settings; - } - } -} diff --git a/Client/Main.cs b/Client/Main.cs index 3c6d094..6249563 100644 --- a/Client/Main.cs +++ b/Client/Main.cs @@ -159,7 +159,7 @@ namespace RageCoop.Client MainChat.Tick(); PlayerList.Tick(); - if (Settings.DisableAutoRespawn) + if (!API.Config.EnableAutoRespawn) { Function.Call(Hash.PAUSE_DEATH_ARREST_RESTART, true); Function.Call(Hash.FORCE_GAME_STATE_PLAYING); diff --git a/Client/Networking/DownloadManager.cs b/Client/Networking/DownloadManager.cs index 34625ff..df0e3e9 100644 --- a/Client/Networking/DownloadManager.cs +++ b/Client/Networking/DownloadManager.cs @@ -7,11 +7,11 @@ namespace RageCoop.Client internal static class DownloadManager { private static readonly List _downloadFiles = new List(); - private static readonly Dictionary _streams = new Dictionary(); - private static readonly List _filesFinished = new List(); + private static readonly Dictionary _streams = new Dictionary(); + private static readonly List _filesFinished = new List(); public static bool DownloadComplete = false; - public static void AddFile(byte id, string name, long length) + public static void AddFile(int id, string name, long length) { string downloadFolder = $"Scripts\\RageCoop\\Resources\\{Main.Settings.LastServerAddress.Replace(":", ".")}"; @@ -29,7 +29,7 @@ namespace RageCoop.Client return; } - if (!new string[] { ".js", ".xml" }.Any(x => x == Path.GetExtension(name))) + if (!Path.GetExtension(name).EndsWith(".zip")) { Cancel(id); @@ -92,7 +92,7 @@ namespace RageCoop.Client } } - public static void Write(byte id, byte[] chunk) + public static void Write(int id, byte[] chunk) { lock (_filesFinished) { @@ -132,7 +132,7 @@ namespace RageCoop.Client } } - public static void Cancel(byte id) + public static void Cancel(int id) { lock (_streams) lock (_downloadFiles) lock (_filesFinished) { @@ -158,7 +158,7 @@ namespace RageCoop.Client { lock (_streams) lock (_downloadFiles) lock (_filesFinished) { - foreach (KeyValuePair stream in _streams) + foreach (var stream in _streams) { stream.Value.Close(); stream.Value.Dispose(); @@ -177,7 +177,7 @@ namespace RageCoop.Client public class DownloadFile { - public byte FileID { get; set; } = 0; + public int FileID { get; set; } = 0; public string FileName { get; set; } = string.Empty; public long FileLength { get; set; } = 0; public long FileWritten { get; set; } = 0; diff --git a/Client/Networking/Networking.cs b/Client/Networking/Networking.cs index f6ac8a7..463e0a9 100644 --- a/Client/Networking/Networking.cs +++ b/Client/Networking/Networking.cs @@ -53,9 +53,10 @@ namespace RageCoop.Client { throw new Exception("Malformed URL"); } - - // Send HandshakePacket + EntityPool.AddPlayer(); + + // Send HandshakePacket NetOutgoingMessage outgoingMessage = Client.CreateMessage(); new Packets.Handshake() { @@ -109,13 +110,11 @@ namespace RageCoop.Client Main.Logger.Debug($"player connected:{p.Username}"); Main.DumpCharacters(); - COOPAPI.Connected(packet.PedID); } private static void PlayerDisconnect(Packets.PlayerDisconnect packet) { var name=PlayerList.GetPlayer(packet.PedID).Username; GTA.UI.Notification.Show($"{name} left."); - COOPAPI.Disconnected(packet.PedID); PlayerList.RemovePlayer(packet.PedID); EntityPool.RemoveAllFromPlayer(packet.PedID); diff --git a/Client/Networking/Receive.cs b/Client/Networking/Receive.cs index 4a59b30..469b055 100644 --- a/Client/Networking/Receive.cs +++ b/Client/Networking/Receive.cs @@ -58,7 +58,6 @@ namespace RageCoop.Client #endif - COOPAPI.Connected(); Main.QueueAction(() => { CoopMenu.ConnectedMenuSetting(); Main.MainChat.Init(); @@ -88,7 +87,6 @@ namespace RageCoop.Client CoopMenu.DisconnectedMenuSetting(); #endif - COOPAPI.Disconnected(reason); Main.QueueAction(() => GTA.UI.Notification.Show("~r~Disconnected: " + reason)); @@ -191,10 +189,8 @@ namespace RageCoop.Client Packets.ChatMessage packet = new Packets.ChatMessage(); packet.Unpack(data); - if (!COOPAPI.ChatMessageReceived(packet.Username, packet.Message)) - { - Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message);return true; }); - } + Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; }); + } break; @@ -218,16 +214,9 @@ namespace RageCoop.Client } break; - case PacketTypes.Mod: + case PacketTypes.FileTransferChunk: { - Packets.Mod packet = new Packets.Mod(); - packet.Unpack(data); - // Need to do some stuff here - } - break; - case PacketTypes.FileTransferTick: - { - Packets.FileTransferTick packet = new Packets.FileTransferTick(); + Packets.FileTransferChunk packet = new Packets.FileTransferChunk(); packet.Unpack(data); DownloadManager.Write(packet.ID, packet.FileChunk); @@ -239,7 +228,7 @@ namespace RageCoop.Client Packets.FileTransferRequest packet = new Packets.FileTransferRequest(); packet.Unpack(data); - DownloadManager.AddFile(packet.ID, packet.FileName, packet.FileLength); + DownloadManager.AddFile(packet.ID, packet.Name, packet.FileLength); } break; diff --git a/Client/Networking/Send.cs b/Client/Networking/Send.cs index 9526764..62b4849 100644 --- a/Client/Networking/Send.cs +++ b/Client/Networking/Send.cs @@ -162,7 +162,7 @@ namespace RageCoop.Client } #endif } - public static void SendDownloadFinish(byte id) + public static void SendDownloadFinish(int id) { NetOutgoingMessage outgoingMessage = Client.CreateMessage(); diff --git a/Client/RageCoop.Client.csproj b/Client/RageCoop.Client.csproj index 03ead99..c4b5fee 100644 --- a/Client/RageCoop.Client.csproj +++ b/Client/RageCoop.Client.csproj @@ -43,6 +43,9 @@ + + ..\packages\DotNetZip.1.16.0\lib\net40\DotNetZip.dll + False ..\Libs\Release\scripts\LemonUI.SHVDN3.dll @@ -88,7 +91,7 @@ - + @@ -113,6 +116,7 @@ + diff --git a/Client/Scripting/API.cs b/Client/Scripting/API.cs new file mode 100644 index 0000000..a7f199f --- /dev/null +++ b/Client/Scripting/API.cs @@ -0,0 +1,141 @@ +#undef DEBUG +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using RageCoop.Core; + +namespace RageCoop.Client +{ + /// + /// ? + /// + public static class API + { + public static class Config + { + /// + /// Enable automatic respawn. + /// + public static bool EnableAutoRespawn { get; set; } = true; + /// + /// Don't show other player's name tag + /// + public static bool DisplayNameTag { get; set; }=true; + /// + /// Show other players' blip on map + /// + public static bool DisplayBlip { get; set; } = true; + } + + #region DELEGATES + /// + /// ? + /// + /// + /// The player's id + /// + public delegate void ConnectEvent(bool connected, int from, string reason = null); + /// + /// ? + /// + /// + /// The Lidgren-Network net handle + /// + public delegate void ChatMessage(string from, string message, CancelEventArgs args); + /// + /// ? + /// + /// The Lidgren-Network net handle + /// + /// + /// + #endregion + + /// + /// ? + /// + public static event ChatMessage OnChatMessage; + /// + /// Send a local chat message to this player + /// + /// Username of the player who sent this message + /// The player's message + public static void LocalChatMessage(string from, string message) + { + Main.MainChat.AddMessage(from, message); + } + + /// + /// Disconnect from the server + /// + public static void Disconnect() + { + Networking.ToggleConnection(null); + } + + /// + /// Check if the player is already on a server + /// + public static bool IsOnServer + { + get { return Networking.IsOnServer; } + } + + /// + /// Get the local player's ID + /// + /// PlayerID + public static int LocalPlayerID + { + get { return Main.LocalPlayerID; } + } + + /// + /// Check if a RAGECOOP menu is visible + /// + public static bool IsMenuVisible + { + get { return Menus.CoopMenu.MenuPool.AreAnyVisible; } + } + + /// + /// Check if the RAGECOOP chat is visible + /// + public static bool IsChatFocused + { + get { return Main.MainChat.Focused; } + } + + /// + /// Check if the RAGECOOP list of players is visible + /// + public static bool IsPlayerListVisible + { + get { return Util.GetTickCount64() - PlayerList.Pressed < 5000; } + } + + /// + /// Get the version of RAGECOOP + /// + public static string CurrentVersion + { + get { return Main.CurrentVersion; } + } + + /// + /// Get or set local player's username, set won't be effective if already connected to a server. + /// + public static string Username + { + get { return Main.Settings.Username; } + set + { + if (IsOnServer || string.IsNullOrEmpty(value)) + { + return; + } + Main.Settings.Username = value; + } + } + } +} diff --git a/Client/Settings.cs b/Client/Settings.cs index 7bc7efb..2b18d1f 100644 --- a/Client/Settings.cs +++ b/Client/Settings.cs @@ -54,10 +54,5 @@ namespace RageCoop.Client /// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended). /// public int WorldVehicleSoftLimit { get; set; } = 35; - - /// - /// Disable automatic respawn. - /// - public bool DisableAutoRespawn { get; set; } = false; } } diff --git a/Client/Sync/Entities/SyncedPed.cs b/Client/Sync/Entities/SyncedPed.cs index 9bc0846..62ba686 100644 --- a/Client/Sync/Entities/SyncedPed.cs +++ b/Client/Sync/Entities/SyncedPed.cs @@ -86,7 +86,7 @@ namespace RageCoop.Client public override void Update() { - if (IsPlayer && PedBlip!=null) + if (IsPlayer) { if (Username=="N/A") @@ -95,10 +95,18 @@ namespace RageCoop.Client if (p!=null) { Username=p.Username; - PedBlip.Name=Username; + if (PedBlip!=null) + { + PedBlip.Name=Username; + } } } + if((!API.Config.DisplayBlip) && (PedBlip!=null)) + { + PedBlip.Delete(); + PedBlip=null; + } RenderNameTag(); } @@ -112,10 +120,6 @@ namespace RageCoop.Client } - - - - bool characterExist = (MainPed != null) && MainPed.Exists(); if (!characterExist) @@ -167,7 +171,6 @@ namespace RageCoop.Client if (Health <= 0 && !MainPed.IsDead) { MainPed.IsInvincible = false; - Main.Logger.Debug($"Killing ped {ID}. Reason:PedDied"); MainPed.Kill(); return; } @@ -188,7 +191,7 @@ namespace RageCoop.Client private void RenderNameTag() { - if (!IsPlayer || !MainPed.IsVisible || !MainPed.IsInRange(Game.Player.Character.Position, 20f)) + if (!API.Config.DisplayNameTag || (MainPed==null) || !MainPed.IsVisible || !MainPed.IsInRange(Game.Player.Character.Position, 20f)) { return; } @@ -269,13 +272,15 @@ namespace RageCoop.Client MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableShockingEvents, true); MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true); - SetClothes(); if (IsPlayer) { - // Add a new blip for the ped - PedBlip=MainPed.AddBlip(); + if (API.Config.DisplayBlip) + { + // Add a new blip for the ped + PedBlip=MainPed.AddBlip(); + } MainPed.AttachedBlip.Color = BlipColor.White; MainPed.AttachedBlip.Scale = 0.8f; MainPed.AttachedBlip.Name =Username; @@ -295,7 +300,7 @@ namespace RageCoop.Client } _lastClothes = Clothes; } - #region Onfoot + #region ONFOOT #region -- VARIABLES -- /// /// The latest character rotation (may not have been applied yet) @@ -567,14 +572,6 @@ namespace RageCoop.Client WalkTo(); } } - private void DisplayInVehicle() - { - if (MainPed.IsOnTurretSeat()) - { - Function.Call(Hash.SET_VEHICLE_TURRET_SPEED_THIS_FRAME, MainPed.CurrentVehicle, 100); - Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z); - } - } #region WEAPON private void CheckCurrentWeapon() @@ -716,5 +713,14 @@ namespace RageCoop.Client return anim; } #endregion + + private void DisplayInVehicle() + { + if (MainPed.IsOnTurretSeat()) + { + Function.Call(Hash.SET_VEHICLE_TURRET_SPEED_THIS_FRAME, MainPed.CurrentVehicle, 100); + Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z); + } + } } } diff --git a/Client/packages.config b/Client/packages.config new file mode 100644 index 0000000..b41cde8 --- /dev/null +++ b/Client/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Core/Logging/Logger.cs b/Core/Logging/Logger.cs index f0d08a3..cbec7bd 100644 --- a/Core/Logging/Logger.cs +++ b/Core/Logging/Logger.cs @@ -74,7 +74,7 @@ namespace RageCoop.Core.Logging if (LogLevel>4) { return; } lock (Buffer) { - string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(),string.Join("\r\n",ex.Message,ex.StackTrace,ex.ToString()), Process.GetCurrentProcess().Id); + string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(),"\r\n"+ex.ToString(), Process.GetCurrentProcess().Id); Buffer+=msg+"\r\n"; } diff --git a/Core/Packets/DownloadPackets.cs b/Core/Packets/FilePackets.cs similarity index 81% rename from Core/Packets/DownloadPackets.cs rename to Core/Packets/FilePackets.cs index 5b8e760..be7527e 100644 --- a/Core/Packets/DownloadPackets.cs +++ b/Core/Packets/FilePackets.cs @@ -6,13 +6,18 @@ using Lidgren.Network; namespace RageCoop.Core { + public enum FileType:byte + { + Resource=0, + Custom=1, + } public partial class Packets { public class FileTransferRequest : Packet { - public byte ID { get; set; } + public int ID { get; set; } - public string FileName { get; set; } + public string Name { get; set; } public long FileLength { get; set; } @@ -24,10 +29,11 @@ namespace RageCoop.Core List byteArray = new List(); // The ID from the download - byteArray.Add(ID); + byteArray.AddInt(ID); + // The name of the file - byte[] nameBytes = Encoding.UTF8.GetBytes(FileName); + byte[] nameBytes = Encoding.UTF8.GetBytes(Name); byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length)); byteArray.AddRange(nameBytes); @@ -46,29 +52,29 @@ namespace RageCoop.Core #region NetIncomingMessageToPacket BitReader reader = new BitReader(array); - ID = reader.ReadByte(); + ID = reader.ReadInt(); int nameArrayLength = reader.ReadInt(); - FileName = reader.ReadString(nameArrayLength); + Name = reader.ReadString(nameArrayLength); FileLength = reader.ReadLong(); #endregion } } - public class FileTransferTick : Packet + public class FileTransferChunk : Packet { - public byte ID { get; set; } + public int ID { get; set; } public byte[] FileChunk { get; set; } public override void Pack(NetOutgoingMessage message) { #region PacketToNetOutGoingMessage - message.Write((byte)PacketTypes.FileTransferTick); + message.Write((byte)PacketTypes.FileTransferChunk); List byteArray = new List(); // The ID from the download - byteArray.Add(ID); + byteArray.AddInt(ID); // The chunk of the file byteArray.AddRange(BitConverter.GetBytes(FileChunk.Length)); @@ -86,7 +92,7 @@ namespace RageCoop.Core #region NetIncomingMessageToPacket BitReader reader = new BitReader(array); - ID = reader.ReadByte(); + ID = reader.ReadInt(); int chunkLength = reader.ReadInt(); FileChunk = reader.ReadByteArray(chunkLength); #endregion @@ -95,7 +101,7 @@ namespace RageCoop.Core public class FileTransferComplete : Packet { - public byte ID { get; set; } + public int ID { get; set; } public override void Pack(NetOutgoingMessage message) { @@ -105,7 +111,7 @@ namespace RageCoop.Core List byteArray = new List(); // The ID from the download - byteArray.Add(ID); + byteArray.AddInt(ID); byte[] result = byteArray.ToArray(); @@ -119,7 +125,7 @@ namespace RageCoop.Core #region NetIncomingMessageToPacket BitReader reader = new BitReader(array); - ID = reader.ReadByte(); + ID = reader.ReadInt(); #endregion } } diff --git a/Core/Packets/Packets.cs b/Core/Packets/Packets.cs index 67b3b46..8abfdbc 100644 --- a/Core/Packets/Packets.cs +++ b/Core/Packets/Packets.cs @@ -123,13 +123,14 @@ namespace RageCoop.Core ChatMessage=10, NativeCall=11, NativeResponse=12, - Mod=13, + //Mod=13, CleanUpWorld=14, - FileTransferTick=15, + + FileTransferChunk=15, FileTransferRequest=16, FileTransferComplete=17, - ServerClientEvent=18, - + + ServerClientEvent = 18, #region Sync #region INTERVAL @@ -236,58 +237,6 @@ namespace RageCoop.Core public partial class Packets { - public class Mod : Packet - { - public string Name { get; set; } - - public byte CustomPacketID { get; set; } - - public byte[] Bytes { get; set; } - - public override void Pack(NetOutgoingMessage message) - { - #region PacketToNetOutGoingMessage - message.Write((byte)PacketTypes.Mod); - - List byteArray = new List(); - - // Write Name - byte[] nameBytes = Encoding.UTF8.GetBytes(Name); - byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length)); - byteArray.AddRange(nameBytes); - - // Write CustomPacketID - byteArray.Add(CustomPacketID); - - // Write Bytes - byteArray.AddRange(BitConverter.GetBytes(Bytes.Length)); - byteArray.AddRange(Bytes); - - byte[] result = byteArray.ToArray(); - - message.Write(result.Length); - message.Write(result); - #endregion - } - - public override void Unpack(byte[] array) - { - #region NetIncomingMessageToPacket - BitReader reader = new BitReader(array); - - // Read Name - int nameLength = reader.ReadInt(); - Name = reader.ReadString(nameLength); - - // Read CustomPacketID - CustomPacketID = reader.ReadByte(); - - // Read Bytes - int bytesLength = reader.ReadInt(); - Bytes = reader.ReadByteArray(bytesLength); - #endregion - } - } public class ChatMessage : Packet { diff --git a/RAGECOOP.sln b/RAGECOOP.sln index 3125dd1..e5ead53 100644 --- a/RAGECOOP.sln +++ b/RAGECOOP.sln @@ -9,10 +9,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client", "Client\R EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Core", "Core\RageCoop.Core.csproj", "{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Resources.Base", "Resources\Base\RageCoop.Resources.Base.csproj", "{9DC11623-8A8B-4D17-B18B-91852922163D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resources", "Resources", "{F49A2617-832B-44DA-9D42-29B5DD09A186}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,21 +41,10 @@ Global {CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Release|Any CPU.Build.0 = Release|Any CPU {CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Release|x64.ActiveCfg = Release|Any CPU {CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Release|x64.Build.0 = Release|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Debug|x64.ActiveCfg = Debug|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Debug|x64.Build.0 = Debug|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Release|Any CPU.Build.0 = Release|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Release|x64.ActiveCfg = Release|Any CPU - {9DC11623-8A8B-4D17-B18B-91852922163D}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9DC11623-8A8B-4D17-B18B-91852922163D} = {F49A2617-832B-44DA-9D42-29B5DD09A186} - EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6CC7EA75-E4FF-4534-8EB6-0AEECF2620B7} EndGlobalSection diff --git a/Resources/Base/ServerBase.cs b/Resources/Base/ServerBase.cs index 6a1d290..56d640f 100644 --- a/Resources/Base/ServerBase.cs +++ b/Resources/Base/ServerBase.cs @@ -1,17 +1,5 @@ using RageCoop.Server.Scripting; namespace RageCoop.Resources.Base { - public class ServerBase :ServerScript - { - public ServerBase() - { - API.RegisterCommand("kick", (ctx) => - { - if (ctx.Args.Length<1) { return; } - var reason = "EAT POOP!"; - if(ctx.Args.Length>=2) { reason=ctx.Args[1]; } - API.GetClientByUsername(ctx.Args[0]).Kick(reason); - }); - } - } + } \ No newline at end of file diff --git a/Server/Allowlist.cs b/Server/Allowlist.cs deleted file mode 100644 index 56e9caa..0000000 --- a/Server/Allowlist.cs +++ /dev/null @@ -1 +0,0 @@ -using System.Collections.Generic; diff --git a/Server/Client.cs b/Server/Client.cs index 173469a..6462873 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -14,9 +14,7 @@ namespace RageCoop.Server private readonly Dictionary _customData = new(); private long _callbacksCount = 0; public readonly Dictionary> Callbacks = new(); - public bool FilesReceived { get;internal set; } = false; - public bool FilesSent = false; - + public bool IsReady { get; internal set; }=false; #region CUSTOMDATA FUNCTIONS public void SetData(string name, T data) { @@ -189,9 +187,9 @@ namespace RageCoop.Server public void SendTriggerEvent(string eventName, params object[] args) { - if (!FilesReceived) + if (!IsReady) { - Program.Logger.Warning($"Player \"{Player.Username}\" doesn't have all the files yet!"); + Program.Logger.Warning($"Player \"{Player.Username}\" is not ready!"); return; } diff --git a/Server/DownloadManager.cs b/Server/DownloadManager.cs index be46c44..23c60b0 100644 --- a/Server/DownloadManager.cs +++ b/Server/DownloadManager.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Collections.Generic; using RageCoop.Core; using Lidgren.Network; - -namespace RageCoop.Server +/* +namespace RageCoop.Server.Obsolete { public static class DownloadManager { @@ -276,3 +276,4 @@ namespace RageCoop.Server public List FileChunks { get; set; } = null; } } +*/ \ No newline at end of file diff --git a/Server/Entities.cs b/Server/Entities.cs deleted file mode 100644 index 9a24fb7..0000000 --- a/Server/Entities.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RageCoop.Core; - -namespace RageCoop.Server -{ - internal static class EntitiesBlah - { - public static Dictionary Peds=new Dictionary(); - public static Dictionary Vehicles = new Dictionary(); - - } - internal class SyncedVehicle - { - public long Owner { get; set; } - // - // public Dictionary Seats=new Dictionary(); - } - internal class SyncedCharacter - { - public long Owner { get; set; } - } -} diff --git a/Server/FileTransfer.cs b/Server/FileTransfer.cs new file mode 100644 index 0000000..ab31bb1 --- /dev/null +++ b/Server/FileTransfer.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RageCoop.Server +{ + internal class FileTransfer + { + public int ID { get; set; } + public float Progress { get; set; } + public string Name { get; set; } + public bool Cancel { get; set; }=false; + } +} diff --git a/Server/Program.cs b/Server/Program.cs index 2ae035c..38925fb 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -33,11 +33,6 @@ namespace RageCoop.Server Console.Title = "RAGECOOP"; #endif - if (File.Exists("log.txt")) - { - File.WriteAllText("log.txt", string.Empty); - } - Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { if (e.SpecialKey == ConsoleSpecialKey.ControlC) @@ -51,8 +46,7 @@ namespace RageCoop.Server } catch (Exception e) { - Program.Logger.Error(e.InnerException?.Message ?? e.Message); - Console.ReadLine(); + Logger.Error($"Fatal error occurred, server shutting down:{e}"); } } diff --git a/Server/RageCoop.Server.csproj b/Server/RageCoop.Server.csproj index 1575644..b57ebe8 100644 --- a/Server/RageCoop.Server.csproj +++ b/Server/RageCoop.Server.csproj @@ -21,6 +21,10 @@ + + + + diff --git a/Server/Resources.cs b/Server/Resources.cs new file mode 100644 index 0000000..54a01d8 --- /dev/null +++ b/Server/Resources.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RageCoop.Server.Scripting; +using System.IO; +using Ionic.Zip; + +namespace RageCoop.Server +{ + internal static class Resources + { + public static readonly Engine ScriptingEngine = new(); + /// + /// Pack client-side resources as a zip file + /// + public static void PackClientFiles() + { + Program.Logger.Info("Packing client side resources"); + } + + public static void LoadAll() + { + var path = Path.Combine("Resources", "Client"); + Directory.CreateDirectory(path); + var clientResources = Directory.GetDirectories(path); + if (clientResources.Length!=0) + { + // Pack client side resources as a zip file + Program.Logger.Info("Packing client-side resources"); + + var zippath = Path.Combine(path, "Resources.zip"); + if (File.Exists(zippath)) + { + File.Delete(zippath); + } + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(path); + zip.Save(zippath); + } + } + ScriptingEngine.LoadAll(); + } + } +} diff --git a/Server/Scripting/API.cs b/Server/Scripting/API.cs index 8262ef0..e272d10 100644 --- a/Server/Scripting/API.cs +++ b/Server/Scripting/API.cs @@ -24,8 +24,6 @@ namespace RageCoop.Server.Scripting public static event EventHandler OnPlayerHandshake; public static event PlayerConnect OnPlayerConnected; public static event PlayerDisconnect OnPlayerDisconnected; - // public static event EventHandler OnPlayerUpdate; - #region INVOKE internal static void InvokeOnStop() { OnStop?.Invoke(); } internal static void InvokeOnChatMessage(Packets.ChatMessage p,NetConnection con) diff --git a/Server/Scripting/Engine.cs b/Server/Scripting/Engine.cs index 16b0c26..3e18ad4 100644 --- a/Server/Scripting/Engine.cs +++ b/Server/Scripting/Engine.cs @@ -24,7 +24,7 @@ namespace RageCoop.Server.Scripting } private void LoadResource(string path) { - foreach(var assembly in Directory.GetFiles(path,"*.dll")) + foreach(var assembly in Directory.GetFiles(path,"*.dll",SearchOption.AllDirectories)) { LoadScriptsFromAssembly(assembly); } diff --git a/Server/Server.cs b/Server/Server.cs index bc2f4e8..486a373 100644 --- a/Server/Server.cs +++ b/Server/Server.cs @@ -12,6 +12,7 @@ using Newtonsoft.Json; using System.Threading.Tasks; using Lidgren.Network; using System.Timers; +using System.Security.Cryptography; using RageCoop.Server.Scripting; namespace RageCoop.Server @@ -35,7 +36,8 @@ namespace RageCoop.Server public static readonly Dictionary Clients = new(); private static System.Timers.Timer SendLatencyTimer = new System.Timers.Timer(5000); - public static readonly Engine ScriptingEngine = new(); + + private static Dictionary InProgressFileTransfers=new(); public Server() { Program.Logger.Info("================"); @@ -169,10 +171,7 @@ namespace RageCoop.Server }).Start(); #endregion } - ScriptingEngine.LoadAll(); - Program.Logger.Info("Searching for client-side files..."); - DownloadManager.CheckForDirectoryAndFiles(); - + Resources.LoadAll(); Listen(); } @@ -192,25 +191,6 @@ namespace RageCoop.Server while (!Program.ReadyToStop) { - // Only new clients that did not receive files on connection will receive the current files in "clientside" - if (DownloadManager.AnyFileExists) - { - lock (Clients) - { - Clients.Values.ToList().ForEach(client => - { - if (!client.FilesSent) - { - DownloadManager.InsertClient(client.NetID); - client.FilesSent = true; - } - }); - } - - DownloadManager.Tick(); - } - - // 15 milliseconds to sleep to reduce CPU usage Thread.Sleep(15); @@ -269,7 +249,6 @@ namespace RageCoop.Server { long nethandle = message.SenderConnection.RemoteUniqueIdentifier; - DownloadManager.RemoveClient(nethandle); SendPlayerDisconnectPacket(nethandle); } @@ -280,251 +259,182 @@ namespace RageCoop.Server break; } case NetIncomingMessageType.Data: - // Get packet type - byte btype = message.ReadByte(); - var type = (PacketTypes)btype; - switch (type) { + // Get packet type + byte btype = message.ReadByte(); + var type = (PacketTypes)btype; + int len = message.ReadInt32(); + byte[] data = message.ReadBytes(len); + try + { - #region SyncData - - case PacketTypes.PedStateSync: + switch (type) { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - Packets.PedStateSync packet = new(); - packet.Unpack(data); + #region SyncData - PedStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier); - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - case PacketTypes.VehicleStateSync: - { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - - Packets.VehicleStateSync packet = new(); - packet.Unpack(data); - - VehicleStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier); - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - case PacketTypes.PedSync: - { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - - Packets.PedSync packet = new(); - packet.Unpack(data); - - PedSync(packet, message.SenderConnection.RemoteUniqueIdentifier); - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - case PacketTypes.VehicleSync: - { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - - Packets.VehicleSync packet = new(); - packet.Unpack(data); - - VehicleSync(packet, message.SenderConnection.RemoteUniqueIdentifier); - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - case PacketTypes.ProjectileSync: - { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - - Packets.ProjectileSync packet = new(); - packet.Unpack(data); - ProjectileSync(packet, message.SenderConnection.RemoteUniqueIdentifier); - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - - - #endregion - - case PacketTypes.ChatMessage: - { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - - Packets.ChatMessage packet = new(); - packet.Unpack(data); - - API.Events.InvokeOnChatMessage(packet,message.SenderConnection); - SendChatMessage(packet); - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - - case PacketTypes.NativeResponse: - { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - - Packets.NativeResponse packet = new(); - packet.Unpack(data); - - Client client = Util.GetClientByNetID(message.SenderConnection.RemoteUniqueIdentifier); - if (client != null) + case PacketTypes.PedStateSync: { - if (client.Callbacks.ContainsKey(packet.ID)) + Packets.PedStateSync packet = new(); + packet.Unpack(data); + + PedStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier); + break; + } + case PacketTypes.VehicleStateSync: + { + Packets.VehicleStateSync packet = new(); + packet.Unpack(data); + + VehicleStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier); + + break; + } + case PacketTypes.PedSync: + { + + Packets.PedSync packet = new(); + packet.Unpack(data); + + PedSync(packet, message.SenderConnection.RemoteUniqueIdentifier); + + } + break; + case PacketTypes.VehicleSync: + { + Packets.VehicleSync packet = new(); + packet.Unpack(data); + + VehicleSync(packet, message.SenderConnection.RemoteUniqueIdentifier); + + } + break; + case PacketTypes.ProjectileSync: + { + + Packets.ProjectileSync packet = new(); + packet.Unpack(data); + ProjectileSync(packet, message.SenderConnection.RemoteUniqueIdentifier); + + } + break; + + + #endregion + + case PacketTypes.ChatMessage: + { + try { - client.Callbacks[packet.ID].Invoke(packet.Args[0]); - client.Callbacks.Remove(packet.ID); + + Packets.ChatMessage packet = new(); + packet.Unpack(data); + + API.Events.InvokeOnChatMessage(packet, message.SenderConnection); + SendChatMessage(packet); + } + catch (Exception e) + { + DisconnectAndLog(message.SenderConnection, type, e); } } - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - case PacketTypes.FileTransferComplete: - { - try - { - if (DownloadManager.AnyFileExists) - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); + break; - Packets.FileTransferComplete packet = new(); + case PacketTypes.NativeResponse: + { + Packets.NativeResponse packet = new(); packet.Unpack(data); Client client = Util.GetClientByNetID(message.SenderConnection.RemoteUniqueIdentifier); - if (client != null && !client.FilesReceived) + if (client != null) { - DownloadManager.TryToRemoveClient(client.NetID, packet.ID); - } - } - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - case PacketTypes.ServerClientEvent: - { - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - - Packets.ServerClientEvent packet = new Packets.ServerClientEvent(); - packet.Unpack(data); - - long senderNetHandle = message.SenderConnection.RemoteUniqueIdentifier; - Client client = null; - lock (Clients) - { - client = Util.GetClientByNetID(senderNetHandle); - } - - if (client != null) - { - if (TriggerEvents.Any(x => x.Key.EventName == packet.EventName)) - { - EventContext ctx = new() + if (client.Callbacks.ContainsKey(packet.ID)) { - Client = client, - Args = packet.Args.ToArray() - }; - - TriggerEvents.FirstOrDefault(x => x.Key.EventName == packet.EventName).Value?.Invoke(ctx); - } - else - { - Program.Logger.Warning($"Player \"{client.Player.Username}\" attempted to trigger an unknown event! [{packet.EventName}]"); + client.Callbacks[packet.ID].Invoke(packet.Args[0]); + client.Callbacks.Remove(packet.ID); + } } } - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } - } - break; - default: - if (type.IsSyncEvent()) - { - // Sync Events - try - { - int len = message.ReadInt32(); - byte[] data = message.ReadBytes(len); - NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); - outgoingMessage.Write(btype); - outgoingMessage.Write(len); - outgoingMessage.Write(data); - MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != message.SenderConnection.RemoteUniqueIdentifier).ForEach(x => + break; + case PacketTypes.ServerClientEvent: { + Packets.ServerClientEvent packet = new Packets.ServerClientEvent(); + packet.Unpack(data); - MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync); + long senderNetHandle = message.SenderConnection.RemoteUniqueIdentifier; + Client client = null; + lock (Clients) + { + client = Util.GetClientByNetID(senderNetHandle); + } - }); - } - catch (Exception e) - { - DisconnectAndLog(message.SenderConnection, type, e); - } + if (client != null) + { + if (TriggerEvents.Any(x => x.Key.EventName == packet.EventName)) + { + EventContext ctx = new() + { + Client = client, + Args = packet.Args.ToArray() + }; + + TriggerEvents.FirstOrDefault(x => x.Key.EventName == packet.EventName).Value?.Invoke(ctx); + } + else + { + Program.Logger.Warning($"Player \"{client.Player.Username}\" attempted to trigger an unknown event! [{packet.EventName}]"); + } + } + } + break; + case PacketTypes.FileTransferComplete: + { + Packets.FileTransferComplete packet = new Packets.FileTransferComplete(); + packet.Unpack(data); + FileTransfer toRemove; + + // Cancel the download if it's in progress + if (InProgressFileTransfers.TryGetValue(packet.ID,out toRemove)) + { + toRemove.Cancel=true; + } + } + break; + default: + if (type.IsSyncEvent()) + { + // Sync Events + try + { + var outgoingMessage = MainNetServer.CreateMessage(); + outgoingMessage.Write(btype); + outgoingMessage.Write(len); + outgoingMessage.Write(data); + var toSend = MainNetServer.Connections.Exclude(message.SenderConnection); + if (toSend.Count!=0) + { + MainNetServer.SendMessage(outgoingMessage, toSend, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.SyncEvents); + } + } + catch (Exception e) + { + DisconnectAndLog(message.SenderConnection, type, e); + } + } + else + { + Program.Logger.Error("Unhandled Data / Packet type"); + } + break; } - else - { - Program.Logger.Error("Unhandled Data / Packet type"); - } - break; + } + catch (Exception e) + { + DisconnectAndLog(message.SenderConnection, type, e); + } + break; } - break; case NetIncomingMessageType.ConnectionLatencyUpdated: { Client client = Util.GetClientByNetID(message.SenderConnection.RemoteUniqueIdentifier); @@ -579,7 +489,7 @@ namespace RageCoop.Server senderConnection.Disconnect(e.Message); } - #region -- PLAYER -- + #region -- SYNC -- // Before we approve the connection, we must shake hands private void GetHandshake(NetConnection connection, Packets.Handshake packet) { @@ -649,7 +559,7 @@ namespace RageCoop.Server return; } - Program.Logger.Info($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}"); + Program.Logger.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}"); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); // Create a new handshake packet @@ -673,18 +583,20 @@ namespace RageCoop.Server return; } - List clients; - if ((clients = Util.FilterAllLocal(local)).Count > 0) + List clients=MainNetServer.Connections.Exclude(local); + // Send all players to local + + + if (clients.Count > 0) { - // Send all players to local - clients.ForEach(targetPlayer => + clients.ForEach(targetPlayer => { long targetNetHandle = targetPlayer.RemoteUniqueIdentifier; + NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); Client targetClient = Util.GetClientByNetID(targetNetHandle); if (targetClient != null) { - NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); new Packets.PlayerConnect() { // NetHandle = targetNetHandle, @@ -700,11 +612,13 @@ namespace RageCoop.Server NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); new Packets.PlayerConnect() { - // NetHandle = local.RemoteUniqueIdentifier, PedID=localClient.Player.PedID, Username = localClient.Player.Username }.Pack(outgoingMessage); - MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0); + if(clients.Count > 0) + { + MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0); + } } API.Events.InvokePlayerConnected(localClient); @@ -757,10 +671,11 @@ namespace RageCoop.Server } - NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); - packet.Pack(outgoingMessage); + foreach (var c in Clients.Values) { + NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); + packet.Pack(outgoingMessage); if (c.NetID==client.NetID) { continue; } MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync); } @@ -796,8 +711,7 @@ namespace RageCoop.Server } bool isPlayer = packet.ID==client.Player.PedID; if (isPlayer) { client.Player.Position=packet.Position; } - NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); - packet.Pack(outgoingMessage); + foreach (var c in Clients.Values) { @@ -816,6 +730,9 @@ namespace RageCoop.Server { continue; } + + NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); + packet.Pack(outgoingMessage); MainNetServer.SendMessage(outgoingMessage,c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync); } } @@ -990,5 +907,89 @@ namespace RageCoop.Server RegisterEvent(attribute.EventName, (Action)Delegate.CreateDelegate(typeof(Action), method)); } } + public static void SendFile(FileStream fs,string name,Client client,Action updateCallback=null) + { + int id = RequestFileID(); + FileTransfer transfer = new() + { + ID=id, + Name = name, + }; + InProgressFileTransfers.Add(id,transfer); + fs.Seek(0, SeekOrigin.Begin); + Send( + new Packets.FileTransferRequest() + { + FileLength= fs.Length, + Name=name, + ID=id, + }, + client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered + ); + while (fs.CanRead && (!transfer.Cancel)) + { + // 4 KB chunk + byte[] chunk = new byte[4096]; + int read = fs.Read(chunk, 0, chunk.Length); + if (read!=chunk.Length) + { + // EOF reached + var newchunk = new byte[read]; + Array.Copy(chunk, 0, newchunk, 0, read); + chunk=newchunk; + } + Send( + new Packets.FileTransferChunk() + { + ID=id, + FileChunk=chunk, + }, + client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered + ); + transfer.Progress=fs.Position/fs.Length; + if (updateCallback!=null) { updateCallback(transfer.Progress);} + }; + Send( + new Packets.FileTransferComplete() + { + ID= id, + } + , client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered + ); + InProgressFileTransfers.Remove(id); + } + public static async void SendFileAsync(FileStream fs, string name, Client client,Action updateCallback=null,Action completedCallback=null) + { + SendFile(fs, name, client,updateCallback); + if(completedCallback!=null) { completedCallback(); } + } + public static int RequestFileID() + { + 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; + } + + /// + /// Pack the packet then send to server. + /// + /// + /// + /// + public static void Send(Packet p,Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced) + { + NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); + p.Pack(outgoingMessage); + MainNetServer.SendMessage(outgoingMessage, client.Connection,method,(int)channel); + } } } diff --git a/Server/Util.cs b/Server/Util.cs index 58e10f5..9e69d8b 100644 --- a/Server/Util.cs +++ b/Server/Util.cs @@ -76,9 +76,9 @@ namespace RageCoop.Server } // Return a list of all connections but not the local connection - public static List FilterAllLocal(NetConnection local) + public static List Exclude(this IEnumerable connections,NetConnection toExclude) { - return new(Server.MainNetServer.Connections.Where(e => e != local)); + return new(connections.Where(e => e != toExclude)); } public static List FilterAllLocal(long local) {