Use BlockingCollection + Small performance tweaks

This commit is contained in:
Mitchell Kutchuk 2015-05-24 17:33:43 -07:00
parent 7c8309171b
commit a2b760e527
5 changed files with 46 additions and 35 deletions

View File

@ -31,14 +31,14 @@ namespace TrueCraft.Client.Handlers
&& packet.Depth == Chunk.Depth) // Fast path && packet.Depth == Chunk.Depth) // Fast path
{ {
// Block IDs // Block IDs
Array.Copy(data, 0, chunk.Blocks, 0, chunk.Blocks.Length); Buffer.BlockCopy(data, 0, chunk.Blocks, 0, chunk.Blocks.Length);
// Block metadata // 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 // 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); chunk.BlockLight.Data, 0, chunk.BlockLight.Data.Length);
// Sky light // 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); chunk.SkyLight.Data, 0, chunk.SkyLight.Data.Length);
} }
else // Slow path else // Slow path

View File

@ -31,14 +31,14 @@ namespace TrueCraft.Client
private TcpClient Client { get; set; } private TcpClient Client { get; set; }
private IMinecraftStream Stream { get; set; } private IMinecraftStream Stream { get; set; }
private PacketReader PacketReader { get; set; } private PacketReader PacketReader { get; set; }
private ConcurrentQueue<IPacket> PacketQueue { get; set; } private BlockingCollection<IPacket> PacketQueue { get; set; }
private Thread NetworkWorker { get; set; } private Thread NetworkWorker { get; set; }
private readonly PacketHandler[] PacketHandlers; private readonly PacketHandler[] PacketHandlers;
public MultiplayerClient() public MultiplayerClient()
{ {
Client = new TcpClient(); Client = new TcpClient();
PacketQueue = new ConcurrentQueue<IPacket>(); PacketQueue = new BlockingCollection<IPacket>(new ConcurrentQueue<IPacket>());
PacketReader = new PacketReader(); PacketReader = new PacketReader();
PacketReader.RegisterCorePackets(); PacketReader.RegisterCorePackets();
NetworkWorker = new Thread(new ThreadStart(DoNetwork)); NetworkWorker = new Thread(new ThreadStart(DoNetwork));
@ -71,7 +71,7 @@ namespace TrueCraft.Client
public void QueuePacket(IPacket packet) public void QueuePacket(IPacket packet)
{ {
PacketQueue.Enqueue(packet); PacketQueue.Add(packet);
} }
private void ConnectionComplete(IAsyncResult result) private void ConnectionComplete(IAsyncResult result)
@ -101,9 +101,12 @@ namespace TrueCraft.Client
while (PacketQueue.Any() && DateTime.Now < limit) while (PacketQueue.Any() && DateTime.Now < limit)
{ {
idle = false; idle = false;
while (!PacketQueue.TryDequeue(out packet)) { }
PacketReader.WritePacket(Stream, packet); if (PacketQueue.TryTake(out packet, 100))
Stream.BaseStream.Flush(); {
PacketReader.WritePacket(Stream, packet);
Stream.BaseStream.Flush();
}
} }
if (idle) if (idle)
Thread.Sleep(100); Thread.Sleep(100);

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Linq.Expressions;
using TrueCraft.API.Networking; using TrueCraft.API.Networking;
using TrueCraft.Core.Networking.Packets; using TrueCraft.Core.Networking.Packets;
@ -9,8 +10,8 @@ namespace TrueCraft.Core.Networking
public static readonly int Version = 14; public static readonly int Version = 14;
public int ProtocolVersion { get { return Version; } } public int ProtocolVersion { get { return Version; } }
private Type[] ClientboundPackets = new Type[0x100]; private Func<IPacket>[] ClientboundPackets = new Func<IPacket>[0x100];
private Type[] ServerboundPackets = new Type[0x100]; private Func<IPacket>[] ServerboundPackets = new Func<IPacket>[0x100];
/// <summary> /// <summary>
/// Registers TrueCraft.Core implementations of all packets used by vanilla Minecraft. /// Registers TrueCraft.Core implementations of all packets used by vanilla Minecraft.
@ -89,24 +90,26 @@ namespace TrueCraft.Core.Networking
public void RegisterPacketType<T>(bool clientbound = true, bool serverbound = true) where T : IPacket public void RegisterPacketType<T>(bool clientbound = true, bool serverbound = true) where T : IPacket
{ {
var packet = (IPacket)Activator.CreateInstance(typeof(T)); var func = Expression.Lambda<Func<IPacket>>(Expression.Convert(Expression.New(typeof(T)), typeof(IPacket))).Compile();
var packet = func();
if (clientbound) if (clientbound)
ClientboundPackets[packet.ID] = typeof(T); ClientboundPackets[packet.ID] = func;
if (serverbound) if (serverbound)
ServerboundPackets[packet.ID] = typeof(T); ServerboundPackets[packet.ID] = func;
} }
public IPacket ReadPacket(IMinecraftStream stream, bool serverbound = true) public IPacket ReadPacket(IMinecraftStream stream, bool serverbound = true)
{ {
var id = stream.ReadUInt8(); var id = stream.ReadUInt8();
Type type; Func<IPacket> createPacket;
if (serverbound) if (serverbound)
type = ServerboundPackets[id]; createPacket = ServerboundPackets[id];
else else
type = ClientboundPackets[id]; createPacket = ClientboundPackets[id];
if (type == null) if (createPacket == null)
throw new NotSupportedException("Unable to read packet type 0x" + id.ToString("X2")); throw new NotSupportedException("Unable to read packet type 0x" + id.ToString("X2"));
var instance = (IPacket)Activator.CreateInstance(type); var instance = createPacket();
instance.ReadPacket(stream); instance.ReadPacket(stream);
return instance; return instance;
} }

View File

@ -274,21 +274,26 @@ namespace TrueCraft
RemoteClient client; RemoteClient client;
lock (ClientLock) lock (ClientLock)
client = Clients[i] as RemoteClient; client = Clients[i] as RemoteClient;
if (client == null)
continue;
while (client.PacketQueue.Count != 0) while (client.PacketQueue.Count != 0)
{ {
idle = false; idle = false;
try try
{ {
IPacket packet; IPacket packet;
while (!client.PacketQueue.TryDequeue(out packet)) if (client.PacketQueue.TryTake(out packet))
;
LogPacket(packet, false);
PacketReader.WritePacket(client.MinecraftStream, packet);
client.MinecraftStream.BaseStream.Flush();
if (packet is DisconnectPacket)
{ {
DisconnectClient(client); LogPacket(packet, false);
break; PacketReader.WritePacket(client.MinecraftStream, packet);
client.MinecraftStream.BaseStream.Flush();
if (packet is DisconnectPacket)
{
DisconnectClient(client);
break;
}
} }
} }
catch (SocketException e) catch (SocketException e)

View File

@ -29,7 +29,7 @@ namespace TrueCraft
{ {
NetworkStream = stream; NetworkStream = stream;
MinecraftStream = new MinecraftStream(new TrueCraft.Core.Networking.BufferedStream(NetworkStream)); MinecraftStream = new MinecraftStream(new TrueCraft.Core.Networking.BufferedStream(NetworkStream));
PacketQueue = new ConcurrentQueue<IPacket>(); PacketQueue = new BlockingCollection<IPacket>(new ConcurrentQueue<IPacket>());
LoadedChunks = new List<Coordinates2D>(); LoadedChunks = new List<Coordinates2D>();
Server = server; Server = server;
Inventory = new InventoryWindow(server.CraftingRepository); Inventory = new InventoryWindow(server.CraftingRepository);
@ -52,7 +52,7 @@ namespace TrueCraft
public NetworkStream NetworkStream { get; set; } public NetworkStream NetworkStream { get; set; }
public IMinecraftStream MinecraftStream { get; internal set; } public IMinecraftStream MinecraftStream { get; internal set; }
public ConcurrentQueue<IPacket> PacketQueue { get; private set; } public BlockingCollection<IPacket> PacketQueue { get; private set; }
public string Username { get; internal set; } public string Username { get; internal set; }
public bool LoggedIn { get; internal set; } public bool LoggedIn { get; internal set; }
public IMultiplayerServer Server { get; set; } public IMultiplayerServer Server { get; set; }
@ -191,7 +191,7 @@ namespace TrueCraft
public void QueuePacket(IPacket packet) public void QueuePacket(IPacket packet)
{ {
PacketQueue.Enqueue(packet); PacketQueue.Add(packet);
} }
public void SendMessage(string message) public void SendMessage(string message)
@ -321,10 +321,10 @@ namespace TrueCraft
byte[] data = new byte[bytesPerChunk]; byte[] data = new byte[bytesPerChunk];
Array.Copy(chunk.Blocks, 0, data, 0, chunk.Blocks.Length); Buffer.BlockCopy(chunk.Blocks, 0, data, 0, chunk.Blocks.Length);
Array.Copy(chunk.Metadata.Data, 0, data, chunk.Blocks.Length, chunk.Metadata.Data.Length); Buffer.BlockCopy(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); Buffer.BlockCopy(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.SkyLight.Data, 0, data, chunk.Blocks.Length + chunk.Metadata.Data.Length
+ chunk.BlockLight.Data.Length, chunk.SkyLight.Data.Length); + chunk.BlockLight.Data.Length, chunk.SkyLight.Data.Length);
var result = ZlibStream.CompressBuffer(data); var result = ZlibStream.CompressBuffer(data);