diff --git a/TrueCraft.Client/Handlers/ChunkHandler.cs b/TrueCraft.Client/Handlers/ChunkHandler.cs index 44c5b3f..2710be6 100644 --- a/TrueCraft.Client/Handlers/ChunkHandler.cs +++ b/TrueCraft.Client/Handlers/ChunkHandler.cs @@ -31,14 +31,14 @@ namespace TrueCraft.Client.Handlers && packet.Depth == Chunk.Depth) // Fast path { // Block IDs - Array.Copy(data, 0, chunk.Blocks, 0, chunk.Blocks.Length); + Buffer.BlockCopy(data, 0, chunk.Blocks, 0, chunk.Blocks.Length); // Block metadata - Array.Copy(data, chunk.Blocks.Length, chunk.Metadata.Data, 0, chunk.Metadata.Data.Length); + Buffer.BlockCopy(data, chunk.Blocks.Length, chunk.Metadata.Data, 0, chunk.Metadata.Data.Length); // Block light - Array.Copy(data, chunk.Blocks.Length + chunk.Metadata.Data.Length, + Buffer.BlockCopy(data, chunk.Blocks.Length + chunk.Metadata.Data.Length, chunk.BlockLight.Data, 0, chunk.BlockLight.Data.Length); // Sky light - Array.Copy(data, chunk.Blocks.Length + chunk.Metadata.Data.Length + chunk.BlockLight.Data.Length, + Buffer.BlockCopy(data, chunk.Blocks.Length + chunk.Metadata.Data.Length + chunk.BlockLight.Data.Length, chunk.SkyLight.Data, 0, chunk.SkyLight.Data.Length); } else // Slow path diff --git a/TrueCraft.Client/MultiplayerClient.cs b/TrueCraft.Client/MultiplayerClient.cs index 7fbebcb..2b1422e 100644 --- a/TrueCraft.Client/MultiplayerClient.cs +++ b/TrueCraft.Client/MultiplayerClient.cs @@ -31,14 +31,14 @@ namespace TrueCraft.Client private TcpClient Client { get; set; } private IMinecraftStream Stream { get; set; } private PacketReader PacketReader { get; set; } - private ConcurrentQueue PacketQueue { get; set; } + private BlockingCollection PacketQueue { get; set; } private Thread NetworkWorker { get; set; } private readonly PacketHandler[] PacketHandlers; public MultiplayerClient() { Client = new TcpClient(); - PacketQueue = new ConcurrentQueue(); + PacketQueue = new BlockingCollection(new ConcurrentQueue()); PacketReader = new PacketReader(); PacketReader.RegisterCorePackets(); NetworkWorker = new Thread(new ThreadStart(DoNetwork)); @@ -71,7 +71,7 @@ namespace TrueCraft.Client public void QueuePacket(IPacket packet) { - PacketQueue.Enqueue(packet); + PacketQueue.Add(packet); } private void ConnectionComplete(IAsyncResult result) @@ -101,9 +101,12 @@ namespace TrueCraft.Client while (PacketQueue.Any() && DateTime.Now < limit) { idle = false; - while (!PacketQueue.TryDequeue(out packet)) { } - PacketReader.WritePacket(Stream, packet); - Stream.BaseStream.Flush(); + + if (PacketQueue.TryTake(out packet, 100)) + { + PacketReader.WritePacket(Stream, packet); + Stream.BaseStream.Flush(); + } } if (idle) Thread.Sleep(100); diff --git a/TrueCraft.Core/Networking/PacketReader.cs b/TrueCraft.Core/Networking/PacketReader.cs index d781e29..f281ce5 100644 --- a/TrueCraft.Core/Networking/PacketReader.cs +++ b/TrueCraft.Core/Networking/PacketReader.cs @@ -1,4 +1,5 @@ using System; +using System.Linq.Expressions; using TrueCraft.API.Networking; using TrueCraft.Core.Networking.Packets; @@ -9,8 +10,8 @@ namespace TrueCraft.Core.Networking public static readonly int Version = 14; public int ProtocolVersion { get { return Version; } } - private Type[] ClientboundPackets = new Type[0x100]; - private Type[] ServerboundPackets = new Type[0x100]; + private Func[] ClientboundPackets = new Func[0x100]; + private Func[] ServerboundPackets = new Func[0x100]; /// /// Registers TrueCraft.Core implementations of all packets used by vanilla Minecraft. @@ -89,24 +90,26 @@ namespace TrueCraft.Core.Networking public void RegisterPacketType(bool clientbound = true, bool serverbound = true) where T : IPacket { - var packet = (IPacket)Activator.CreateInstance(typeof(T)); + var func = Expression.Lambda>(Expression.Convert(Expression.New(typeof(T)), typeof(IPacket))).Compile(); + var packet = func(); + if (clientbound) - ClientboundPackets[packet.ID] = typeof(T); + ClientboundPackets[packet.ID] = func; if (serverbound) - ServerboundPackets[packet.ID] = typeof(T); + ServerboundPackets[packet.ID] = func; } public IPacket ReadPacket(IMinecraftStream stream, bool serverbound = true) { var id = stream.ReadUInt8(); - Type type; + Func createPacket; if (serverbound) - type = ServerboundPackets[id]; + createPacket = ServerboundPackets[id]; else - type = ClientboundPackets[id]; - if (type == null) + createPacket = ClientboundPackets[id]; + if (createPacket == null) throw new NotSupportedException("Unable to read packet type 0x" + id.ToString("X2")); - var instance = (IPacket)Activator.CreateInstance(type); + var instance = createPacket(); instance.ReadPacket(stream); return instance; } diff --git a/TrueCraft/MultiplayerServer.cs b/TrueCraft/MultiplayerServer.cs index 6d5a2ea..7c3d95a 100644 --- a/TrueCraft/MultiplayerServer.cs +++ b/TrueCraft/MultiplayerServer.cs @@ -274,21 +274,26 @@ namespace TrueCraft RemoteClient client; lock (ClientLock) client = Clients[i] as RemoteClient; + + if (client == null) + continue; + while (client.PacketQueue.Count != 0) { idle = false; try { IPacket packet; - while (!client.PacketQueue.TryDequeue(out packet)) - ; - LogPacket(packet, false); - PacketReader.WritePacket(client.MinecraftStream, packet); - client.MinecraftStream.BaseStream.Flush(); - if (packet is DisconnectPacket) + if (client.PacketQueue.TryTake(out packet)) { - DisconnectClient(client); - break; + LogPacket(packet, false); + PacketReader.WritePacket(client.MinecraftStream, packet); + client.MinecraftStream.BaseStream.Flush(); + if (packet is DisconnectPacket) + { + DisconnectClient(client); + break; + } } } catch (SocketException e) diff --git a/TrueCraft/RemoteClient.cs b/TrueCraft/RemoteClient.cs index f69cb2f..0ab591d 100644 --- a/TrueCraft/RemoteClient.cs +++ b/TrueCraft/RemoteClient.cs @@ -29,7 +29,7 @@ namespace TrueCraft { NetworkStream = stream; MinecraftStream = new MinecraftStream(new TrueCraft.Core.Networking.BufferedStream(NetworkStream)); - PacketQueue = new ConcurrentQueue(); + PacketQueue = new BlockingCollection(new ConcurrentQueue()); LoadedChunks = new List(); Server = server; Inventory = new InventoryWindow(server.CraftingRepository); @@ -52,7 +52,7 @@ namespace TrueCraft public NetworkStream NetworkStream { get; set; } public IMinecraftStream MinecraftStream { get; internal set; } - public ConcurrentQueue PacketQueue { get; private set; } + public BlockingCollection PacketQueue { get; private set; } public string Username { get; internal set; } public bool LoggedIn { get; internal set; } public IMultiplayerServer Server { get; set; } @@ -191,7 +191,7 @@ namespace TrueCraft public void QueuePacket(IPacket packet) { - PacketQueue.Enqueue(packet); + PacketQueue.Add(packet); } public void SendMessage(string message) @@ -321,10 +321,10 @@ namespace TrueCraft byte[] data = new byte[bytesPerChunk]; - Array.Copy(chunk.Blocks, 0, data, 0, chunk.Blocks.Length); - Array.Copy(chunk.Metadata.Data, 0, data, chunk.Blocks.Length, chunk.Metadata.Data.Length); - Array.Copy(chunk.BlockLight.Data, 0, data, chunk.Blocks.Length + chunk.Metadata.Data.Length, chunk.BlockLight.Data.Length); - Array.Copy(chunk.SkyLight.Data, 0, data, chunk.Blocks.Length + chunk.Metadata.Data.Length + Buffer.BlockCopy(chunk.Blocks, 0, data, 0, chunk.Blocks.Length); + Buffer.BlockCopy(chunk.Metadata.Data, 0, data, chunk.Blocks.Length, chunk.Metadata.Data.Length); + Buffer.BlockCopy(chunk.BlockLight.Data, 0, data, chunk.Blocks.Length + chunk.Metadata.Data.Length, chunk.BlockLight.Data.Length); + Buffer.BlockCopy(chunk.SkyLight.Data, 0, data, chunk.Blocks.Length + chunk.Metadata.Data.Length + chunk.BlockLight.Data.Length, chunk.SkyLight.Data.Length); var result = ZlibStream.CompressBuffer(data);