using System;
using UnityEngine;
namespace Mirror
{
///
/// NetworkReader to be used with NetworkReaderPool
///
public class PooledNetworkReader : NetworkReader, IDisposable
{
internal PooledNetworkReader(byte[] bytes) : base(bytes) { }
internal PooledNetworkReader(ArraySegment segment) : base(segment) { }
public void Dispose()
{
NetworkReaderPool.Recycle(this);
}
}
///
/// Pool of NetworkReaders
/// Use this pool instead of NetworkReader to reduce memory allocation
/// Use Capacity to change size of pool
///
public static class NetworkReaderPool
{
static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkReaderPool), LogType.Error);
///
/// Size of the pool
/// If pool is too small getting readers will causes memory allocation
/// Default value: 100
///
public static int Capacity
{
get => pool.Length;
set
{
// resize the array
Array.Resize(ref pool, value);
// if capacity is smaller than before, then we need to adjust
// 'next' so it doesn't point to an index out of range
// -> if we set '0' then next = min(_, 0-1) => -1
// -> if we set '2' then next = min(_, 2-1) => 1
next = Mathf.Min(next, pool.Length - 1);
}
}
///
/// Mirror usually only uses up to 4 readers in nested usings,
/// 100 is a good margin for edge cases when users need a lot readers at
/// the same time.
///
/// keep in mind, most entries of the pool will be null in most cases
///
///
/// Note: we use an Array instead of a Stack because it's significantly
/// faster: https://github.com/vis2k/Mirror/issues/1614
static PooledNetworkReader[] pool = new PooledNetworkReader[100];
static int next = -1;
///
/// Get the next reader in the pool
/// If pool is empty, creates a new Reader
///
public static PooledNetworkReader GetReader(byte[] bytes)
{
if (next == -1)
{
return new PooledNetworkReader(bytes);
}
PooledNetworkReader reader = pool[next];
pool[next] = null;
next--;
// reset buffer
SetBuffer(reader, bytes);
return reader;
}
///
/// Get the next reader in the pool
/// If pool is empty, creates a new Reader
///
public static PooledNetworkReader GetReader(ArraySegment segment)
{
if (next == -1)
{
return new PooledNetworkReader(segment);
}
PooledNetworkReader reader = pool[next];
pool[next] = null;
next--;
// reset buffer
SetBuffer(reader, segment);
return reader;
}
///
/// Puts reader back into pool
/// When pool is full, the extra reader is left for the GC
///
public static void Recycle(PooledNetworkReader reader)
{
if (next < pool.Length - 1)
{
next++;
pool[next] = reader;
}
else
{
logger.LogWarning("NetworkReaderPool.Recycle, Pool was full leaving extra reader for GC");
}
}
// SetBuffer methods mirror constructor for ReaderPool
static void SetBuffer(NetworkReader reader, byte[] bytes)
{
reader.buffer = new ArraySegment(bytes);
reader.Position = 0;
}
static void SetBuffer(NetworkReader reader, ArraySegment segment)
{
reader.buffer = segment;
reader.Position = 0;
}
}
}