/*
	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.
*/

//=====================================================================================================================
/// @brief		This class handles the network session for the game. It sets up a connection for this peer as 
///				either a game host, a game host with a dummy (local) peer, or as a peer connecting to a host.
///				It also sets the game world itself once the session has been established, and handles the 
///				sending of network data. One final duty of the session is also to check for timeouts and
///				disconnections. All that logic also happens here.
//=====================================================================================================================

#include "Precompiled.h"
#include "Game\GameSession.h"
#include "Game\GameSessionDirector_Server.h"
#include "Game\GameSessionDirector_Client.h"
#include "Game\GameCore.h"
#include "Game\GamePeer.h"
#include "Game\GameMenus.h"
#include "Game\GameObjectManager.h"
#include "Game\GamePacketCenter.h"
#include "Game\GamePacket.h"
#include "GameObjects\GameMap.h"
#include "GameObjects\GamePlayer.h"
#include "Game\GameNetSerializer.h"
#include "Graphics\Camera3D.h"
#include "Network\DatagramSocket.h"

using namespace Game;

//=====================================================================================================================
// Statics
//=====================================================================================================================

/// This is a singleton pointer to this object

GameSession * GameSession::s_this = 0;

//=====================================================================================================================
/// @brief		Creates the session object that is initially disconnected
//=====================================================================================================================

GameSession::GameSession() : m_settings("NetConfig.xml")
{
	// Initially disconnected:
	
	m_session_state = STATE_DISCONNECTED;
	
	// No packet center:
	
	m_packet_center = 0;
	
	// Initialise these:
	
	m_peer_id = 0; m_next_peer_id = 1;
	
	// These are non-existant initially:
	
	m_server_director = 0;
	m_client_director = 0;
	
	// No control object initially:
	
	m_control_object = 0;
	
	// Fill this in
	
	s_this = this;
}

//=====================================================================================================================
/// @brief		Destroys the session object and disconnects if not already done so
/// @post		The list of game peers must have been cleared by this stage
//=====================================================================================================================

GameSession::~GameSession()
{
	// Disconnect:
	
	Disconnect();
	
	// Make sure ok:
	
	ENSURE( m_peers.size() == 0 , "The list of game peers must have been cleared by this stage" )
	
	// Clear this
	
	s_this = 0;
}

//=====================================================================================================================
/// @brief		Annouces the type name for this object.
/// @returns	Type name of this object
//=====================================================================================================================

const char * GameSession::GetTypeName() const { return "GameSession"; }

//=====================================================================================================================
/// @brief		Starts a new session. This will automatically tear down any existing session.
/// @param		type - type of game session we will have
/// @param		host - host for the sesssion. if we are the host then this is not used except for the port number, which
///				is the port the server listens on.
/// @pre		The game must exist
/// @pre		The game must have an object manager
//=====================================================================================================================

void GameSession::Connect( SessionType type , const NetworkAddress & host )
{
	// Make sure ok:
	
	ENSURE( GameCore::GetSingleton()						, "The game must exist"						)
	ENSURE( GameCore::GetSingleton()->GetObjectManager()	, "The game must have an object manager"	)	

	// Tear down any existing sessions:
	
	Disconnect();
	
	// Initialise these:
	
	m_peer_id = 0; m_next_peer_id = 1;
	
	// Set the session type:
	
	m_session_type = type;
	
	// See if we are acting as a client or a server
	
	if ( m_session_type == SESSION_SERVER )
	{
		// Reset the net ids for net objects:
		
		NetObject::ResetNextNetID();	
	
		// Now playing the game:
		
		m_session_state = STATE_PLAY;
	
		// Create our packet center:
		
		m_packet_center = new GamePacketCenter(host.GetPort(),m_settings.m_timeout_ms);
		
		// Make sure our socket is ok:
		
		if ( m_packet_center->GetSocket()->IsValid() )
		{
			// Make our server traffic director
			
			m_server_director = new GameSessionDirector_Server(*this);
			
			// Set the window titles:
			
			GameCore::GetSingleton()->GetWindow()->SetTitle
			(
				std::string(GameCore::GAME_TITLE) + ": Server @ port " + String::ToString(host.GetPort()) 
			);
			
			#ifdef USE_DEBUG_CONSOLE
			
				{
					// Do for debug console
			
					std::string title = std::string(GameCore::DEBUG_CONSOLE_TITLE) + ": Server @ port " + String::ToString(host.GetPort());
			
					DebugConsole::SetWindowTitle(title.c_str());
				}
			
			#endif		
		}
		else
		{
			// Invalid server socket: disconnect
			
			Disconnect();
		}
	}
	else
	{
		// Set the sesion state to connecting:
		
		m_session_state = STATE_CONNECTING;	
	
		// We are a client: connect to the server.
		
		m_packet_center = new GamePacketCenter(0,m_settings.m_timeout_ms);
		
		// Make the server peer:
		
		m_peers.push_back( new GamePeer(host,this) );
		
		// We have not been assigned a peer id yet:
		
		m_peer_id = 0xffffffff;		
		
		// Make our client traffic director:
		
		m_client_director = new GameSessionDirector_Client(*this);		
	}
}

