//
// Asura_Network.h
//
// Created by Kevin Lea - 13/06/2001 11:30:33
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_NETWORK_H__
#define __ASURA_NETWORK_H__

#include "Core/Asura_Handle.h"
#include "Core/Asura_LinkList.h"
#include "Core/Asura_PlatformBasics.h"
#include "Network/Asura_Guid.h"

#ifndef ASURA_NETWORK_LOGGING
#if _DEBUG
#define ASURA_NETWORK_LOGGING 1
#else
#define ASURA_NETWORK_LOGGING 0
#endif
#endif

#define ASURA_CONSOLECMD_LISTPLAYERS  L"ListPlayers"
#define ASURA_CONSOLECMD_REMOVEPLAYER L"RemovePlayer"

static const float ASURA_NETWORK_TIME_BETWEEN_ENTITY_UPDATES = 0.1f;// deprecated
static const float fASURA_NETWORK_TIME_BETWEEN_ENTITY_UPDATES = 0.1f;
static const u_int uASURA_NETWORK_MSECS_BETWEEN_ENTITY_UPDATES = 100;
static const u_int ASURA_NETWORK_MAXHOSTNAMECHARS = 15;

enum ASURA_NETWORK_DISCONNECT_REASON
{
	ASURA_NDR_NOTDISCONNECTED = 0,			// connection is still valid 
	ASURA_NDR_UNKNOWN,						// unknown reason for losing connection
	ASURA_NDR_SERVERQUIT,					// the server has exited the game
	ASURA_NDR_SERVERKICK,					// kicked off by the server
	ASURA_NDR_VOTED,						// other players have voted us off
	ASURA_NDR_CHECKSUM,						// level checksums don't match
	ASURA_NDR_CHEATING,						// suspected of cheating
	ASURA_NDR_CDKEY,						// problems with the CD key
	ASURA_NDR_SERVERFULL,					// connection failed: too many players on server
	ASURA_NDR_PASSWORD,						// connection failed: incorrect password
	ASURA_NDR_VERSION,						// game versions do not match
	ASURA_NDR_TIMEOUT,						// time out reached
	ASURA_NDR_NETWORKING_ERROR,				// check the transport layer for more info
	ASURA_NDR_SERVER_RESET,					// ServerSessionID didn't match, so server must have restarted.
	ASURA_NDR_WRONG_CHALLENGE_RESPONSE,		// client challenge response incorrect
	ASURA_NDR_CLIENT_RESET,					// server thinks the client restarted without closing connection first.
	ASURA_NDR_CONNECTION_DROPPED,			// connection to the internet/network was lost.
	ASURA_NDR_PROFILE_LOGGED_OUT,			// received profile logged out event (e.g. logged GameSpy profile in on another machine)
	ASURA_NDR_FAILED_TO_LIST_SERVER,		// failed to get server registered so it won't appear on server lists etc.
	ASURA_NDR_IDLE,							// no input received from player too long
	ASURA_NDR_RELIABLESOCKET_ERROR,			// Check TCP.txt for detail (TODO: update this wrt steamworks)
	ASURA_NDR_NUM_REASONS,
	ASURA_NDR_START_PROJECT_REASONS = 100,
};

class Asura_Entity_Server;
class Asura_Message;
class Asura_MessageHeader;
class Asura_Network_ClientMachineStatus;
class Asura_Network_MessageBuffer;
class Asura_Network_MessageBuffer_Manager;
class Asura_Network_PlayerInfo;
class Asura_NetMsg;

class Asura_Network
{
	friend class Asura_Network_MessageBuffer;

	// Callback for completing sending all client create messages.
	typedef void(*ClientCreateMessagesSentFn)(Asura_Guid uClientGuid);

	public:


		/// Kevin Lea - 12/08/2002 16:33:33 - Initialise takes lots of exciting parameters:
		static void Initialise
		(
			bool bExternalNetworkRequired,	// need to connect to external machines
			bool bIsServer,					// true if this machine is server
			void(*pfnServerMessageHandler)(const Asura_Message* pxMessage)=0, // callback fn (project specific)
			void(*pfnClientMessageHandler)(const Asura_Message* pxMessage)=0, // callback fn (project specific)
			u_int uNumberOfLocalPlayers=4,	// number of players on this machine (i.e. num of split-screens)
			u_int uMaxNumberOfPlayers=32,	// total allowed in game (for servers)
			u_int uMaxNumberOfMachines=32,	// total machines allowed in game (for servers)
			const char* szIPAddressToConnectTo=0	// (for clients)
		);

