using System.Runtime.CompilerServices;
using FishNet.Managing;
using GameKit.Dependencies.Utilities;
using UnityEngine;
namespace FishNet.Serializing.Helping
{
///
/// Used to reserve bytes in a writer for length, then inserts length after data has been written.
/// Reserved values are always written as unsigned.
///
internal class ReservedLengthWriter : IResettable
{
private Writer _writer;
private int _startPosition;
private byte _reservedBytes;
///
/// Number of bytes currently written.
///
public int Length
{
get { return (_writer == null) ? 0 : (_writer.Position - _startPosition); }
}
public void Initialize(Writer writer, byte reservedBytes)
{
_writer = writer;
_reservedBytes = reservedBytes;
writer.Skip(reservedBytes);
_startPosition = writer.Position;
}
///
/// Writes the amount of data written to the reserved space.
/// This also resets the state of this object.
///
public void WriteLength()
{
WriteLength((uint)Length);
ResetState();
}
///
/// Writes the amount of data written to the reserved space. If no data was written the reserved amount is removed.
/// This also resets the state of this object.
/// Returns if length was written.
///
public bool WriteLengthOrRemove(uint written)
{
if (written == 0)
_writer.Remove(_reservedBytes);
else
WriteLength(written);
ResetState();
return (written > 0);
}
///
/// Writes the amount of data written to the reserved space. This overrides Length normally written.
/// This also resets the state of this object.
///
public void WriteLength(uint written)
{
switch (_reservedBytes)
{
case 1:
_writer.InsertUInt8Unpacked((byte)written, _startPosition - _reservedBytes);
break;
case 2:
_writer.InsertUInt16Unpacked((ushort)written, _startPosition - _reservedBytes);
break;
case 4:
_writer.InsertUInt32Unpacked((uint)written, _startPosition - _reservedBytes);
break;
default:
string errorMsg = $"Reserved bytes value of {_reservedBytes} is unhandled.";
if (_writer != null)
_writer.NetworkManager.LogError(errorMsg);
else
NetworkManagerExtensions.LogError(errorMsg);
break;
}
ResetState();
}
///
/// Writes the amount of data written to the reserved space. If no data was written the reserved amount is removed.
/// This also resets the state of this object.
///
public bool WriteLengthOrRemove()
{
//Insert written amount.
int written = (_writer.Position - _startPosition);
if (written == 0)
_writer.Remove(_reservedBytes);
else
WriteLength((uint)written);
ResetState();
return (written > 0);
}
///
/// Returns a length read based on a reserved byte count.
///
/// True to reset to position before read.
public static uint ReadLength(PooledReader reader, byte reservedBytes, bool resetPosition = false)
{
uint result;
switch (reservedBytes)
{
case 1:
result = reader.ReadUInt8Unpacked();
break;
case 2:
result = reader.ReadUInt16Unpacked();
break;
case 4:
result = reader.ReadUInt32Unpacked();
break;
default:
string errorMsg = $"Reserved bytes value of {reservedBytes} is unhandled.";
if (reader != null)
reader.NetworkManager.LogError(errorMsg);
else
NetworkManagerExtensions.LogError(errorMsg);
return 0;
}
if (resetPosition)
reader.Position -= (int)result;
return result;
}
public void ResetState()
{
_writer = null;
_startPosition = 0;
_reservedBytes = 0;
}
public void InitializeState() { }
}
internal static class ReservedWritersExtensions
{
///
/// Stores to a cache.
///
public static void Store(this ReservedLengthWriter rlw) => ResettableObjectCaches.Store(rlw);
///
/// Retrieves from a cache.
///
///
public static ReservedLengthWriter Retrieve() => ResettableObjectCaches.Retrieve();
}
}