//=====================================================================================================================
/// @brief		Disconnects from this session: this will destroy all objects in the game.
/// @pre		The game must exist
/// @pre		The game should have a game object manager
/// @pre		If we are disconnected then the packet center should be null
//=====================================================================================================================

void GameSession::Disconnect()
{
	// Make sure ok:
	
	ENSURE( GameCore::GetSingleton()						, "The game must exist"							)
	ENSURE( GameCore::GetSingleton()->GetObjectManager()	, "The game should have a game object manager"	)
	
	// Debug only:
	
	#ifdef DEBUG
	
		if ( IsConnected() == false )
		{
			ENSURE( m_packet_center == 0 , "If we are already disconnected then the packet center should be null" )
		}
	
	#endif
	
	// Set the window titles:
	
	GameCore::GetSingleton()->GetWindow()->SetTitle( GameCore::GAME_TITLE );
	
	#ifdef USE_DEBUG_CONSOLE
	
		DebugConsole::SetWindowTitle( GameCore::DEBUG_CONSOLE_TITLE );
	
	#endif
	
	// Remove our session directors:
	
	if ( m_server_director ) delete m_server_director; m_server_director = 0;
	if ( m_client_director ) delete m_client_director; m_client_director = 0;

	// Only if not disconnected already:
	
	if ( m_session_state != STATE_DISCONNECTED )
	{
		// Send a disconnect message to all peers:
		
		{		
			std::list<GamePeer*>::iterator i = m_peers.begin();
			std::list<GamePeer*>::iterator e = m_peers.end();
			
			// Remove them all:
			
			while ( i != e )
			{ 
				// Store the packet here:
			
				GamePacket p; 
				
				p.SetAddress((*i)->GetAddress());
				p.WriteChunkId(GamePacketChunk::PKCKID_DISCONNECT);
				p.WriteChunkId(GamePacketChunk::PKCKID_END);
				
				// Send it off:
				
				m_packet_center->WritePacket(p);
				
				// Move along
				
				i++;
			}
		}
	
		// Remove all the peers:
		
		{
			std::list<GamePeer*>::iterator i = m_peers.begin();
			std::list<GamePeer*>::iterator e = m_peers.end();
			
			// Remove them all:
			
			while ( i != e ){ delete *i; i++; } 
			
			// Clear the list:
			
			m_peers.clear();
		}
		
		// If we are a client then remove our control object:
		
		if ( IsClient() ) SetControlObject(0);
	
		// Destroy all objects in the game:
		
		GameCore::GetSingleton()->GetObjectManager()->Clear();
		
		// Get rid of the packet center:
		
		delete m_packet_center; m_packet_center = 0;
		
		// Now disconnected:
		
		m_session_state = STATE_DISCONNECTED;
	}
}

//=====================================================================================================================
/// @brief		Updates the game session: does network sends and receives
/// @pre		The game must exist
/// @pre		The game must have a menus object
/// @pre		The game must have a game object manager
/// @pre		If we are not disconnected we must have a packet center
/// @pre		If we are a client we should only be connected to one or no peer only
/// @pre		The number of peers must not exceed the maximum number of clients
/// @pre		There must be no peers with an invalid address
/// @pre		If we are already disconnected then the packet center should be null
/// @pre		If we are connected we should have a packet center
/// @pre		If we are a client and are not disconnected then there should be a server peer
/// @pre		If we are disconnected then there should be no peers
//=====================================================================================================================