		static void Shutdown(void);
        static inline bool IsNetworkInitialised(void) { return (s_pxMessagePool != NULL); }

		static void Update(void);
		static void EndOfFrameUpdate(void);
		// to enable use of NetMsg system on data from players to the server
		// and also to allow checking of where such updates are being made, 
		// call these 2 functions around the calls to the player's
		// MakeCommandMessageForServer calls.
		static void BeginClientToServerUpdates(void);
		static void EndClientToServerUpdates(void);

		static bool IsSendingDataAtEndOfFrame() { return s_bSendThisFrame; }
        static bool IsWaitingForClientGuid(void);
		static void StartGame(void);
        static void ForceClientUpdateAtEndOfFrame( void );
		static void SetServerLANReporting(bool bEnable);

		// ShouldMessageBeSentToClient() is used to restrict what messages get sent to specific 
		// clients based on things such as client state (e.g. no client updates for clients who
		// haven't actually joined a game but are still loading / in the front end) and possibly
		// bandwidth throttling. I may at some point add throttling to checks before the project 
		// check. (MH - 23.02.2005) 
		static bool ShouldMessageBeSentToClient( const Asura_Message* pxMessage, Asura_Guid uClientID );
        static bool ShouldMessageBeHandledOnClient( const Asura_Message* pxMsg ) { return Project_ShouldMessageBeHandledOnClient( pxMsg ); }

		static Asura_Message* CreateMessage(unsigned short messageID, 
											unsigned int dataSize = 0, 
											unsigned short usEntityClassification = 0,
											const void* pData = 0);
        static Asura_Message* DuplicateMessage( const Asura_Message* pxSrcMsg, bool bPointToExistingData );
		static void DestroyMessage(Asura_Message* message);
	
		static void Send( Asura_Message* pxMsg, bool bDestroyMsg = true, bool bSetSentTime = true );
		static void Forward( const Asura_Message* pxMessage, Asura_Guid uTo, Asura_Guid uFrom = ASURA_GUID_UNREGISTERED, bool bForceUseGuaranteed=false );
        
		// SendToSpecificMachine allows a message to be sent to a single client machine from the server.
		// It is currently only used for routing Create messages to a specific machine in order to 
		// conserve bandwidth. If uClientGuid is ASURA_GUID_UNREGISTERED the message is sent to all
		// client machines.
		static void SendToSpecificMachine( Asura_Message* pxMsg, Asura_Guid uClientGuid );

		// GetClientID returns the Guid of the first local player. This is so 
		// client entities can identify the machine they are on when requesting 
		// things like Create() messages which don't need to be sent to all machines.
		static Asura_Guid GetClientID();

		// GetLastClientID returns the same result as GetClientID(), but can be
		// (and should only be) called once Asura_Network has been shutdown. Allows 
		// GUID indexed data in systems which may be active after Asura_Network has 
		// shutdown to still be accessed for the local player.
		static Asura_Guid GetLastClientID();

		/// Kevin Lea - 12/08/2002 14:14:51 - returns a new client id for a human player
		/// should only be called by networking and Asura_Player. The networking uses it on the 
		/// server to assign player guids to a machine handle, the player code uses it on the 
		/// client to automatically set player guids to the client guids supplied by the network
		/// connection process.
		static Asura_Guid GetNewClientGuid(u_int uMachineNumber = 0);
		
		// SNH - 24/01/2005 16:36:09 - should only be called on server, and only by the net transport system.
		// When a client machine connects and we send it an initial client guid, add those guids to the client
		// machine status list. Allows RT to send messages to specific machines in the lobby (no player entities yet)
		static void AddPlayerToMachine(Asura_Guid uClientGuid, u_int uMachineNumber);

		static void ResetPlayerStatus();

		// functions for transport layer to get and release machine handles.
		static Asura_Handle AddMachineToGame(const u_int uMaxNumberOfPlayers);
		static bool RemoveMachineFromGame(const Asura_Handle iHandle);


