multiplayer refactor
This commit is contained in:
316
Runtime/Engine/Code/Network/NetworkBufferWriter.cs
Normal file
316
Runtime/Engine/Code/Network/NetworkBufferWriter.cs
Normal file
@@ -0,0 +1,316 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.Pool;
|
||||
|
||||
namespace RebootKit.Engine.Network {
|
||||
// @NOTE: Data is written in a linear fashion, so the position is always at the end of the written data.
|
||||
// We are writting everything in little-endian format.
|
||||
public struct NetworkBufferWriter : IDisposable {
|
||||
class WriterHandle {
|
||||
public NativeArray<byte> Data;
|
||||
public bool IsOwner; // Indicates if this handle owns the data and should dispose it.
|
||||
public int Position;
|
||||
public int Capacity;
|
||||
}
|
||||
|
||||
static readonly IObjectPool<WriterHandle> s_WriterPool = new ObjectPool<WriterHandle>(
|
||||
() => new WriterHandle(),
|
||||
_ => { },
|
||||
handle => {
|
||||
if (handle.Data.IsCreated && handle.IsOwner) {
|
||||
handle.Data.Dispose();
|
||||
}
|
||||
|
||||
handle.Data = default;
|
||||
handle.Position = 0;
|
||||
handle.Capacity = 0;
|
||||
},
|
||||
handle => {
|
||||
if (handle.Data.IsCreated && handle.IsOwner) {
|
||||
handle.Data.Dispose();
|
||||
}
|
||||
},
|
||||
true,
|
||||
256
|
||||
);
|
||||
|
||||
WriterHandle m_Handle;
|
||||
|
||||
public int Position {
|
||||
get {
|
||||
return m_Handle.Position;
|
||||
}
|
||||
|
||||
set {
|
||||
Assert.IsTrue(value >= 0 && value <= m_Handle.Capacity, "Position must be within the bounds of the buffer.");
|
||||
m_Handle.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkBufferWriter(int capacity, Allocator allocator) {
|
||||
m_Handle = s_WriterPool.Get();
|
||||
m_Handle.Data = new NativeArray<byte>(capacity, allocator);
|
||||
m_Handle.IsOwner = true;
|
||||
m_Handle.Capacity = capacity;
|
||||
m_Handle.Position = 0;
|
||||
}
|
||||
|
||||
public NetworkBufferWriter(NativeArray<byte> buffer, int position) {
|
||||
m_Handle = s_WriterPool.Get();
|
||||
m_Handle.Data = buffer;
|
||||
m_Handle.IsOwner = false;
|
||||
m_Handle.Capacity = buffer.Length;
|
||||
m_Handle.Position = position;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
if (m_Handle != null) {
|
||||
s_WriterPool.Release(m_Handle);
|
||||
m_Handle = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WillFit(int size) {
|
||||
return m_Handle.Position + size <= m_Handle.Capacity;
|
||||
}
|
||||
|
||||
public void Write(byte value) {
|
||||
if (m_Handle.Position >= m_Handle.Capacity) {
|
||||
throw new InvalidOperationException("Buffer overflow: Cannot write beyond capacity.");
|
||||
}
|
||||
m_Handle.Data[m_Handle.Position++] = value;
|
||||
}
|
||||
|
||||
public void Write(byte[] values) {
|
||||
Assert.IsNotNull(values, "Trying to write null byte array to the buffer.");
|
||||
Assert.IsTrue(WillFit(values.Length), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
if (values.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.Length; i++) {
|
||||
m_Handle.Data[m_Handle.Position++] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(NativeArray<byte> values) {
|
||||
Assert.IsTrue(values.IsCreated, "Trying to write uncreated NativeArray to the buffer.");
|
||||
Assert.IsTrue(WillFit(values.Length), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
if (values.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.Length; i++) {
|
||||
m_Handle.Data[m_Handle.Position++] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(int value) {
|
||||
Assert.IsTrue(sizeof(int) == 4, "Size of int must be 4 bytes.");
|
||||
Assert.IsTrue(WillFit(sizeof(int)), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
Write((byte) (value & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) ((value >> 16) & 0xFF));
|
||||
Write((byte) ((value >> 24) & 0xFF));
|
||||
} else {
|
||||
Write((byte) ((value >> 24) & 0xFF));
|
||||
Write((byte) ((value >> 16) & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) (value & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(short value) {
|
||||
Assert.IsTrue(sizeof(short) == 2, "Size of short must be 2 bytes.");
|
||||
Assert.IsTrue(WillFit(sizeof(short)), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
Write((byte) (value & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
} else {
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) (value & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(ushort value) {
|
||||
Assert.IsTrue(sizeof(ushort) == 2, "Size of ushort must be 2 bytes.");
|
||||
Assert.IsTrue(WillFit(sizeof(ushort)), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
Write((byte) (value & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
} else {
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) (value & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(long value) {
|
||||
Assert.IsTrue(sizeof(long) == 8, "Size of long must be 8 bytes.");
|
||||
Assert.IsTrue(WillFit(sizeof(long)), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
Write((byte) (value & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) ((value >> 16) & 0xFF));
|
||||
Write((byte) ((value >> 24) & 0xFF));
|
||||
Write((byte) ((value >> 32) & 0xFF));
|
||||
Write((byte) ((value >> 40) & 0xFF));
|
||||
Write((byte) ((value >> 48) & 0xFF));
|
||||
Write((byte) ((value >> 56) & 0xFF));
|
||||
} else {
|
||||
Write((byte) ((value >> 56) & 0xFF));
|
||||
Write((byte) ((value >> 48) & 0xFF));
|
||||
Write((byte) ((value >> 40) & 0xFF));
|
||||
Write((byte) ((value >> 32) & 0xFF));
|
||||
Write((byte) ((value >> 24) & 0xFF));
|
||||
Write((byte) ((value >> 16) & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) (value & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(ulong value) {
|
||||
Assert.IsTrue(sizeof(ulong) == 8, "Size of ulong must be 8 bytes.");
|
||||
Assert.IsTrue(WillFit(sizeof(ulong)), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
Write((byte) (value & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) ((value >> 16) & 0xFF));
|
||||
Write((byte) ((value >> 24) & 0xFF));
|
||||
Write((byte) ((value >> 32) & 0xFF));
|
||||
Write((byte) ((value >> 40) & 0xFF));
|
||||
Write((byte) ((value >> 48) & 0xFF));
|
||||
Write((byte) ((value >> 56) & 0xFF));
|
||||
} else {
|
||||
Write((byte) ((value >> 56) & 0xFF));
|
||||
Write((byte) ((value >> 48) & 0xFF));
|
||||
Write((byte) ((value >> 40) & 0xFF));
|
||||
Write((byte) ((value >> 32) & 0xFF));
|
||||
Write((byte) ((value >> 24) & 0xFF));
|
||||
Write((byte) ((value >> 16) & 0xFF));
|
||||
Write((byte) ((value >> 8) & 0xFF));
|
||||
Write((byte) (value & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(float value) {
|
||||
Assert.IsTrue(sizeof(float) == 4, "Size of float must be 4 bytes.");
|
||||
Assert.IsTrue(WillFit(sizeof(float)), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
unsafe {
|
||||
byte* bytes = (byte*) &value;
|
||||
Write(bytes[0]);
|
||||
Write(bytes[1]);
|
||||
Write(bytes[2]);
|
||||
Write(bytes[3]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(bool value) {
|
||||
Assert.IsTrue(WillFit(1), "Buffer overflow: Cannot write beyond capacity.");
|
||||
Write((byte) (value ? 1 : 0));
|
||||
}
|
||||
|
||||
public void Write(Vector2 value) {
|
||||
Assert.IsTrue(WillFit(sizeof(float) * 2), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
Write(value.x);
|
||||
Write(value.y);
|
||||
}
|
||||
|
||||
public void Write(Vector3 value) {
|
||||
Assert.IsTrue(WillFit(sizeof(float) * 3), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
Write(value.x);
|
||||
Write(value.y);
|
||||
Write(value.z);
|
||||
}
|
||||
|
||||
public void Write(Vector4 value) {
|
||||
Assert.IsTrue(WillFit(sizeof(float) * 4), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
Write(value.x);
|
||||
Write(value.y);
|
||||
Write(value.z);
|
||||
Write(value.w);
|
||||
}
|
||||
|
||||
public void Write(Quaternion value) {
|
||||
Assert.IsTrue(WillFit(sizeof(float) * 4), "Buffer overflow: Cannot write beyond capacity.");
|
||||
|
||||
Write(value.x);
|
||||
Write(value.y);
|
||||
Write(value.z);
|
||||
Write(value.w);
|
||||
}
|
||||
|
||||
public void Write(FixedString32Bytes value) {
|
||||
Assert.IsTrue(WillFit(32));
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (i < value.Length) {
|
||||
Write(value[i]);
|
||||
} else {
|
||||
Write((byte) 0); // Fill with zero if the string is shorter than 32 bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(FixedString64Bytes value) {
|
||||
Assert.IsTrue(WillFit(64));
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
if (i < value.Length) {
|
||||
Write(value[i]);
|
||||
} else {
|
||||
Write((byte) 0); // Fill with zero if the string is shorter than 64 bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(FixedString128Bytes value) {
|
||||
Assert.IsTrue(WillFit(128));
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
if (i < value.Length) {
|
||||
Write(value[i]);
|
||||
} else {
|
||||
Write((byte) 0); // Fill with zero if the string is shorter than 128 bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(FixedString512Bytes value) {
|
||||
Assert.IsTrue(WillFit(512));
|
||||
|
||||
for (int i = 0; i < 512; i++) {
|
||||
if (i < value.Length) {
|
||||
Write(value[i]);
|
||||
} else {
|
||||
Write((byte) 0); // Fill with zero if the string is shorter than 512 bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(FixedString4096Bytes value) {
|
||||
Assert.IsTrue(WillFit(4096));
|
||||
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (i < value.Length) {
|
||||
Write(value[i]);
|
||||
} else {
|
||||
Write((byte) 0); // Fill with zero if the string is shorter than 4096 bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user