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
|
&& 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
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user