		static inline bool IsExternalNetworkActive(void) 
		{
			return s_bExternalNetworkActive;
		}

		static inline bool IsPlayingOnInternet(void)
		{
			return s_bIsPlayingOnInternet;
		}

		static inline void SetPlayingOnInternet(bool bIsInternet)
		{
			s_bIsPlayingOnInternet = bIsInternet;
		}

        // Bear in mind that a machine can be both a client and server.
        static inline bool IsClient( void ) { return( s_pfnProject_ClientMessageHandler != NULL ); }
        static inline bool IsServer( void ) { return( s_pfnProject_ServerMessageHandler != NULL ); }
		static inline bool IsDedicatedServer( void ) { return s_bDedicatedServer; }

		static inline bool IsWaitingForConnection(void) 
		{
			return s_bWaitingForConnection;
		}
		static inline bool IsConnectionOkay(void) 
		{
			return s_bConnectionOkay;
		}

		static inline void SetWaitingForConnection(bool b) 
		{
			s_bWaitingForConnection = b;
		}
		static void SetConnectionOkay(bool b) 
		{
			s_bConnectionOkay = b;
		}

		static inline u_int GetNumberOfMachines(void)
		{
			return s_uNumberOfMachines;
		}

		static inline u_int GetMaxNumberOfMachines(void) 
		{
			return s_uMaxNumberOfMachines;
		}

		// (MH - 18.11.2003) GetNumberOfPlayers() can be used to iterate through
		// currently-connected players in conjunction with GetPlayerGuid(). Only 
		// valid on servers.
		static inline u_int GetNumberOfPlayers(void)
		{
			return s_uNumberOfPlayers;
		}

		static Asura_Guid GetPlayerGuid(u_int uPlayerIndex);

		static inline u_int GetMaxNumberOfPlayers(void)
		{
			return s_uMaxNumberOfPlayers;
		}

		static inline void SetMaxNumberOfPlayers(u_int uMaxPlayers)
		{
			Asura_Assert(uMaxPlayers >= s_uNumberOfPlayers, "Trying to set a maximum lower than the current number of players!");
			if(uMaxPlayers < s_uNumberOfPlayers) return;
			s_uMaxNumberOfPlayers = uMaxPlayers;
		}

		static bool IsReadyForMessages(void)
		{
			return s_bReadyForMessages;
		}
		static void SetReadyForMessages(bool b)
		{
			s_bReadyForMessages = b;
		}

#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
		static void AddMessageToQueue(Asura_Message* message);
		static void AddMessageToQueue(const Asura_MessageHeader* pxMsgHeader, const void* pData, bool bWasSendGuaranteed);
#endif // #ifdef ASURA_SUPPORT_EXTERNAL_NETWORK

		static float GetLatency(void);
		static u_int GetLatencyForPlayer(Asura_Guid uPlayerGuid);
        
        static bool IsPlayerConnected( Asura_Guid uPlayerGUID, bool bIncludeBots );
        static Asura_Handle GetMachineForPlayer( Asura_Guid uPlayerGUID, bool bIncludeBots );

		static void GetNetworkBandwidthUsage(u_int& uSend, u_int& uReceive);
		static void GetPeakNetworkBandwidthUsage(u_int& uSend, u_int& uReceive);
		static float GetPacketLossPercent() 
		{ 
		    if (!Asura_Network::IsNetworkInitialised())
			{
				return 0.0f;
			}
			return Platform_GetPacketLossPercent(); 
		}
		static void ResetNetworkBandwidthStats() { Platform_ResetNetworkBandwidthStats(); }

        static const Asura_UnicodeChar* GetServerName() { return s_awcHostName; }
		// GetServerNameBuffer() is for adding console var.
		static Asura_UnicodeChar* GetServerNameBuffer( u_int& uBfrSizeInclNull ) 
		{ 
			uBfrSizeInclNull = ASURA_NETWORK_MAXHOSTNAMECHARS + 1; 
			return s_awcHostName; 
		}
		static void SetServerName(const Asura_UnicodeChar* wszServerName);

