using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
/// Sent from server to client.
public enum ServerPackets
{
welcome = 1,
spawnPlayer,
playerPosition,
playerRotation,
playerDisconnected,
playerHealth,
playerRespawned
}
/// Sent from client to server.
public enum ClientPackets
{
welcomeReceived = 1,
playerMovement,
playerShoot
}
public class Packet : IDisposable
{
private List buffer;
private byte[] readableBuffer;
private int readPos;
/// Creates a new empty packet (without an ID).
public Packet()
{
buffer = new List(); // Intitialize buffer
readPos = 0; // Set readPos to 0
}
/// Creates a new packet with a given ID. Used for sending.
/// The packet ID.
public Packet(int _id)
{
buffer = new List(); // Intitialize buffer
readPos = 0; // Set readPos to 0
Write(_id); // Write packet id to the buffer
}
/// Creates a packet from which data can be read. Used for receiving.
/// The bytes to add to the packet.
public Packet(byte[] _data)
{
buffer = new List(); // Intitialize buffer
readPos = 0; // Set readPos to 0
SetBytes(_data);
}
#region Functions
/// Sets the packet's content and prepares it to be read.
/// The bytes to add to the packet.
public void SetBytes(byte[] _data)
{
Write(_data);
readableBuffer = buffer.ToArray();
}
/// Inserts the length of the packet's content at the start of the buffer.
public void WriteLength()
{
buffer.InsertRange(0, BitConverter.GetBytes(buffer.Count)); // Insert the byte length of the packet at the very beginning
}
/// Inserts the given int at the start of the buffer.
/// The int to insert.
public void InsertInt(int _value)
{
buffer.InsertRange(0, BitConverter.GetBytes(_value)); // Insert the int at the start of the buffer
}
/// Gets the packet's content in array form.
public byte[] ToArray()
{
readableBuffer = buffer.ToArray();
return readableBuffer;
}
/// Gets the length of the packet's content.
public int Length()
{
return buffer.Count; // Return the length of buffer
}
/// Gets the length of the unread data contained in the packet.
public int UnreadLength()
{
return Length() - readPos; // Return the remaining length (unread)
}
/// Resets the packet instance to allow it to be reused.
/// Whether or not to reset the packet.
public void Reset(bool _shouldReset = true)
{
if (_shouldReset)
{
buffer.Clear(); // Clear buffer
readableBuffer = null;
readPos = 0; // Reset readPos
}
else
{
readPos -= 4; // "Unread" the last read int
}
}
#endregion
#region Write Data
/// Adds a byte to the packet.
/// The byte to add.
public void Write(byte _value)
{
buffer.Add(_value);
}
/// Adds an array of bytes to the packet.
/// The byte array to add.
public void Write(byte[] _value)
{
buffer.AddRange(_value);
}
/// Adds a short to the packet.
/// The short to add.
public void Write(short _value)
{
buffer.AddRange(BitConverter.GetBytes(_value));
}
/// Adds an int to the packet.
/// The int to add.
public void Write(int _value)
{
buffer.AddRange(BitConverter.GetBytes(_value));
}
/// Adds a long to the packet.
/// The long to add.
public void Write(long _value)
{
buffer.AddRange(BitConverter.GetBytes(_value));
}
/// Adds a float to the packet.
/// The float to add.
public void Write(float _value)
{
buffer.AddRange(BitConverter.GetBytes(_value));
}
/// Adds a bool to the packet.
/// The bool to add.
public void Write(bool _value)
{
buffer.AddRange(BitConverter.GetBytes(_value));
}
/// Adds a string to the packet.
/// The string to add.
public void Write(string _value)
{
Write(_value.Length); // Add the length of the string to the packet
buffer.AddRange(Encoding.ASCII.GetBytes(_value)); // Add the string itself
}
public void Write(Vector3 _value)
{
Write(_value.x);
Write(_value.y);
Write(_value.z);
}
public void Write(Quaternion _value)
{
Write(_value.x);
Write(_value.y);
Write(_value.z);
Write(_value.w);
}
#endregion
#region Read Data
/// Reads a byte from the packet.
/// Whether or not to move the buffer's read position.
public byte ReadByte(bool _moveReadPos = true)
{
if (buffer.Count > readPos)
{
// If there are unread bytes
byte _value = readableBuffer[readPos]; // Get the byte at readPos' position
if (_moveReadPos)
{
// If _moveReadPos is true
readPos += 1; // Increase readPos by 1
}
return _value; // Return the byte
}
else
{
throw new Exception("Could not read value of type 'byte'!");
}
}
/// Reads an array of bytes from the packet.
/// The length of the byte array.
/// Whether or not to move the buffer's read position.
public byte[] ReadBytes(int _length, bool _moveReadPos = true)
{
if (buffer.Count > readPos)
{
// If there are unread bytes
byte[] _value = buffer.GetRange(readPos, _length).ToArray(); // Get the bytes at readPos' position with a range of _length
if (_moveReadPos)
{
// If _moveReadPos is true
readPos += _length; // Increase readPos by _length
}
return _value; // Return the bytes
}
else
{
throw new Exception("Could not read value of type 'byte[]'!");
}
}
/// Reads a short from the packet.
/// Whether or not to move the buffer's read position.
public short ReadShort(bool _moveReadPos = true)
{
if (buffer.Count > readPos)
{
// If there are unread bytes
short _value = BitConverter.ToInt16(readableBuffer, readPos); // Convert the bytes to a short
if (_moveReadPos)
{
// If _moveReadPos is true and there are unread bytes
readPos += 2; // Increase readPos by 2
}
return _value; // Return the short
}
else
{
throw new Exception("Could not read value of type 'short'!");
}
}
/// Reads an int from the packet.
/// Whether or not to move the buffer's read position.
public int ReadInt(bool _moveReadPos = true)
{
if (buffer.Count > readPos)
{
// If there are unread bytes
int _value = BitConverter.ToInt32(readableBuffer, readPos); // Convert the bytes to an int
if (_moveReadPos)
{
// If _moveReadPos is true
readPos += 4; // Increase readPos by 4
}
return _value; // Return the int
}
else
{
throw new Exception("Could not read value of type 'int'!");
}
}
/// Reads a long from the packet.
/// Whether or not to move the buffer's read position.
public long ReadLong(bool _moveReadPos = true)
{
if (buffer.Count > readPos)
{
// If there are unread bytes
long _value = BitConverter.ToInt64(readableBuffer, readPos); // Convert the bytes to a long
if (_moveReadPos)
{
// If _moveReadPos is true
readPos += 8; // Increase readPos by 8
}
return _value; // Return the long
}
else
{
throw new Exception("Could not read value of type 'long'!");
}
}
/// Reads a float from the packet.
/// Whether or not to move the buffer's read position.
public float ReadFloat(bool _moveReadPos = true)
{
if (buffer.Count > readPos)
{
// If there are unread bytes
float _value = BitConverter.ToSingle(readableBuffer, readPos); // Convert the bytes to a float
if (_moveReadPos)
{
// If _moveReadPos is true
readPos += 4; // Increase readPos by 4
}
return _value; // Return the float
}
else
{
throw new Exception("Could not read value of type 'float'!");
}
}
/// Reads a bool from the packet.
/// Whether or not to move the buffer's read position.
public bool ReadBool(bool _moveReadPos = true)
{
if (buffer.Count > readPos)
{
// If there are unread bytes
bool _value = BitConverter.ToBoolean(readableBuffer, readPos); // Convert the bytes to a bool
if (_moveReadPos)
{
// If _moveReadPos is true
readPos += 1; // Increase readPos by 1
}
return _value; // Return the bool
}
else
{
throw new Exception("Could not read value of type 'bool'!");
}
}
/// Reads a string from the packet.
/// Whether or not to move the buffer's read position.
public string ReadString(bool _moveReadPos = true)
{
try
{
int _length = ReadInt(); // Get the length of the string
string _value = Encoding.ASCII.GetString(readableBuffer, readPos, _length); // Convert the bytes to a string
if (_moveReadPos && _value.Length > 0)
{
// If _moveReadPos is true string is not empty
readPos += _length; // Increase readPos by the length of the string
}
return _value; // Return the string
}
catch
{
throw new Exception("Could not read value of type 'string'!");
}
}
public Vector3 ReadVector3(bool _moveReadPos = true)
{
return new Vector3(ReadFloat(_moveReadPos), ReadFloat(_moveReadPos), ReadFloat(_moveReadPos));
}
public Quaternion ReadQuaternion(bool _moveReadPos = true)
{
return new Quaternion(ReadFloat(_moveReadPos), ReadFloat(_moveReadPos), ReadFloat(_moveReadPos), ReadFloat(_moveReadPos));
}
#endregion
private bool disposed = false;
protected virtual void Dispose(bool _disposing)
{
if (!disposed)
{
if (_disposing)
{
buffer = null;
readableBuffer = null;
readPos = 0;
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}