/*
	Lan Wars.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GAME_GAME_PACKET_H
#define GAME_GAME_PACKET_H

//=====================================================================================================================
//=====================================================================================================================

#include "Network\NetworkAddress.h"
#include "Game\GamePacketChunk.h"

//=====================================================================================================================
//=====================================================================================================================

namespace Game
{	
	//=================================================================================================================
	//=================================================================================================================
	
	class DatagramSocket;

	//=================================================================================================================
	/// @brief		Class representing a packet that can be sent by the game. Each packet is of fixed size with 32K
	///				of data (32768 bytes) with 8 bytes reserved for a packet id and packet size, and packet number. 
	///				When the packet is sent over the network however it may be made smaller depending on how much 
	///				of the buffer space is filled up.	
	//=================================================================================================================

	class GamePacket : public Poolable
	{
		public:
			
			//=========================================================================================================
			// Constants
			//=========================================================================================================
				
				/// Maximum size of a packets payload: the real size of a packet is this plus 8 bytes for the checksum, packet number and size field
				
				static const unsigned PAYLOAD_SIZE = 32760;
			
			//=====================================================================================================
			// Structures
			//=====================================================================================================
				
				// Don't want the compiler touching this structure's layout
				
				#pragma pack( push	)
				#pragma pack( 1		)
			
				/// Structure that holds the raw data of the packet as it will be sent across the network
			
				volatile struct Data
				{
					/// Header of the packet
					
					volatile struct Header
					{
						/// Checksum for the packet: 
						
						volatile unsigned __int16 m_checksum;
						
						/// Which packet this is. The sending GamePacketCenter increments this for each outgoing packet.
						
						volatile unsigned __int32 m_packet_num;
						
						//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
						/// Size of the data (in bytes) written to the packet (excluding all header info).
						/// Because of the way in which packets are written as a sequence of bits, there may be waste 
						/// bits at the end because of the fact that we cannot write individual bits to packets. 
						//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
						
						volatile unsigned __int16 m_size;
					
					} m_header;
					
					/// The actual payload of the packet itself
					
					volatile unsigned __int8 m_payload[PAYLOAD_SIZE];
				};
				
				// Restore the previous alignment settings
				
				#pragma pack( pop )
				
			//=========================================================================================================
			// Functions
			//=========================================================================================================

				//=====================================================================================================
				/// @brief		Creates an empty packet
				//=====================================================================================================
				
				inline GamePacket(){ Clear(); }
				
				//=====================================================================================================
				/// @brief		Creates a packet from another packet. Underyling Game::Poolable data is left untouched.
				/// @param		other - other packet to create from
				/// @pre		The other packet's marked payload must not exceed the maximum packet size
				//=====================================================================================================
				
				inline GamePacket( const GamePacket & other )
				{
					// Make sure ok:
					
					ENSURE( other.m_data.m_header.m_size <= PAYLOAD_SIZE , "The other packet's marked payload must not exceed the maximum packet size" )				
				
					// Copy address:
				
					m_address = other.m_address;

					// Copy bit position

					m_current_bit = other.m_current_bit;
					
					// Debug only:
					
					#ifdef USE_DEBUG_CONSOLE
					
						m_send_time = other.m_send_time;
					
					#endif
					
					// Figure out how much data to copy:
					
					unsigned write_bytes = sizeof(other.m_data.m_header) + other.m_data.m_header.m_size;
					
					// Do the copy:
					
					memcpy( &m_data , &other.m_data , write_bytes ); 
				}				
				
				//=====================================================================================================
				/// @brief		Assigns from another packet. Underyling Game::Poolable data is left untouched.
				/// @param		other - other packet to assign from
				/// @returns	This packet
				/// @pre		The other packet's marked payload must not exceed the maximum packet size
				//=====================================================================================================
				
				inline GamePacket & operator = ( const GamePacket & other )
				{
					// Make sure ok:
					
					ENSURE( other.m_data.m_header.m_size <= PAYLOAD_SIZE , "The other packet's marked payload must not exceed the maximum packet size" )
				
					// Only if not the same:
					
					if ( this != & other )
					{				
						// Copy address:
					
						m_address = other.m_address;

						// Copy bit position

						m_current_bit = other.m_current_bit;
						
						// Debug only:
						
						#ifdef USE_DEBUG_CONSOLE
						
							m_send_time = other.m_send_time;
						
						#endif						
						
						// Figure out how much data to copy:
						
						unsigned write_bytes = sizeof(other.m_data.m_header) + other.m_data.m_header.m_size;										
						
						// Do the copy:
						
						memcpy( &m_data , &other.m_data , write_bytes );
					}
					
					// Return us:
					
					return * this;
				}				
				
				//=====================================================================================================
				/// @brief		Sets the size of the packet's payload to 0, marking the packet as being cleared.
				///				Also clears the packet's ID and the address of this packet, as well as the packet 
				///				number.
				//=====================================================================================================
				
				inline void Clear()
				{ 
					// Clear the packet data
				
					m_data.m_header.m_size			= 0;
					m_data.m_header.m_packet_num	= 0;
				
					// Not writing to any bits in the data stream

					m_current_bit = 0;
					
					// Clear the checksum
					
					SetChecksum(0xffff);				
					
					// Debug only:
					
					#ifdef USE_DEBUG_CONSOLE
					
						m_send_time = 0xffffffff;
					
					#endif
					
					// Clear destination / sender address
					
					m_address = NetworkAddress::InvalidAddress();
				}
				
				//=====================================================================================================
				/// @brief		Compares two packets for equality. Compares first based on the sender and
				///				next based on the packet number.
				/// @param		other - other packet to compare to
				/// @returns	Result of the comparison
				//=====================================================================================================
				
				inline bool operator == ( const GamePacket & other ) const 
				{
					return 
					(
						GetAddress().GetIP()	== other.GetAddress().GetIP()		&&
						GetAddress().GetPort()	== other.GetAddress().GetPort()		&&
						GetPacketNumber()		== other.GetPacketNumber()
					);
				}
				
				//=====================================================================================================
				/// @brief		Compares two packets for equality. Compares first based on the sender and
				///				next based on the packet number.
				/// @param		other - other packet to compare to
				/// @returns	Result of the comparison
				//=====================================================================================================
				
				inline bool operator != ( const GamePacket & other ) const 
				{
					return 
					(
						GetAddress().GetIP()	!= other.GetAddress().GetIP()		||
						GetAddress().GetPort()	!= other.GetAddress().GetPort()		||
						GetPacketNumber()		!= other.GetPacketNumber()
					);
				}
				
				//=====================================================================================================
				/// @brief		Compares two packets for equality. Compares first based on the sender and
				///				next based on the packet number.
				/// @param		other - other packet to compare to
				/// @returns	Result of the comparison
				//=====================================================================================================
				
				inline bool operator > ( const GamePacket & other ) const 
				{
					// Ugh... 
				
					if ( GetAddress().GetIP() > other.GetAddress().GetIP() )
					{
						return true;
					}
					else if ( GetAddress().GetIP() == other.GetAddress().GetIP() )
					{
						if ( GetAddress().GetPort() > other.GetAddress().GetPort() )
						{
							return true;
						}
						else if ( GetAddress().GetPort() == other.GetAddress().GetPort() )
						{
							return GetPacketNumber() > other.GetPacketNumber();
						}
						else
						{
							return false;
						}
					}
					else
					{
						return false;
					}
				}
				
				//=====================================================================================================
				/// @brief		Compares two packets for equality. Compares first based on the sender and
				///				next based on the packet number.
				/// @param		other - other packet to compare to
				/// @returns	Result of the comparison
				//=====================================================================================================
				
				inline bool operator >= ( const GamePacket & other ) const 
				{
					// Ugh... 
				
					if ( GetAddress().GetIP() > other.GetAddress().GetIP() )
					{
						return true;
					}
					else if ( GetAddress().GetIP() == other.GetAddress().GetIP() )
					{
						if ( GetAddress().GetPort() > other.GetAddress().GetPort() )
						{
							return true;
						}
						else if ( GetAddress().GetPort() == other.GetAddress().GetPort() )
						{
							return GetPacketNumber() >= other.GetPacketNumber();
						}
						else
						{
							return false;
						}
					}
					else
					{
						return false;
					}
				}
				
				//=====================================================================================================
				/// @brief		Compares two packets for equality. Compares first based on the sender and
				///				next based on the packet number.
				/// @param		other - other packet to compare to
				/// @returns	Result of the comparison
				//=====================================================================================================
				
				inline bool operator < ( const GamePacket & other ) const 
				{
					// Ugh... 
				
					if ( GetAddress().GetIP() < other.GetAddress().GetIP() )
					{
						return true;
					}
					else if ( GetAddress().GetIP() == other.GetAddress().GetIP() )
					{
						if ( GetAddress().GetPort() < other.GetAddress().GetPort() )
						{
							return true;
						}
						else if ( GetAddress().GetPort() == other.GetAddress().GetPort() )
						{
							return GetPacketNumber() < other.GetPacketNumber();
						}
						else
						{
							return false;
						}
					}
					else
					{
						return false;
					}
				}
				
				//=====================================================================================================
				/// @brief		Compares two packets for equality. Compares first based on the sender and
				///				next based on the packet number.
				/// @param		other - other packet to compare to
				/// @returns	Result of the comparison
				//=====================================================================================================
				
				inline bool operator <= ( const GamePacket & other ) const 
				{
					// Ugh... 
				
					if ( GetAddress().GetIP() < other.GetAddress().GetIP() )
					{
						return true;
					}
					else if ( GetAddress().GetIP() == other.GetAddress().GetIP() )
					{
						if ( GetAddress().GetPort() < other.GetAddress().GetPort() )
						{
							return true;
						}
						else if ( GetAddress().GetPort() == other.GetAddress().GetPort() )
						{
							return GetPacketNumber() <= other.GetPacketNumber();
						}
						else
						{
							return false;
						}
					}
					else
					{
						return false;
					}
				}
				
				//=====================================================================================================
				/// @brief		Gets the address of the packet, which is either the destination address or the 
				///				address we received from- depending on the direction the packet is heading in.
				/// @returns	Address of the packet
				//=====================================================================================================
				
				inline const NetworkAddress & GetAddress() const { return m_address; }

				//=====================================================================================================
				/// @brief		Sets the address of the packet, which is either the destination address or the 
				///				address we received from- depending on the direction the packet is heading in.
				/// @param		address - the new address of the packet
				//=====================================================================================================
				
				inline void SetAddress( const NetworkAddress & address ){ m_address = address; }
				
				//=====================================================================================================
				/// @brief		Returns the number of bytes of data in this packet. This includes the last byte, 
				///				which may have some waste bits due to the read/write marker not being aligned on
				///				byte boundaries.
				/// @returns	The size of the packets payload (in bytes) as it currently stands
				/// @remarks	The packet payload size is increased by writing and decreased by reading
				//=====================================================================================================
				
				inline unsigned GetByteSize() const { return (unsigned) m_data.m_header.m_size; }
				
				//=====================================================================================================
				/// @brief		Returns the number of bits that have been either read or written from this packet.
				/// @returns	The number of bits that have been read or written.
				/// @remarks	The packet payload size is increased by writing and decreased by reading
				//=====================================================================================================

				inline unsigned GetBitCount(){ return m_current_bit; }
				
				//=====================================================================================================
				/// @brief		Returns the 16-bit checksum of this packet as it is in the header of the packet.
				/// @returns	The checksum for the packet as stored in the header
				//=====================================================================================================
				
				inline unsigned __int16 GetChecksum() const 
				{
					return m_data.m_header.m_checksum;
				}
				
				//=====================================================================================================
				/// @brief		Sets the 11-bit checksum for this packet.
				/// @param		checksum - value of the checksum
				/// @remarks	The setting of checksums is handled automatically by the GamePacket center. 
				//=====================================================================================================
				
				inline void SetChecksum( unsigned __int16 checksum )
				{
					// Set the checksum bits:
					
					m_data.m_header.m_checksum = checksum;
				}
				
				//=====================================================================================================
				/// @brief		Writes the given data to the packet's payload. This does a literal bit copy and may
				///				not be suited for objects that require assignment operators.
				/// @returns	True if the data was written, false if the packet cannot hold the data
				/// @remarks	This function increases the size of the packets payload after successful execution.
				/// @remarks	Reading and writing is done in the same order for network sends an receives.
				///				Reading will also move the current bit position in the stream forward, rather than backward.
				//=====================================================================================================
				
				template <class T> inline bool Write( const T & data )
				{
					// Write the bits and return the result:

					return WriteBits(&data,sizeof(T)*8);
				}
				
				//=====================================================================================================
				/// @brief		Writes an unsigned integer with the specified number of bits to the stream.
				/// @param		v - the value to write
				/// @param		bits - the number of bits to write
				/// @returns	True if the data could be written
				/// @pre		The number of bits must not be > 32
				/// @pre		The number of bits must be > 0
				//=====================================================================================================
				
				inline bool WritePrecisionUint( unsigned v , unsigned char bits )
				{
					// Make sure ok:
					
					ENSURE( bits <= 32	, "The number of bits must not be > 32" )
					ENSURE( bits > 0	, "The number of bits must be > 0"		)
					
					// Do the writing
					
					return WriteBits(&v,bits);
				}
				
				//=====================================================================================================
				/// @brief		Writes a packed unsigned integer where 5 bits at the start are used to indicate how
				///				many bits are needed to fully store the integer, and where the rest of the (required) 
				///				bits are stored normally. This is ideal where you small numbers are normally sent, 
				///				but where there is a safety requirement for large numbers (potentially) as well.
				///				This is useful for IDs of all sorts.
				/// @param		v - the value to write to the stream
				/// @returns	True on a successful write
				//=====================================================================================================
				
				inline bool WritePackedUint( unsigned v )
				{
					// Need to figure out the number of bits required to store the number:
					
					unsigned highest_bit = 0;
					
					// Go through all the bits and see which is the highest:
					
					for ( unsigned i = 0 ; i < 32 ; i++ )
					{
						if ( ( v & ( 1 << i ) ) != 0 ) highest_bit = i;
					}
					
					// Write the number of bits required to the stream:
					
					bool success = WritePrecisionUint(highest_bit,5);
					
					// See if ok:
					
					if ( success )
					{
						// Number of bits has 1 added to it
						
						highest_bit += 1;
						
						// Write the rest of the integer:
						
						success = WritePrecisionUint(v,(unsigned char)(highest_bit));
					}
					
					// Return if we succeeded:
					
					return success;
				}						
				
				//=====================================================================================================
				/// @brief		Writes a float in the range from 0 to 1 as two bytes or 16 bits
				/// @param		f - the float to write
				/// @pre		The given float must be in the range 0 to 1
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool WriteNormalisedFloat16( float f )
				{
					// Make sure ok
					
					ENSURE( f >= 0 && f <= 1 , "The given float must be in the range 0 to 1" )
					
					// Integerise the value of the float:
					
					unsigned val = unsigned( (float)(f) * float(0xfffff) );
					
					// Make sure not out of range:
					
					if ( val > 0xffff ) val = 0xffff;
					
					// Convert to short:
					
					unsigned short val_short = (unsigned short)(val);
					
					// Write it:
					
					return WriteBits(&val_short,sizeof(unsigned short)*8);
				}

				//=====================================================================================================
				/// @brief		Writes a float in the range from -1 to 1 using 12 bits
				/// @param		f - the float to write
				/// @pre		The given float must be in the range -1 to 1
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool WriteNormalisedSignedFloat12( float f )
				{
					// Make sure ok
					
					ENSURE( f >= -1 && f <= 1 , "The given float must be in the range 0 to 1" )

					// Store if the float is negative

					bool negative = f < 0 ? true : false; 

					// Make sure it is positive:

					f = Float::Abs(f);
					
					// Integerise the value of the float:
					
					unsigned val = unsigned( (float)(f) * float(0x7ff) );
					
					// Make sure not out of range:
					
					if ( val > 0x7ff ) val = 0x7ff;
					
					// If negative then set bit 11:

					if ( negative ) val |= 0x800;
					
					// Write it:
					
					return WriteBits(&val,12);
				}
				
				//=====================================================================================================
				/// @brief		Writes a float in the range from -1 to 1 using 16 bits
				/// @param		f - the float to write
				/// @pre		The given float must be in the range -1 to 1
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool WriteNormalisedSignedFloat16( float f )
				{
					// Make sure ok
					
					ENSURE( f >= -1 && f <= 1 , "The given float must be in the range 0 to 1" )

					// Store if the float is negative

					bool negative = f < 0 ? true : false; 

					// Make sure it is positive:

					f = Float::Abs(f);
					
					// Integerise the value of the float:
					
					unsigned val = unsigned( (float)(f) * float(0x7fff) );
					
					// Make sure not out of range:
					
					if ( val > 0x7fff ) val = 0x7fff;
					
					// If negative then set bit 15:

					if ( negative ) val |= 0x8000;
					
					// Write it:
					
					return WriteBits(&val,16);
				}				

				//=====================================================================================================
				/// @brief		Writes a floating point angle between -PI and +PI to the stream using 12 bits
				/// @param		a - the float to write that is a radian
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool WriteAngle12( float a )
				{
					// Wrap the angle

					a = Angle::Wrap(a);

					// Figure out where it lies in between -PI and PI

					float t = a / Float::PI();

					// Make sure it is in range:

					t = Float::Clamp(t,-1,1);

					// Write as a signed 12 bit float

					return WriteNormalisedSignedFloat12(t);
				}
				
				//=====================================================================================================
				/// @brief		Writes a floating point angle between -PI and +PI to the stream using 16 bits
				/// @param		a - the float to write that is a radian
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool WriteAngle16( float a )
				{
					// Wrap the angle

					a = Angle::Wrap(a);

					// Figure out where it lies in between -PI and PI

					float t = a / Float::PI();

					// Make sure it is in range:

					t = Float::Clamp(t,-1,1);

					// Write as a signed 12 bit float

					return WriteNormalisedSignedFloat16(t);
				}				

				//=====================================================================================================
				/// @brief		Writes a 3 dimensional floating point vector in 40 bits or 5 bytes.
				/// @param		v - vector to write
				//=====================================================================================================

				inline bool WriteVector40( const Vec3f & v )
				{
					// Get the length of the vector:

					float len = v.Length();

					// Produce a normalised version of the vector

					Vec3f n = v; 
					
					if ( len > 0 ) 
					{
						n.x /= len;
						n.y /= len;
					}

					// Make sure in range:

					n.x = Float::Clamp( n.x , -1 , 1 );
					n.y = Float::Clamp( n.y , -1 , 1 );

					// Write the length of the vector:

					bool success = Write( unsigned short(len) );

					// Write the two vector components: the third can be calculated at the other end

					success = success && WriteNormalisedSignedFloat12(n.x);
					success = success && WriteNormalisedSignedFloat12(n.y);

					// Return if we are successful

					return success;
				}
				
				//=====================================================================================================
				/// @brief		Writes a fixed point number in 4.8 format. 1 bit is used for sign, 3 are for
				///				the whole number, and 8 are for the decimal part.
				/// @param		v - the value to write
				/// @returns	True if the write was successful
				//=====================================================================================================
				
				bool WriteFP_4_8( float v )
				{
					// Convert to an integer:
					
					unsigned int_val = unsigned( int( v * 256 ) & 0x7fffffff );
					
					// Clamp if too big:
					
					if ( int_val > 0x7ff ) int_val = 0x7ff;
					
					// Now set the last bit if negative:
					
					if ( v < 0 ) int_val |= 0x800;
					
					// Write the integer:
					
					return WriteBits(&int_val,12);
				}				
				
				//=====================================================================================================
				/// @brief		Writes a packet chunk ID to the packet.
				/// @param		id - id of the chunk to write to the packet.
				/// @pre		The chunk id must be valid
				/// @returns	True if written successfully, false on failure.
				//=====================================================================================================
				
				bool WriteChunkId( GamePacketChunk::ChunkID id )
				{
					// Make sure ok:
					
					ENSURE( unsigned(id) < GamePacketChunk::PKCKID_INVALID , "The chunk id must be valid" )
					
					// Make sure not greater than the invalid chunk id:
					
					if ( unsigned(id) > unsigned(GamePacketChunk::PKCKID_INVALID) ) id = GamePacketChunk::PKCKID_INVALID;
					
					// Write:
					
					return WriteBits( &id , GamePacketChunk::CHUNK_ID_BITS );
				}
				
				//=====================================================================================================
				/// @brief		Writes a single bit flag to the stream
				/// @param		v - value to write
				/// @returns	True if written successfully, false on failure.
				//=====================================================================================================
				
				bool WriteFlag( bool v )
				{
					// See if true or false:
					
					if ( v ) return WritePrecisionUint(1,1); else return WritePrecisionUint(0,1);
				}
				
				//=====================================================================================================
				/// @brief		Reads the given data from the packet's payload into the given type. This does a 
				///				literal bit copy and may not be suited for objects that require assignment operators.
				/// @returns	True if the data was read, false if the packet does not have the necessary data
				/// @remarks	This function decreases the size of the packets payload after successful execution.
				/// @remarks	Reading and writing is done in the same order for network sends an receives.
				///				Reading will also move the current bit position in the stream forward, rather than backward.
				//=====================================================================================================
				
				template <class T> inline bool Read( T & data )
				{
					// Read the bits and return the result@

					return ReadBits(&data,sizeof(T)*8);
				}
				
				//=====================================================================================================
				/// @brief		Read an unsigned integer with the specified number of bits from the stream.
				/// @param		v - the value to read into
				/// @param		bits - the number of bits to read
				/// @returns	True if the data could be read
				/// @pre		The number of bits must not be > 32
				/// @pre		The number of bits must be > 0
				//=====================================================================================================
				
				inline bool ReadPrecisionUint( unsigned & v , unsigned char bits )
				{
					// Make sure ok:
					
					ENSURE( bits <= 32	, "The number of bits must not be > 32" )
					ENSURE( bits > 0	, "The number of bits must be > 0"		)										
					
					// Do the reading:
					
					v = 0; return ReadBits(&v,bits);
				}					
				
				//=====================================================================================================
				/// @brief		Reads a packed unsigned integer where 5 bits at the start are used to indicate how
				///				many bits are needed to fully store the integer, and where the rest of the (required) 
				///				bits are stored normally. This is ideal where you small numbers are normally sent, 
				///				but where there is a safety requirement for large numbers (potentially) as well.
				///				This is useful for IDs of all sorts.
				/// @param		v - the value for the integer is stored here
				/// @returns	True on a successful read
				//=====================================================================================================
				
				inline bool ReadPackedUint( unsigned & v )
				{
					// Read the number of bits in the integer
					
					unsigned bits = 0; bool success = ReadPrecisionUint(bits,5);
					
					// See if ok:
					
					if ( success )
					{
						// Number of bits has 1 added to it
						
						bits += 1;
						
						// Read the rest of the integer:
						
						success = ReadPrecisionUint(v,(unsigned char)(bits));
					}
					
					// Return if we succeeded:
					
					return success;
				}	

				//=====================================================================================================
				/// @brief		Reads a float in the range from -1 to 1 using 12 bits
				/// @param		f - the float to read to
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool ReadNormalisedSignedFloat12( float & f )
				{
					// Read the integer:

					unsigned val = 0; bool success = ReadBits(&val,12);

					// Convert to floating point:
					
					f = float( val & 0x7ff ) / float(0x7ff);

					// Negatise if bit 11 is set:

					if ( val & 0x800 ) f = -f;
					
					// Return if successful:
					
					return success;
				}
				
				//=====================================================================================================
				/// @brief		Reads a float in the range from -1 to 1 using 16 bits
				/// @param		f - the float to read to
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool ReadNormalisedSignedFloat16( float & f )
				{
					// Read the integer:

					unsigned val = 0; bool success = ReadBits(&val,16);

					// Convert to floating point:
					
					f = float( val & 0x7fff ) / float(0x7fff);

					// Negatise if bit 15 is set:

					if ( val & 0x8000 ) f = -f;
					
					// Return if successful:
					
					return success;
				}				
				
				//=====================================================================================================
				/// @brief		Reads a float in the range from 0 to 1 as two bytes or 16 bits
				/// @param		f - the float to read into
				//=====================================================================================================
				
				inline bool ReadNormalisedFloat16( float & f )
				{
					// Try and read the short value here:
					
					unsigned short val = 0; bool success = ReadBits(&val,sizeof(unsigned short)*8);
					
					// Convert back to float and return:
					
					f = float( (float)(val) / float(0xffff) );
					
					// Return if we did it or not
					
					return success;
				}

				//=====================================================================================================
				/// @brief		Read a floating point angle between -PI and +PI to the stream using 12 bits
				/// @param		a - the float to write that is a radian
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool ReadAngle12( float & a )
				{
					// Read the angle value:

					bool success = ReadNormalisedSignedFloat12(a);

					// Bring in -PI to PI range

					a *= Float::PI();

					// Return if it succeeded:

					return success;
				}
				
				//=====================================================================================================
				/// @brief		Read a floating point angle between -PI and +PI to the stream using 16 bits
				/// @param		a - the float to write that is a radian
				/// @returns	True if the data could be written
				//=====================================================================================================
				
				inline bool ReadAngle16( float & a )
				{
					// Read the angle value:

					bool success = ReadNormalisedSignedFloat16(a);

					// Bring in -PI to PI range

					a *= Float::PI();

					// Return if it succeeded:

					return success;
				}

				//=====================================================================================================
				/// @brief		Writes a 3 dimensional floating point vector in 40 bits or 5 bytes.
				/// @param		v - vector to write
				//=====================================================================================================

				inline bool ReadVector40( Vec3f & v )
				{
					// Read the length of the vector

					unsigned short len = 0;

					// Read the length of the vector
					
					bool success = ReadBits(&len,sizeof(unsigned short)*8);

					// Read the two vector components

					float x = 0; success = success && ReadNormalisedSignedFloat12(x);
					float y = 0; success = success && ReadNormalisedSignedFloat12(y);
					float z = 0;

					// Calculate the third component

					if ( success && len > 0 )
					{
						z = 1.0f - (( x * x ) + ( y * y )); 
						z = z < 0 ? 0 : z;
						z = Float::Sqrt(z);
					}

					// Calcaulte the vector:

					v.x = x * float(len);
					v.y = y * float(len);
					v.z = z * float(len);

					// Return if we are successful

					return success;
				}
				
				//=====================================================================================================
				/// @brief		Reads a fixed point number in 4.8 format. 1 bit is used for sign, 3 are for
				///				the whole number, and 8 are for the decimal part.
				/// @param		v - where to save the value
				/// @returns	True if the write was successful
				//=====================================================================================================
				
				bool ReadFP_4_8( float & v )
				{
					// Read the integer value
					
					unsigned int_val = 0; bool success = ReadBits(&int_val,12);
					
					// Convert to a float:
					
					v = float( int_val & 0x7ff ) / 256.0f; 
					
					// Negatise if the last bit is negative
					
					if ( int_val & 0x800 ) v = -v;
					
					// Return if there was success
					
					return success;
				}
				
				//=====================================================================================================
				/// @brief		Reads a packet chunk ID from the packet.
				/// @param		id - where to save the id of the chunk within the packet
				/// @returns	True if we read the value successfully, false otherwise
				//=====================================================================================================
				
				bool ReadChunkId( GamePacketChunk::ChunkID & id )
				{
					// Save the id here:
					
					unsigned id_int = 0;
				
					// Read the chunk id:
					
					bool success = ReadPrecisionUint(id_int,(unsigned char)(GamePacketChunk::CHUNK_ID_BITS));
					
					// Make sure not greater than the invalid chunk id:
					
					if ( id_int > GamePacketChunk::PKCKID_INVALID ) id_int = GamePacketChunk::PKCKID_INVALID;
					
					// See if ok:
					
					if ( success )
					{
						id = (GamePacketChunk::ChunkID)(id_int);
					}
					else
					{
						id = GamePacketChunk::PKCKID_INVALID;
					}
					
					// Return if that was ok:
					
					return success;
				}
				
				//=====================================================================================================
				/// @brief		Reads a single bit flag to the stream
				/// @param		v - value to read into
				/// @returns	True if written successfully, false on failure.
				//=====================================================================================================
				
				bool ReadFlag( bool & v )
				{
					// Try and do the read
					
					unsigned val = 0; bool success = ReadPrecisionUint(val,1);
					
					// See if that was succesful:
					
					if ( success )
					{
						if ( val == 1 ) v = true; else v = false;
					}
					
					// Return if successful 
					
					return success;
				}				
				
				//=====================================================================================================
				/// @brief		Rewinds the read/write marker in the packet by a given number of bits
				/// @param		bits - number of bits to rewind by
				/// @pre		The rewind operation must not result in the read/write marker underflowing the packet's
				///				internal data buffer.
				//=====================================================================================================
				
				inline void RewindBits( unsigned bits ) 
				{
					// Make sure ok:
					
					ENSURE
					( 
						m_current_bit >= bits , 
						"The rewind operation must not result in the read/write marker underflowing the packet's"
						"internal data buffer."
					)
					
					// Do the rewind:
					
					m_current_bit -= bits;
				}
				
				//=====================================================================================================
				/// @brief		Rewinds the read/write marker in the packet by a given number of bytes
				/// @param		bytes - number of bits to rewind by
				//=====================================================================================================
				
				inline void RewindBytes( unsigned bytes ){ RewindBits(bytes*8); }
				
				//=====================================================================================================
				/// @brief		Fast forwards the read/write marker in the packet by a given number of bits
				/// @param		bits - number of bits to skip forward by
				//=====================================================================================================
				
				inline void SkipBits( unsigned bits ) 
				{				
					// Do the skip:
					
					m_current_bit += bits;
					
					// Clamp to the end:
					
					if ( m_current_bit > PAYLOAD_SIZE * 8 ) m_current_bit = PAYLOAD_SIZE * 8;
				}
				
				//=====================================================================================================
				/// @brief		Fast forwards the read/write marker in the packet by a given number of bytes
				/// @param		bytes - number of bytes to skip forward by
				//=====================================================================================================
				
				inline void SkipBytes( unsigned bytes ){ SkipBits(bytes*8); }
				
				/// Computes the checksum and returns it
				
				unsigned __int16 ComputeChecksum() const;
				
				//=====================================================================================================
				/// @brief		Tells if the actual checksum of the packet matches the checksum in the header
				/// @returns	True if the two checksums agreee
				//=====================================================================================================
				
				inline bool HasValidChecksum() const
				{
					return ComputeChecksum() == GetChecksum();
				}
				
				//=====================================================================================================
				/// @brief		Gets the packet number for this packet
				/// @returns	The packet number for the packet.
				/// @remarks	The packet number is set on the sending side and incremented for each packet sent.
				//=====================================================================================================
				
				inline unsigned GetPacketNumber() const { return m_data.m_header.m_packet_num; }
				
				//=====================================================================================================
				/// @brief		Sets the packet number for this packet
				/// @param		num - number of the packet
				/// @remarks	The packet number is set on the sending side and incremented for each packet sent.
				//=====================================================================================================
				
				inline void SetPacketNumber( unsigned num ){ m_data.m_header.m_packet_num = num; }
				
				/// Writes the data of the packet to the given datagram socket
				
				bool WriteToSocket( DatagramSocket * socket ) const;
				
				/// Reads the data of the packet from the given datagram socket
				
				bool ReadFromSocket( DatagramSocket * socket );				
				
				// Debug only:
				
				#ifdef USE_DEBUG_CONSOLE
				
					/// Sets the time when we should send this packet to simulate latency and jitter
					
					inline void SetSendTime( unsigned send_time ){ m_send_time = send_time; }
					
					/// Get the time when we should send this packet to simulate latency and jitter
					
					inline unsigned GetSendTime() const { return m_send_time; }					
				
				#endif

		private:

			//=========================================================================================================
			// Functions
			//=========================================================================================================

				/// Writes a specified amount of bits to the packet:

				bool WriteBits( const void * bits , unsigned num_bits );

				/// Reads a specified amount of bits from the packet:

				bool ReadBits( void * bits , unsigned num_bits );

			//=========================================================================================================
			// Variables
			//=========================================================================================================
			
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// This is the address of the packet. It is either the sender of the packet or the address we are 
				/// sending to, depending on whether this is an incoming packet or an outgoing packet.
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				
				NetworkAddress m_address;

				/// The actual data of the packet itself
				
				Data m_data;

				/// This is the current bit we are writing/reading to/from in the data

				unsigned m_current_bit;
				
				// Debug only
				
				#ifdef USE_DEBUG_CONSOLE
				
					/// Time when we should send the packet to simulate network latency and jitter
					
					unsigned m_send_time;
				
				#endif
	};
};

#endif