void GameSession::Update()
{
	// Make sure ok:
	
	ENSURE( GameCore::GetSingleton()						, "The game must exist"													)
	ENSURE( GameCore::GetSingleton()->GetMenus()			, "The game must have a menus object"									)
	ENSURE( GameCore::GetSingleton()->GetObjectManager()	, "The game must have a game objet manager"								)
	ENSURE( m_peers.size() <= MAX_CLIENTS					, "The number of peers must not exceed the maximum number of clients"	)
	
	// Debug only:
	
	#ifdef DEBUG
	
		if ( IsConnected() == false )
		{
			ENSURE( m_packet_center == 0 , "If we are disconnected then the packet center should be null"	)
			ENSURE( m_peers.size()	== 0 , "If we are disconnected then there should be no peers"			)
		}
		else
		{
			ENSURE( m_packet_center != 0 , "If we are connected we should have a packet center"				) 			
		}
	
	#endif
	
	// Debug only:
	
	#ifdef DEBUG
	
		if ( IsConnected() && IsClient() )
		{
			ENSURE( m_peers.size() <= 1 , "If we are a client we should only be connected to one or no peer only" )
		}
	
	#endif
	
	// Only if we are connected:
	
	if ( IsConnected() )
	{
		// See if we are a server or not:
		
		if ( IsServer() ) 
		{
			ENSURE( m_server_director != 0 , "This object must be present" )
		
			m_server_director->Update(); 
		}
		else 
		{
			ENSURE( m_client_director != 0 , "This object must be present" )
		
			m_client_director->Update();
		}
		
		// Check if we need to send keep alive messages
		
		if ( IsConnected() ) CheckKeepalives();
		
		// Check for disconnections
		
		if ( IsConnected() ) CheckTimeouts();	
	}
}

//=====================================================================================================================
/// @brief		Checks for connections that need keepalive messages on either the client or the server
/// @pre		There must be no peers with an invalid address
/// @pre		We must be still connected
//=====================================================================================================================

void GameSession::CheckKeepalives()
{
	// Make sure ok:
	
	ENSURE( GameCore::GetSingleton()				, "The game must exist"					)
	ENSURE( GameCore::GetSingleton()->GetMenus()	, "The game must have a menus object"	)		
	ENSURE( m_packet_center != 0					, "We must be still connected"			)
	
	// Run through the list of peers

	std::list<GamePeer*>::iterator i = m_peers.begin();		 
	std::list<GamePeer*>::iterator e = m_peers.end();	
	
	while ( i != e )
	{
		// Get this peer and move on:
		
		GamePeer * peer = * i; i++;
		
		// Make sure ok:
		
		ENSURE( peer->GetAddress().IsValid() , "There must be no peers with an invalid address" )
		
		// See if we should send a keepalive message:
		
		if ( peer->ShouldSendKeepalive() )
		{
			// Good: makeup a packet to send to the peer
			
			GamePacket p; p.SetAddress( peer->GetAddress() );
			
			// Don't write anything to the packet: just a terminating chunk
			
			p.WriteChunkId( GamePacketChunk::PKCKID_END );
			
			// Off you go:
			
			m_packet_center->WritePacket(p);
			
			// Reset the time since the last send to this peer
			
			peer->SetLastSendTime();
		}
	}
}

//=====================================================================================================================
/// @brief		Checks for connections that have timed out on either the client or server
/// @pre		If we are a client and are not disconnected then there should be a server peer
/// @pre		We must be still connected
/// @pre		The game must exist
/// @pre		The game must have a menus object
/// @todo		notify other clients of the client object removal and properly cleanup
//=====================================================================================================================