        static const Asura_UnicodeChar* GetPlayerName( Asura_Guid uPlayerGUID );
        static Asura_Guid GetPlayerGUID( const Asura_UnicodeChar* wszPlayerName, bool bIncludeBots );

#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
		static bool AddConsoleCmdsAndVars();	// adds RemoveAtReset cmds and vars.
        static bool ConsoleCmd_ListPlayers( bool bHelp );
        static bool ConsoleCmd_RemovePlayer( const Asura_UnicodeChar* wszPlayerNameOrGUID, bool bInterrogate, bool bHelp );
		static bool ConsoleCmd_NetStats( bool bHelp );
        
        // Helper function for ConsoleCmd_RemovePlayer() but generally 
        // useful...
        static Asura_Guid Console_GetGUIDFromInput( const Asura_UnicodeChar* wszInput );
#endif

        static bool RemovePlayer( Asura_Guid uGUID, ASURA_NETWORK_DISCONNECT_REASON eReason = ASURA_NDR_UNKNOWN );
		static void SetReasonForDisconnection(ASURA_NETWORK_DISCONNECT_REASON eReason) { s_eReasonForDisconnection = eReason; }
		static ASURA_NETWORK_DISCONNECT_REASON GetReasonForDisconnection() { return s_eReasonForDisconnection; }

		static void FlushBufferedMessages(void);

        static void StartClient(const char* szIPAddressToConnectTo);

#if ASURA_NETWORK_LOGGING
		enum MSG_LOG_LEVEL
		{
			MSG_LOG_LEVEL_NONE,
			MSG_LOG_LEVEL_HEADER_ONLY,
			MSG_LOG_LEVEL_EXPAND_PACKED_MESSAGES,
			MSG_LOG_LEVEL_EXPAND_NETMSG_CONTENTS,
			MSG_LOG_LEVEL_NUM_LEVELS,
		};
		static MSG_LOG_LEVEL GetMsgLogLevel( void ) { return s_eMsgLogLevel; }
		static void SetMsgLogLevel( MSG_LOG_LEVEL eLevel, bool bSent = true, bool bReceived = false );
		// I have made these functions to convert msg ID, guid or entity classification 
		// to string public to improve debugging output.
		// Guid and Entity lookup may fail in which case nothing is written to pszDesc, 
		// so the ptr must be inialised to 0 or to a default string first.
		// if ASURA_NETWORK_LOGGING is 0, they return the ID as a string.
		static void GetMsgIDDesc( u_int uMsgID, const char** pszDesc );
		static void GetGuidDesc( Asura_Guid uGuid, const char** pszDesc );
		static void GetEntityClassificationDesc( u_short usEntityClassification, const char** pszDesc );
#endif
		// These overloaded versions are more convenient as they always return a valid string, 
		// and if ASURA_NETWORK_LOGGING is 0, they return the ID as a string.
		static const char* GetMsgIDDesc( u_int uMsgID );
		static const char* GetGuidDesc( Asura_Guid uGuid );
		static const char* GetEntityClassificationDesc( u_short usEntityClassification );

		// (AW - 27/07/05 - Ported from BHD branch, useful to know to stop cable unplugging cheats.
		static u_int GetMSecsSinceLastMessageReceived();

		static void RegisterClientForCreateMessages(Asura_Guid uGuid);
		static void SetClientCreateMessagesSentFunction(ClientCreateMessagesSentFn pfnClientCreateMessagesSentFn) { s_pfnClientCreateMessagesSentFn = pfnClientCreateMessagesSentFn; }

#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
		static void AddClientToIgnoreNetMsgUpdatesList(Asura_Guid uGuid);
		static void RemoveClientFromIgnoreNetMsgUpdatesList(Asura_Guid uGuid);
		static const Asura_NetMsg* RegisterNetMsg(u_short usMsgID, u_short usEntityClassification);
		static bool IsMessageDataInNetworkByteOrder(u_short usMsgID, u_short usEntityClassification);
#endif //#ifdef ASURA_SUPPORT_NETMSG_SYSTEM

		static void RemoveClientFromInitialisationLists(Asura_Guid uGuid);

	private:
		static void Platform_EndOfFrame(void);
		
		static void Platform_SetServerLANReporting(bool bEnable);

		static void PlatformUpdate(void);

		static void StartServer(void);
		static void StopServer(void);

		static void ServerMessageHandler(const Asura_Message* pxMessage);
		static void ClientMessageHandler(const Asura_Message* pxMessage);

		
		static void StopClient(void);

		static void UpdateClientCreateMessageList();

