411 lines
13 KiB
C#
411 lines
13 KiB
C#
using System;
|
|
using Unity.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
using UnityEngine.Pool;
|
|
|
|
namespace RebootKit.Engine.Network {
|
|
public struct NetworkBufferReader : IDisposable {
|
|
class ReaderHandle {
|
|
public NativeSlice<byte> Data;
|
|
public int Position;
|
|
public bool IsBigEndian;
|
|
}
|
|
|
|
static readonly IObjectPool<ReaderHandle> s_ReaderPool = new ObjectPool<ReaderHandle>(
|
|
() => new ReaderHandle(),
|
|
_ => { },
|
|
handle => {
|
|
handle.Data = default;
|
|
handle.Position = 0;
|
|
handle.IsBigEndian = false;
|
|
},
|
|
_ => { },
|
|
true,
|
|
256
|
|
);
|
|
|
|
ReaderHandle m_Handle;
|
|
|
|
public NetworkBufferReader(NativeSlice<byte> data, int position = 0) {
|
|
Assert.IsTrue(position >= 0 && position <= data.Length,
|
|
"Position must be within the bounds of the data array.");
|
|
|
|
m_Handle = s_ReaderPool.Get();
|
|
m_Handle.Data = data;
|
|
m_Handle.Position = position;
|
|
m_Handle.IsBigEndian = !BitConverter.IsLittleEndian;
|
|
}
|
|
|
|
public void Dispose() {
|
|
if (m_Handle != null) {
|
|
s_ReaderPool.Release(m_Handle);
|
|
m_Handle = null;
|
|
}
|
|
}
|
|
|
|
public bool HasNext(int size) {
|
|
return m_Handle.Position + size <= m_Handle.Data.Length;
|
|
}
|
|
|
|
public bool Read(out NativeArray<byte> value, int size, Allocator allocator = Allocator.Temp) {
|
|
Assert.IsTrue(HasNext(size),
|
|
$"Not enough data to read the requested size. Requested: {size}, Available: {m_Handle.Data.Length - m_Handle.Position}");
|
|
|
|
if (size <= 0) {
|
|
value = default;
|
|
return false;
|
|
}
|
|
|
|
value = new NativeArray<byte>(size, allocator);
|
|
for (int i = 0; i < size; i++) {
|
|
value[i] = m_Handle.Data[m_Handle.Position++];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out NativeSlice<byte> value, int size) {
|
|
if (!HasNext(size)) {
|
|
value = default;
|
|
return false;
|
|
}
|
|
|
|
value = m_Handle.Data.Slice(m_Handle.Position, size);
|
|
m_Handle.Position += size;
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out byte value) {
|
|
if (!HasNext(1)) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
Assert.IsTrue(HasNext(1), "Not enough data to read a byte.");
|
|
value = m_Handle.Data[m_Handle.Position++];
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out bool value) {
|
|
if (!HasNext(1)) {
|
|
value = false;
|
|
return false;
|
|
}
|
|
|
|
value = m_Handle.Data[m_Handle.Position++] != 0;
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out int value) {
|
|
value = 0;
|
|
|
|
if (!HasNext(4)) {
|
|
return false;
|
|
}
|
|
|
|
if (m_Handle.IsBigEndian) {
|
|
value |= m_Handle.Data[m_Handle.Position++] << 24;
|
|
value |= m_Handle.Data[m_Handle.Position++] << 16;
|
|
value |= m_Handle.Data[m_Handle.Position++] << 8;
|
|
value |= m_Handle.Data[m_Handle.Position++];
|
|
} else {
|
|
value |= m_Handle.Data[m_Handle.Position++];
|
|
value |= m_Handle.Data[m_Handle.Position++] << 8;
|
|
value |= m_Handle.Data[m_Handle.Position++] << 16;
|
|
value |= m_Handle.Data[m_Handle.Position++] << 24;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out short value) {
|
|
value = 0;
|
|
|
|
if (!HasNext(2)) {
|
|
return false;
|
|
}
|
|
|
|
if (m_Handle.IsBigEndian) {
|
|
value |= (short) (m_Handle.Data[m_Handle.Position++] << 8);
|
|
value |= (short) (m_Handle.Data[m_Handle.Position++]);
|
|
} else {
|
|
value |= (short) (m_Handle.Data[m_Handle.Position++]);
|
|
value |= (short) (m_Handle.Data[m_Handle.Position++] << 8);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out ushort value) {
|
|
value = 0;
|
|
|
|
if (!HasNext(2)) {
|
|
return false;
|
|
}
|
|
|
|
if (m_Handle.IsBigEndian) {
|
|
value |= (ushort) (m_Handle.Data[m_Handle.Position++] << 8);
|
|
value |= (ushort) (m_Handle.Data[m_Handle.Position++]);
|
|
} else {
|
|
value |= (ushort) (m_Handle.Data[m_Handle.Position++]);
|
|
value |= (ushort) (m_Handle.Data[m_Handle.Position++] << 8);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out long value) {
|
|
value = 0;
|
|
|
|
if (!HasNext(8)) {
|
|
return false;
|
|
}
|
|
|
|
if (m_Handle.IsBigEndian) {
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 56;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 48;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 40;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 32;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 24;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 16;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 8;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++];
|
|
} else {
|
|
value |= (long) m_Handle.Data[m_Handle.Position++];
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 8;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 16;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 24;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 32;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 40;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 48;
|
|
value |= (long) m_Handle.Data[m_Handle.Position++] << 56;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out ulong value) {
|
|
value = 0;
|
|
|
|
if (!HasNext(8)) {
|
|
return false;
|
|
}
|
|
|
|
if (m_Handle.IsBigEndian) {
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 56;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 48;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 40;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 32;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 24;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 16;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 8;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++];
|
|
} else {
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++];
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 8;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 16;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 24;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 32;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 40;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 48;
|
|
value |= (ulong) m_Handle.Data[m_Handle.Position++] << 56;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out float value) {
|
|
if (Read(out int intValue)) {
|
|
value = System.BitConverter.Int32BitsToSingle(intValue);
|
|
return true;
|
|
}
|
|
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
public bool Read(out Vector2 value) {
|
|
Assert.IsTrue(HasNext(sizeof(float) * 2), "Not enough data to read a Vector2.");
|
|
|
|
if (Read(out float x) && Read(out float y)) {
|
|
value = new Vector2(x, y);
|
|
return true;
|
|
}
|
|
|
|
value = Vector2.zero;
|
|
return false;
|
|
}
|
|
|
|
public bool Read(out Vector3 value) {
|
|
Assert.IsTrue(HasNext(sizeof(float) * 3), "Not enough data to read a Vector3.");
|
|
|
|
if (Read(out float x) && Read(out float y) && Read(out float z)) {
|
|
value = new Vector3(x, y, z);
|
|
return true;
|
|
}
|
|
|
|
value = Vector3.zero;
|
|
return false;
|
|
}
|
|
|
|
public bool Read(out Vector4 value) {
|
|
Assert.IsTrue(HasNext(sizeof(float) * 4), "Not enough data to read a Vector4.");
|
|
|
|
if (Read(out float x) && Read(out float y) && Read(out float z) && Read(out float w)) {
|
|
value = new Vector4(x, y, z, w);
|
|
return true;
|
|
}
|
|
|
|
value = Vector4.zero;
|
|
return false;
|
|
}
|
|
|
|
public bool Read(out Quaternion value) {
|
|
Assert.IsTrue(HasNext(sizeof(float) * 4), "Not enough data to read a Quaternion.");
|
|
|
|
if (Read(out float x) && Read(out float y) && Read(out float z) && Read(out float w)) {
|
|
value = new Quaternion(x, y, z, w);
|
|
return true;
|
|
}
|
|
|
|
value = Quaternion.identity;
|
|
return false;
|
|
}
|
|
|
|
public bool Read(out FixedString32Bytes value) {
|
|
Assert.IsTrue(HasNext(32), "Not enough data to read a FixedString32Bytes.");
|
|
|
|
NativeArray<byte> tempData = new NativeArray<byte>(32, Allocator.Temp);
|
|
|
|
value = new FixedString32Bytes();
|
|
int length = 0;
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
Read(out byte byteValue);
|
|
|
|
tempData[i] = byteValue;
|
|
|
|
if (byteValue != 0) {
|
|
length++;
|
|
}
|
|
}
|
|
|
|
value.Length = length;
|
|
for (int i = 0; i < length; i++) {
|
|
value[i] = tempData[i];
|
|
}
|
|
|
|
tempData.Dispose();
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out FixedString64Bytes value) {
|
|
Assert.IsTrue(HasNext(64), "Not enough data to read a FixedString64Bytes.");
|
|
|
|
NativeArray<byte> tempData = new NativeArray<byte>(64, Allocator.Temp);
|
|
|
|
value = new FixedString64Bytes();
|
|
int length = 0;
|
|
|
|
for (int i = 0; i < 64; i++) {
|
|
Read(out byte byteValue);
|
|
|
|
tempData[i] = byteValue;
|
|
|
|
if (byteValue != 0) {
|
|
length++;
|
|
}
|
|
}
|
|
|
|
value.Length = length;
|
|
for (int i = 0; i < length; i++) {
|
|
value[i] = tempData[i];
|
|
}
|
|
|
|
tempData.Dispose();
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out FixedString128Bytes value) {
|
|
Assert.IsTrue(HasNext(128), "Not enough data to read a FixedString128Bytes.");
|
|
|
|
NativeArray<byte> tempData = new NativeArray<byte>(128, Allocator.Temp);
|
|
|
|
value = new FixedString128Bytes();
|
|
int length = 0;
|
|
|
|
for (int i = 0; i < 128; i++) {
|
|
Read(out byte byteValue);
|
|
|
|
tempData[i] = byteValue;
|
|
|
|
if (byteValue != 0) {
|
|
length++;
|
|
}
|
|
}
|
|
|
|
value.Length = length;
|
|
for (int i = 0; i < length; i++) {
|
|
value[i] = tempData[i];
|
|
}
|
|
|
|
tempData.Dispose();
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out FixedString512Bytes value) {
|
|
Assert.IsTrue(HasNext(512), "Not enough data to read a FixedString512Bytes.");
|
|
|
|
NativeArray<byte> tempData = new NativeArray<byte>(512, Allocator.Temp);
|
|
|
|
value = new FixedString512Bytes();
|
|
int length = 0;
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
Read(out byte byteValue);
|
|
|
|
tempData[i] = byteValue;
|
|
|
|
if (byteValue != 0) {
|
|
length++;
|
|
}
|
|
}
|
|
|
|
value.Length = length;
|
|
for (int i = 0; i < length; i++) {
|
|
value[i] = tempData[i];
|
|
}
|
|
|
|
tempData.Dispose();
|
|
return true;
|
|
}
|
|
|
|
public bool Read(out FixedString4096Bytes value) {
|
|
Assert.IsTrue(HasNext(4096), "Not enough data to read a FixedString4096Bytes.");
|
|
|
|
NativeArray<byte> tempData = new NativeArray<byte>(4096, Allocator.Temp);
|
|
|
|
value = new FixedString4096Bytes();
|
|
int length = 0;
|
|
|
|
for (int i = 0; i < 4096; i++) {
|
|
Read(out byte byteValue);
|
|
|
|
tempData[i] = byteValue;
|
|
|
|
if (byteValue != 0) {
|
|
length++;
|
|
}
|
|
}
|
|
|
|
value.Length = length;
|
|
for (int i = 0; i < length; i++) {
|
|
value[i] = tempData[i];
|
|
}
|
|
|
|
tempData.Dispose();
|
|
return true;
|
|
}
|
|
}
|
|
} |