void GameSession::CheckTimeouts()
{
	// Make sure this is ok
	
	ENSURE( m_packet_center != 0 , "We must be still connected" )

	// See if we are a client or a server

	if ( IsClient() )
	{	
		// Make sure ok:
		
		ENSURE( m_peers.size() == 1 , "If we are a client and are not disconnected then there should be a server peer" )
		
		// Get the server peer:
		
		GamePeer * server = m_peers.front();
		
		// See if we have timed out:
		
		if ( server->HasConnectionTimedOut() )
		{
			// Connection to the server has timed out: disconnect
			
			Disconnect();
			
			// Show the disconnect menu:
			
			GameCore::GetSingleton()->GetMenus()->SetMenu( GameMenus::MENU_CONNECTION_LOST );
		}
	}
	else if ( IsServer() )
	{
		// Need to run through all the clients
		
		std::list<GamePeer*>::iterator i = m_peers.begin();
		std::list<GamePeer*>::iterator e = m_peers.end();
		
		// Run through them all:
		
		while ( i != e )
		{
			// Get this client:
			
			GamePeer * client = *i;
			
			// See if connection to the client has timed out:
			
			if ( client->HasConnectionTimedOut() )
			{
				// Connection timeout: save this clients control object
				
				GameObjectBase * control_object = client->GetControlObject();
				
				// Get rid of this client:
				
				delete client;
				
				// Remove from the list of clients:
				
				i = m_peers.erase(i);
				
				// Remove this object from the game world
				
				if ( control_object )
				{				
					GameCore::GetSingleton()->GetObjectManager()->RemoveObject(control_object);
				}
			}
			else
			{
				// Move on in the list normally
				
				i++;
			}
		}
	}
}

//=====================================================================================================================
/// @brief		Server only function: tells if the given address is from one of our connected clients
/// @param		addr - address to check
/// @returns	True if this is our client's address
/// @pre		We must be connected
/// @pre		We must be a server
//=====================================================================================================================

bool GameSession::IsClientAddress( const NetworkAddress & addr ) const
{
	// Make sure ok:
	
	ENSURE( IsConnected()	, "We must be connected"	)
	ENSURE( IsServer()		, "We must be a server"		)
	
	// Run through the list of client peers:
	
	std::list<GamePeer*>::const_iterator i = m_peers.begin();
	std::list<GamePeer*>::const_iterator e = m_peers.end();
	
	while ( i != e )
	{
		// Get this client and move on:
		
		const GamePeer * client = *i; i++;
		
		// See if it's address matches the address given:
		
		if ( client->GetAddress() == addr ) return true;
	}
	
	// Not a client address: return false
	
	return false;
}

//=====================================================================================================================
/// @brief		Client only function: tells if the given address is the address of our server/// @param		
/// @param		addr - address to check
/// @returns	True if this is our server's address
/// @pre		We must be connected
/// @pre		We must be a client
/// @pre		There must be 1 peer in the peers list only for a client
//=====================================================================================================================

bool GameSession::IsServerAddress( const NetworkAddress & addr ) const
{
	// Make sure ok:
	
	ENSURE( IsConnected()		, "We must be connected"										)
	ENSURE( IsClient()			, "We must be a client"											)
	ENSURE( m_peers.size() == 1 , "There must be 1 peer in the peers list only for a client"	)
	
	// See if ok:
	
	const GamePeer * server = m_peers.front(); return server->GetAddress() == addr;
}

//=====================================================================================================================
/// @brief		Server only function: Returns the peer that sent a packet from the given network address
/// @param		addr - address of one of our clients
/// @returns	The requested client
/// @pre		This function can only be called on the server
/// @pre		The given address must represent one of our clients
/// @pre		We must be connected
//=====================================================================================================================

GamePeer * GameSession::GetSendingClient( const NetworkAddress & addr )
{
	// Make sure ok:
	
	ENSURE( IsConnected() , "We must be connected" )

	// Make sure ok:
	
	ENSURE( IsServer()				, "This function can only be called on the server"		)
	ENSURE( IsClientAddress(addr)	, "The given address must represent one of our clients" )
	
	// Find the client with this address:
	
	std::list<GamePeer*>::iterator i = m_peers.begin();
	std::list<GamePeer*>::iterator e = m_peers.end();
	
	// Run through the list:
	
	while ( i != e )
	{
		// Get this client and move on:
		
		GamePeer * client = *i; i++;
		
		// See if it's address matches
		
		if ( client->GetAddress() == addr ) return client;
	}
	
	// This is only here to keep the compiler happy
	
	return 0;
}

//=====================================================================================================================
/// @brief		Client only function: returns the address of the server
/// @returns	The address of the server
/// @pre		We must be a client and we must be connected
//=====================================================================================================================

