Add StickGame Assets
This commit is contained in:
237
phr/StickGame/Assets/FishNet/Runtime/Serializing/WriterPool.cs
Normal file
237
phr/StickGame/Assets/FishNet/Runtime/Serializing/WriterPool.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using FishNet.Managing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace FishNet.Serializing
|
||||
{
|
||||
/// <summary>
|
||||
/// Writer which is reused to save on garbage collection and performance.
|
||||
/// </summary>
|
||||
public sealed class PooledWriter : Writer, IDisposable
|
||||
{
|
||||
public void Store() => WriterPool.Store(this);
|
||||
public void StoreLength() => WriterPool.StoreLength(this);
|
||||
[Obsolete("Use Store().")] //Remove on 2024/01/01.
|
||||
public void Dispose() => this.Store();
|
||||
[Obsolete("Use StoreLength().")] //Remove on 2024/01/01.
|
||||
public void DisposeLength() => this.StoreLength();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of PooledWriter. Stores and gets PooledWriter.
|
||||
/// </summary>
|
||||
public static class WriterPool
|
||||
{
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// Pool of writers where length is the minimum and increased at runtime.
|
||||
/// </summary>
|
||||
private static readonly Stack<PooledWriter> _pool = new Stack<PooledWriter>();
|
||||
/// <summary>
|
||||
/// Pool of writers where length is of minimum key and may be increased at runtime.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<int, Stack<PooledWriter>> _lengthPool = new Dictionary<int, Stack<PooledWriter>>();
|
||||
#endregion
|
||||
|
||||
#region Const.
|
||||
/// <summary>
|
||||
/// Length of each bracket when using the length based writer pool.
|
||||
/// </summary>
|
||||
internal const int LENGTH_BRACKET = 1000;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets a writer from the pool.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
[Obsolete("Use Retrieve(NetworkManager).")] //Remove on 2024/01/01
|
||||
public static PooledWriter GetWriter(NetworkManager networkManager) => Retrieve(networkManager);
|
||||
/// <summary>
|
||||
/// Gets a writer from the pool.
|
||||
/// </summary>
|
||||
public static PooledWriter Retrieve(NetworkManager networkManager)
|
||||
{
|
||||
PooledWriter result = (_pool.Count > 0) ? _pool.Pop() : new PooledWriter();
|
||||
result.Reset(networkManager);
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a writer from the pool.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
[Obsolete("Use Retrieve().")] //Remove on 2024/01/01
|
||||
public static PooledWriter GetWriter() => Retrieve();
|
||||
/// Gets a writer from the pool.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static PooledWriter Retrieve()
|
||||
{
|
||||
return Retrieve(null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next writer in the pool of minimum length.
|
||||
/// </summary>
|
||||
/// <param name="length">Minimum length the writer buffer must be.</param>
|
||||
[Obsolete("Use Retrieve(int).")] //Remove on 2024/01/01
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static PooledWriter GetWriter(int length) => Retrieve(length);
|
||||
/// <summary>
|
||||
/// Gets the next writer in the pool of minimum length.
|
||||
/// </summary>
|
||||
/// <param name="length">Minimum length the writer buffer must be.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static PooledWriter Retrieve(int length)
|
||||
{
|
||||
return Retrieve(null, length);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the next writer in the pool of minimum length.
|
||||
/// </summary>
|
||||
/// <param name="length">Minimum length the writer buffer must be.</param>
|
||||
[Obsolete("Use Retrieve(NetworkManager, int).")] //Remove on 2024/01/01
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static PooledWriter GetWriter(NetworkManager networkManager, int length) => Retrieve(networkManager, length);
|
||||
/// <summary>
|
||||
/// Gets the next writer in the pool of minimum length.
|
||||
/// </summary>
|
||||
/// <param name="length">Minimum length the writer buffer must be.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static PooledWriter Retrieve(NetworkManager networkManager, int length)
|
||||
{
|
||||
/* The index returned will be for writers which have
|
||||
* length as a minimum capacity.
|
||||
* EG: if length is 1200 / 1000 (length_bracket) result
|
||||
* will be index 1. Index 0 will be up to 1000, while
|
||||
* index 1 will be up to 2000. */
|
||||
int index = GetDictionaryIndex(length);
|
||||
Stack<PooledWriter> stack;
|
||||
//There is already one pooled.
|
||||
if (_lengthPool.TryGetValue(index, out stack) && stack.Count > 0)
|
||||
{
|
||||
PooledWriter result = stack.Pop();
|
||||
result.Reset(networkManager);
|
||||
return result;
|
||||
}
|
||||
//Not pooled yet.
|
||||
else
|
||||
{
|
||||
//Get any ol' writer.
|
||||
PooledWriter writer = Retrieve(networkManager);
|
||||
/* Ensure length to fill it's bracket.
|
||||
* Increase index by 1 since 0 index would
|
||||
* just return 0 as the capacity. */
|
||||
int requiredCapacity = (index + 1) * LENGTH_BRACKET;
|
||||
writer.EnsureBufferCapacity(requiredCapacity);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a writer to the appropriate length pool.
|
||||
/// Writers must be a minimum of 1000 bytes in length to be sorted by length.
|
||||
/// Writers which do not meet the minimum will be resized to 1000 bytes.
|
||||
/// </summary>
|
||||
[Obsolete("Use StoreLength(PooledWriter).")] //Remove on 2024/01/01
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RecycleLength(PooledWriter writer) => StoreLength(writer);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a writer to the appropriate length pool.
|
||||
/// Writers must be a minimum of 1000 bytes in length to be sorted by length.
|
||||
/// Writers which do not meet the minimum will be resized to 1000 bytes.
|
||||
/// </summary>
|
||||
public static void StoreLength(PooledWriter writer)
|
||||
{
|
||||
int index = GetDictionaryIndex(writer);
|
||||
Stack<PooledWriter> stack;
|
||||
if (!_lengthPool.TryGetValue(index, out stack))
|
||||
{
|
||||
stack = new Stack<PooledWriter>();
|
||||
_lengthPool[index] = stack;
|
||||
}
|
||||
|
||||
stack.Push(writer);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a writer to the pool.
|
||||
/// </summary>
|
||||
[Obsolete("Use Store(PooledWriter).")] //Remove on 2024/01/01
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Recycle(PooledWriter writer) => Store(writer);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a writer to the pool.
|
||||
/// </summary>
|
||||
public static void Store(PooledWriter writer)
|
||||
{
|
||||
_pool.Push(writer);
|
||||
}
|
||||
|
||||
#region Dictionary indexes.
|
||||
/// <summary>
|
||||
/// Gets which index to use for length when retrieving a writer.
|
||||
/// </summary>
|
||||
private static int GetDictionaryIndex(int length)
|
||||
{
|
||||
/* The index returned will be for writers which have
|
||||
* length as a minimum capacity.
|
||||
* EG: if length is 1200 / 1000 (length_bracket) result
|
||||
* will be index 1. Index 0 will be up to 1000, while
|
||||
* index 1 will be up to 2000. So to accomodate 1200
|
||||
* length index 1 must be used as 0 has a maximum of 1000. */
|
||||
|
||||
/* Examples if length_bracket is 1000, using floor:
|
||||
* 800 / 1000 = 0.
|
||||
* 1200 / 1000 = 1.
|
||||
* 1000 / 1000 = 1. But has 0 remainder so is reduced by 1, resulting in 0.
|
||||
*/
|
||||
int index = UnityEngine.Mathf.FloorToInt(length / LENGTH_BRACKET);
|
||||
if (index > 0 && length % LENGTH_BRACKET == 0)
|
||||
index--;
|
||||
|
||||
//UnityEngine.Debug.Log($"Returning length {length} from index {index}");
|
||||
return index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets which index to use for length when storing a writer.
|
||||
/// </summary>
|
||||
private static int GetDictionaryIndex(PooledWriter writer)
|
||||
{
|
||||
int capacity = writer.Capacity;
|
||||
/* If capacity is less than 1000 then the writer
|
||||
* does not meet the minimum length bracket. This should never
|
||||
* be the case unless the user perhaps manually calls this method. */
|
||||
if (capacity < LENGTH_BRACKET)
|
||||
{
|
||||
capacity = LENGTH_BRACKET;
|
||||
writer.EnsureBufferCapacity(LENGTH_BRACKET);
|
||||
}
|
||||
|
||||
/* Since capacity is set to minimum of length_bracket
|
||||
* capacity / length_bracket will always be at least 1.
|
||||
*
|
||||
* Here are some result examples using floor:
|
||||
* 1000 / 1000 = 1.
|
||||
* 1200 / 1000 = 1.
|
||||
* 2400 / 1000 = 2.
|
||||
*/
|
||||
int index = UnityEngine.Mathf.FloorToInt(capacity / LENGTH_BRACKET);
|
||||
/* As mentioned the index will always be a minimum of 1. Because of this
|
||||
* we can safely reduce index by 1 and it not be negative.
|
||||
* This reduction also ensures the writer ends up in the proper pool.
|
||||
* Since index 0 ensures minimum of 1000, 1000-1999 would go there.
|
||||
* Just as 2000-2999 would go into 1. */
|
||||
index--;
|
||||
|
||||
//UnityEngine.Debug.Log($"Storing capacity {capacity} at index {index}");
|
||||
return index;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user