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
{
// 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

View File

@ -31,14 +31,14 @@ namespace TrueCraft.Client
private TcpClient Client { get; set; }
private IMinecraftStream Stream { 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 readonly PacketHandler[] PacketHandlers;
public MultiplayerClient()
{
Client = new TcpClient();
PacketQueue = new ConcurrentQueue<IPacket>();
PacketQueue = new BlockingCollection<IPacket>(new ConcurrentQueue<IPacket>());
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);

View File

@ -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<IPacket>[] ClientboundPackets = new Func<IPacket>[0x100];
private Func<IPacket>[] ServerboundPackets = new Func<IPacket>[0x100];
/// <summary>
/// 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
{
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)
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<IPacket> 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;
}

View File

@ -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)

View File

@ -29,7 +29,7 @@ namespace TrueCraft
{
NetworkStream = stream;
MinecraftStream = new MinecraftStream(new TrueCraft.Core.Networking.BufferedStream(NetworkStream));
PacketQueue = new ConcurrentQueue<IPacket>();
PacketQueue = new BlockingCollection<IPacket>(new ConcurrentQueue<IPacket>());
LoadedChunks = new List<Coordinates2D>();
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<IPacket> PacketQueue { get; private set; }
public BlockingCollection<IPacket> 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);