NetworkAddress GameSession::GetServerAddress() const
{
	// Make sure ok:
	
	ENSURE( IsConnected() && IsClient() , "We must be a client and we must be connected" )
	
	// Get the top peer and return it's address: this will be the server
	
	return m_peers.front()->GetAddress();
}

//=====================================================================================================================
/// @brief		Returns the peer with the given id or null on failure
/// @param		id - id of the peer to get
/// @pre		We must be connected
//=====================================================================================================================

GamePeer * GameSession::GetPeer( unsigned id )
{
	// Make sure ok:
	
	ENSURE( IsConnected() , "We must be connected" )

	// Run through the list of peers and look for the peer with this id:

	std::list<GamePeer*>::iterator i = m_peers.begin();
	std::list<GamePeer*>::iterator e = m_peers.end();

	// Look for this id:

	while ( i != e )
	{
		// Get this peer:

		GamePeer * peer = * i; i++;

		// Return if there is a match

		if ( peer->GetPeerId() == id ) return peer;
	}

	// Not found: return null

	return 0;
}

//=====================================================================================================================
/// @brief		Client only function: sets the object we are controlling
/// @param		object - object we are controlling as the client
/// @pre		We must be connected
/// @pre		We must be a client
/// @pre		The object (if given) must have a valid net id and be involved in network transmission. 
/// @pre		The object (if given) must be owned by this client.
//=====================================================================================================================

void GameSession::SetControlObject( GameObjectBase * object )
{
	// Make sure ok:
	
	ENSURE( IsConnected()	, "We must be connected"	)
	ENSURE( IsClient()		, "We must be a client"		)
	
	#ifdef DEBUG
	
		if ( object )
		{
			ENSURE( object->IsLocalObject() , "The object (if given) must be owned by this client." )
			
			ENSURE
			( 
				object->GetNetId() != NetObject::NET_ID_NONE && object->GetNetId() != NetObject::NET_ID_INVALID ,
				"The object (if given) must have a valid net id and be involved in network transmission."
			)
		}
	
	#endif
	
	// Add a reference to the new object:
	
	if ( object ) object->AddReference();
	
	// See if we have a previous control object:
	
	if ( m_control_object ) m_control_object->RemoveReference();
	
	// Save:
	
	m_control_object = object;
}

//=====================================================================================================================
/// @brief		Client only function: returns the server peer
/// @pre		We must be connected
/// @pre		This must be called on the client
/// @post		There must be a server peer
//=====================================================================================================================

GamePeer & GameSession::GetServerPeer()
{
	// Make sure ok:
	
	ENSURE( IsConnected()		, "We must be connected"				)
	ENSURE( IsClient()			, "This must be called on the client"	)
	ENSURE( m_peers.size() == 1 , "There must be a server peer"			)
	
	// Return the server peer:
	
	return * m_peers.front();
}

//=====================================================================================================================
/// @brief		Adds a given client to the server. Also makes up pending create object requests so that the client
///				will receive all of the current game objects in the world at a later stage.
/// @param		client_address - address of the client to be added
/// @pre		We must be connected
/// @pre		We must be a server
/// @pre		GameCore must exist
/// @pre		GameCore must have a game object manager
/// @pre		The client must not already be added to the list of clients
/// @pre		The given network address must be valid
/// @pre		We must not be at the maximum number of clients
//=====================================================================================================================

