Use BlockingCollection + Small performance tweaks
This commit is contained in:
parent
7c8309171b
commit
a2b760e527
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user