		static void BuildEntitiesToCreateList(Asura_LinkList<Asura_Guid>& xList);
		static void SendAllClientCreateMessages(Asura_Guid uGuid); // Probably only ever for the server's players.
		static bool ShouldAddToCreateMessageList(const Asura_Entity_Server* pxEntity);

		// functions for external network
#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
		static void AddToClientUpdatePackage(Asura_Message* message);
		static void BufferMessageToServer(const Asura_Message* pxMessage);
		static void BufferMessageToAllRemoteClients(const Asura_Message* pxMessage);
		static void BufferMessageToSingleClient(const Asura_Message* pxMessage, int iMachine);
#endif
		static void PlatformInitialise(void);
		static void PlatformShutdown(void);

		static bool PlatformStartServer(void);
		static void PlatformStopServer(void);

		static void PlatformStartClient(const char* szIPAddressToConnectTo);
		static void PlatformStopClient(void);

		// (MH - 13.07.2004) when a player is kicked, the player's machine must be removed from 
		// the game. Platform_RemoveMachineFromGame should result in the machine being removed
		// within the delay time. Allowing some delay for buffered and guaranteed messages to 
		// arrive is advisable, e.g. to ensure the player is informed of why he was kicked.
		static void Platform_RemoveMachineFromGame( int iMachine, float fDelay );
		
		static void Platform_SendMessageToServer(const Asura_Message* pxMessage);
		static void Platform_SendMessageToAllClients(const Asura_Message* pxMessage);
		static void Platform_SendMessageToClientMachine(const Asura_Message* pxMessage, int iMachine);
		static void Platform_StartGame();

		static void Platform_LockMessageQueue(void);
		static void Platform_UnlockMessageQueue(void);

		static float Platform_GetLatency(void);
		static u_int Platform_GetLatencyForPlayer(Asura_Guid uPlayerGuid);
		static void Platform_GetNetworkBandwidthUsage(u_int& uSend, u_int& uReceive);
		static void Platform_GetPeakNetworkBandwidthUsage(u_int& uSend, u_int& uReceive);
		static float Platform_GetPacketLossPercent();
		static void Platform_ResetNetworkBandwidthStats();

        static void Platform_SetServerName(const Asura_UnicodeChar* wszServerName);

		static bool Platform_ClientMessageHandler(const Asura_Message* pxMessage);
		static bool Platform_ServerMessageHandler(const Asura_Message* pxMessage);

		static bool Project_ShouldMessageBeSentToClient( const Asura_Message* pxMessage, Asura_Guid uClientID );
        static bool Project_ShouldMessageBeHandledOnClient( const Asura_Message* pxMsg );

        static bool Project_IsBotConnected( Asura_Guid uBotGUID );
        static bool Project_RemoveBot( Asura_Guid uBotGUID );

        static Asura_Guid Project_GetPlayerGUID( const Asura_UnicodeChar* wszPlayerName, bool bIncludeBots );
        static const Asura_UnicodeChar* Project_GetPlayerName( Asura_Guid uPlayerGUID );

#ifdef ASURA_SUPPORT_COMMAND_CONSOLE
		static bool Project_ListClientPlayersInConsole( void );
        static bool Project_ListBotsInConsole( void );
#endif

#if ASURA_NETWORK_LOGGING
		// set iMachine to -1 for unknown.
#ifdef ASURA_SUPPORT_EXTERNAL_NETWORK
		static void LogMsgInfo( const Asura_MessageHeader& xMsgHeader, const void* pData, bool bIndent, bool bReceived, int iMachine = -1);
#endif
		static void Project_GetMsgIDDesc( u_int uMsgID, const char** pszDesc );
		static void Project_GetEntityClassificationDesc( u_short usEntityClassification, const char** pszDesc );
#endif
		
#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
		static const Asura_NetMsg* Project_RegisterNetMsg(u_short usMsgID, u_short usEntityClassification);
		static bool Project_IsMessageDataInNetworkByteOrder(u_short usMsgID, u_short usEntityClassification);
#endif
		static class Asura_Mempool* s_pxMessagePool;
		
		static float	s_fTimeSinceLastClientUpdates;	// Asura_Network::Update() updates s_fTimeSinceLastClientUpdates
		static bool		s_bSendThisFrame;				// and sets s_bSendThisFrame if we're going to send in EndOfFrameUpdate()