GamePeer * GameSession::AddClient( const NetworkAddress & client_address )
{
	// Make sure ok:
	
	ENSURE( IsConnected()									, "We must be connected"							)
	ENSURE( IsServer()										, "This must be called on the server"				)
	ENSURE( GameCore::GetSingleton()						, "GameCore must exist"								)
	ENSURE( GameCore::GetSingleton()->GetObjectManager()	, "GameCore must have a game object manager"		)
	ENSURE( client_address.IsValid()						, "The given network address must be valid"			)
	ENSURE( m_peers.size() != MAX_CLIENTS					, "We must not be at the maximum number of clients"	)

	// Debug only:

	#ifdef DEBUG

		{
			std::list<GamePeer*>::iterator i = m_peers.begin();
			std::list<GamePeer*>::iterator e = m_peers.end();

			while ( i != e )
			{
				// Get this peer and move on:

				GamePeer * peer = * i; i++;

				// Make sure it is not the same as the given peer:

				ENSURE( client_address != peer->GetAddress() , "The client must not already be added to the list of clients" )
			}
		}

	#endif
	
	// Make the new client:
	
	GamePeer * client_peer = new GamePeer(client_address,this,m_next_peer_id);
	
	// Increment the client id of the next client to join
	
	m_next_peer_id++;

	// Add the client into the list of clients:

	m_peers.push_back(client_peer);

	// Get the game object manager 

	GameObjectManager & mgr = * GameCore::GetSingleton()->GetObjectManager();

	// Need to get the client to create all objects:

	std::vector<GameObjectBase*> objects; mgr.GetNetObjects(objects);

	// Send all of the objects to the client:

	for ( unsigned i = 0 ; i < objects.size() ; ++i )
	{
		// This should never fail:

		ENSURE( objects[i] != 0 , "Given a null NetObject! " )

		// Do this:

		client_peer->AddCreateRequest(*objects[i]);
	}
	
	// Return the created client
	
	return client_peer;
}

//=====================================================================================================================
/// @brief		Removes a given client from the game on the server
/// @param		client - client to remove
/// @pre		We must be connected
/// @pre		We must be a server
/// @pre		GameCore must exist
/// @pre		GameCore must have a game object manager
//=====================================================================================================================

void GameSession::RemoveClient( GamePeer & client )
{
	// Make sure ok:
	
	ENSURE( IsConnected()									, "We must be connected"						)
	ENSURE( IsServer()										, "This must be called on the server"			)
	ENSURE( GameCore::GetSingleton()						, "GameCore must exist"							)
	ENSURE( GameCore::GetSingleton()->GetObjectManager()	, "GameCore must have a game object manager"	)
		
	// See if the peer has a control object:
	
	if ( client.GetControlObject() )
	{
		// Save here:
		
		GameObjectBase * control_object = client.GetControlObject();
		
		// Add reference:
		
		control_object->AddReference();
		
		// Clear control object on the peer:
		
		client.SetControlObject(0);
		
		// Remove from the game:
		
		GameCore::GetSingleton()->GetObjectManager()->RemoveObject(control_object);
		
		// Now done with it:
		
		control_object->RemoveReference();
	}
}

//=====================================================================================================================
/// @brief		Notifies all clients that an object has been created and puts the event into a queue to be 
///				transmitted to all clients later. This is called by GameObjects on the server when they are 
///				added into the game. N.B there must be no duplicate requests to create!
/// @param		object - object to make the notification to all clients for
/// @pre		We must be connected
/// @pre		This can only be called on the server
//=====================================================================================================================

void GameSession::ClientCreateNofify( GameObjectBase & object )
{
	// Make sure ok

	ENSURE( IsConnected()		, "We must be connected"					)
	ENSURE( IsServer()			, "This can only be called on the server"	)

	// Run through all the clients:

	std::list<GamePeer*>::iterator i = m_peers.begin();
	std::list<GamePeer*>::iterator e = m_peers.end();

	while ( i != e )
	{
		// Get this peer

		GamePeer * peer = * i; i++;

		// Notify it:

		peer->AddCreateRequest(object);
	}
}

//=====================================================================================================================
/// @brief		Notifies all clients that an object has been delete and puts the event into a queue to be 
///				transmitted to all clients later. This is called by GameObjects on the server when they are 
///				removed into the game. N.B there must be no duplicate requests to delete!
/// @param		object - object to make the notification to all clients for
/// @pre		We must be connected
/// @pre		This can only be called on the server
//=====================================================================================================================

void GameSession::ClientDeleteNofify( GameObjectBase & object )
{
	// Make sure ok

	ENSURE( IsConnected()		, "We must be connected"					)
	ENSURE( IsServer()			, "This can only be called on the server"	)

	// Run through all the clients:

	std::list<GamePeer*>::iterator i = m_peers.begin();
	std::list<GamePeer*>::iterator e = m_peers.end();

	while ( i != e )
	{
		// Get this peer

		GamePeer * peer = * i; i++;

		// Notify it:

		peer->AddDeleteRequest(object);
	}
}
