using System; using System.Collections; using System.Collections.Generic; using System.Text; using UnityEngine; 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); } }