		static bool		s_bExternalNetworkActive;
		static bool		s_bIsPlayingOnInternet;
		static bool		s_bServer;
		static bool		s_bDedicatedServer;
						
		static bool		s_bWaitingForConnection;
		static bool		s_bConnectionOkay;
						
		static bool		s_bReadyForMessages;
		static bool		s_bReceivedValidClientGuids;
						
		static u_int	s_uMaxNumberOfPlayers;
		static u_int	s_uMaxNumberOfMachines;

		static u_int	s_uNumberOfPlayers;
		static Asura_Network_PlayerInfo* s_pxPlayerInfo;
		static u_int	s_uNumberOfMachines;
		
		static ASURA_NETWORK_DISCONNECT_REASON s_eReasonForDisconnection;

		static Asura_UnicodeChar s_awcHostName[ASURA_NETWORK_MAXHOSTNAMECHARS + 1];
			
		/// Kevin Lea - 09/08/2002 17:40:13 - describes which players are on which machines 
		static Asura_Network_ClientMachineStatus*	s_pxClientMachineStatus;
		static Asura_Tracking_Handle_List*			s_pxClientMachineHandleList;

		/// Kevin Lea - 18/12/2001 11:56:08 - server specific data
		static Asura_Guid s_uNextClientGuid;
		static class Asura_Network_GuidRecycler* s_pxGuidRecycler;

		// SNH - 02/09/2003 14:22:11 - client data.
		// s_uInitialClientGuid: the s_uNextClientGuid we were given by the server when we connected. This is stored so when ResetPlayerStatus is called
		// s_uNextClientGuid can be set to its initial value - this means that in eg network coop games, when we don't want to close the
		// network connection between levels, players can be created each level with the same guid (Dredd's code assumes this in some places).
		static Asura_Guid s_uInitialClientGuid;	

		// SNH - 02/09/2003 14:47:25 - s_uNextGuidForNewClients is the next guid which will be given to new clients when they connect. This is not reset in
		// ResetPlayerStatus, so two clients can never end up with the same client guid. Server specific. (Only reset on network shutdown / initialise).
		static Asura_Guid s_uNextGuidForNewClients;

		/// Kevin Lea - 19/12/2001 10:59:47 - project specific fn pointer
		/// set when initialising the Network
		static void(*s_pfnProject_ServerMessageHandler)(const Asura_Message* pxMessage);
		static void(*s_pfnProject_ClientMessageHandler)(const Asura_Message* pxMessage);
		
		// (MH - 09.05.2003) on server, keep a buffer for each client machine. 
		// Buffers can be flushed at any time. Clients just keep a single buffer 
		// for sending to the server. The manager is an interface for this. 
		static Asura_Network_MessageBuffer_Manager* s_pxMsgBuffManager;

#if ASURA_NETWORK_LOGGING
		static MSG_LOG_LEVEL	s_eMsgLogLevel;
		static bool				s_bLogMessagesSent;
		static bool				s_bLogMessagesReceived;
#endif
		// (AW - 27/07/05 - Ported from BHD branch, useful to know to stop cable unplugging cheats.
		static u_int s_uTimeOfLastMessageReceived;

		// AJG - 17/01/08 - Lists to help with games that have an initialising phase between loading and playing a level, allowing them to create all client entities on remote machines without waiting for update messages to be sent.
		static Asura_LinkList<Asura_Guid> s_xClientsAwaitingCreateMessages;
		static ClientCreateMessagesSentFn s_pfnClientCreateMessagesSentFn; // Function to allow projects to do something when a client machine has had all its client create messages sent.

		struct CreatingClientData
		{
			Asura_Guid m_uClientGuid;
			Asura_LinkList<Asura_Guid> m_xEntitiesToCreate;
		};

		static Asura_LinkList<CreatingClientData*> s_xClientsReceivingCreateMessages;
		static float s_fTimeUntilNextCreateMessageBatch;

#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
		static Asura_LinkList<Asura_Guid> s_xClientsIgnoringNetMsgUpdates; // This list will often match the one above, but projects may want to leave clients in this one for a little longer, to give the create messages a chance to arrive.
#endif //#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
};

#endif//__ASURA_NETWORK_H__
