//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
# ifndef NETWORKVAR_H
# define NETWORKVAR_H
# ifdef _WIN32
# pragma once
# endif
# include "tier0/dbg.h"
# include "convar.h"
# if defined( CLIENT_DLL ) || defined( GAME_DLL )
# include "basehandle.h"
# endif
# pragma warning( disable : 4284 ) // warning C4284: return type for 'CNetworkVarT<int>::operator ->' is 'int *' (ie; not a UDT or reference to a UDT. Will produce errors if applied using infix notation)
# define MyOffsetOf( type, var ) ( (intp)&((type*)0)->var )
# ifdef _DEBUG
extern bool g_bUseNetworkVars ;
# define CHECK_USENETWORKVARS if(g_bUseNetworkVars)
# else
# define CHECK_USENETWORKVARS // don't check for g_bUseNetworkVars
# endif
inline int InternalCheckDeclareClass ( const char * pClassName , const char * pClassNameMatch , void * pTestPtr , void * pBasePtr )
{
// This makes sure that casting from ThisClass to BaseClass works right. You'll get a compiler error if it doesn't
// work at all, and you'll get a runtime error if you use multiple inheritance.
Assert ( pTestPtr = = pBasePtr ) ;
// This is triggered by IMPLEMENT_SERVER_CLASS. It does DLLClassName::CheckDeclareClass( #DLLClassName ).
// If they didn't do a DECLARE_CLASS in DLLClassName, then it'll be calling its base class's version
// and the class names won't match.
Assert ( ( void * ) pClassName = = ( void * ) pClassNameMatch ) ;
return 0 ;
}
template < typename T >
inline int CheckDeclareClass_Access ( T * , const char * pShouldBe )
{
return T : : CheckDeclareClass ( pShouldBe ) ;
}
# ifndef _STATIC_LINKED
# ifdef _MSC_VER
# if defined(_DEBUG) && (_MSC_VER > 1200 )
# define VALIDATE_DECLARE_CLASS 1
# endif
# endif
# endif
# ifdef VALIDATE_DECLARE_CLASS
# define DECLARE_CLASS( className, baseClassName ) \
typedef baseClassName BaseClass ; \
typedef className ThisClass ; \
template < typename T > friend int CheckDeclareClass_Access ( T * , const char * pShouldBe ) ; \
static int CheckDeclareClass ( const char * pShouldBe ) \
{ \
InternalCheckDeclareClass ( pShouldBe , # className , ( ThisClass * ) 0xFFFFF , ( BaseClass * ) ( ThisClass * ) 0xFFFFF ) ; \
return CheckDeclareClass_Access ( ( BaseClass * ) NULL , # baseClassName ) ; \
}
// Use this macro when you have a base class, but it's part of a library that doesn't use network vars
// or any of the things that use ThisClass or BaseClass.
# define DECLARE_CLASS_GAMEROOT( className, baseClassName ) \
typedef baseClassName BaseClass ; \
typedef className ThisClass ; \
template < typename T > friend int CheckDeclareClass_Access ( T * , const char * pShouldBe ) ; \
static int CheckDeclareClass ( const char * pShouldBe ) \
{ \
return InternalCheckDeclareClass ( pShouldBe , # className , ( ThisClass * ) 0xFFFFF , ( BaseClass * ) ( ThisClass * ) 0xFFFFF ) ; \
}
// Deprecated macro formerly used to work around VC++98 bug
# define DECLARE_CLASS_NOFRIEND( className, baseClassName ) \
DECLARE_CLASS ( className , baseClassName )
# define DECLARE_CLASS_NOBASE( className ) \
typedef className ThisClass ; \
template < typename T > friend int CheckDeclareClass_Access ( T * , const char * pShouldBe ) ; \
static int CheckDeclareClass ( const char * pShouldBe ) \
{ \
return InternalCheckDeclareClass ( pShouldBe , # className , 0 , 0 ) ; \
}
# else
# define DECLARE_CLASS( className, baseClassName ) \
typedef baseClassName BaseClass ; \
typedef className ThisClass ;
# define DECLARE_CLASS_GAMEROOT( className, baseClassName ) DECLARE_CLASS( className, baseClassName )
# define DECLARE_CLASS_NOFRIEND( className, baseClassName ) DECLARE_CLASS( className, baseClassName )
# define DECLARE_CLASS_NOBASE( className ) typedef className ThisClass;
# endif
// All classes that contain CNetworkVars need a NetworkStateChanged() function. If the class is not an entity,
// it needs to forward the call to the entity it's in. These macros can help.
// These macros setup an entity pointer in your class. Use IMPLEMENT_NETWORKVAR_CHAIN before you do
// anything inside the class itself.
class CBaseEntity ;
class CAutoInitEntPtr
{
public :
CAutoInitEntPtr ( )
{
m_pEnt = NULL ;
}
CBaseEntity * m_pEnt ;
} ;
//TODO: Currently, these don't get the benefit of tracking changes to individual vars.
// Would be nice if they did.
# define DECLARE_NETWORKVAR_CHAIN() \
CAutoInitEntPtr __m_pChainEntity ; \
void NetworkStateChanged ( ) { CHECK_USENETWORKVARS __m_pChainEntity . m_pEnt - > NetworkStateChanged ( ) ; } \
void NetworkStateChanged ( void * pVar ) { CHECK_USENETWORKVARS __m_pChainEntity . m_pEnt - > NetworkStateChanged ( ) ; }
# define IMPLEMENT_NETWORKVAR_CHAIN( varName ) \
( varName ) - > __m_pChainEntity . m_pEnt = this ;
// Use this macro when you want to embed a structure inside your entity and have CNetworkVars in it.
template < class T >
static inline void DispatchNetworkStateChanged ( T * pObj )
{
CHECK_USENETWORKVARS pObj - > NetworkStateChanged ( ) ;
}
template < class T >
static inline void DispatchNetworkStateChanged ( T * pObj , void * pVar )
{
CHECK_USENETWORKVARS pObj - > NetworkStateChanged ( pVar ) ;
}
# define DECLARE_EMBEDDED_NETWORKVAR() \
template < typename T > friend int ServerClassInit ( T * ) ; \
template < typename T > friend int ClientClassInit ( T * ) ; \
virtual void NetworkStateChanged ( ) { } virtual void NetworkStateChanged ( void * pProp ) { }
// NOTE: Assignment operator is disabled because it doesn't call copy constructors of scalar types within the aggregate, so they are not marked changed
# define CNetworkVarEmbedded( type, name ) \
class NetworkVar_ # # name ; \
friend class NetworkVar_ # # name ; \
static inline int GetOffset_ # # name ( ) { return MyOffsetOf ( ThisClass , name ) ; } \
typedef ThisClass ThisClass_ # # name ; \
class NetworkVar_ # # name : public type \
{ \
template < class T > NetworkVar_ # # name & operator = ( const T & val ) { * ( ( type * ) this ) = val ; return * this ; } \
public : \
void CopyFrom ( const type & src ) { * ( ( type * ) this ) = src ; NetworkStateChanged ( ) ; } \
virtual void NetworkStateChanged ( ) \
{ \
DispatchNetworkStateChanged ( ( ThisClass_ # # name * ) ( ( ( char * ) this ) - GetOffset_ # # name ( ) ) ) ; \
} \
virtual void NetworkStateChanged ( void * pVar ) \
{ \
DispatchNetworkStateChanged ( ( ThisClass_ # # name * ) ( ( ( char * ) this ) - GetOffset_ # # name ( ) ) , pVar ) ; \
} \
} ; \
NetworkVar_ # # name name ;
template < typename T >
FORCEINLINE void NetworkVarConstruct ( T & x ) { x = T ( 0 ) ; }
FORCEINLINE void NetworkVarConstruct ( color32_s & x ) { x . r = x . g = x . b = x . a = 0 ; }
template < class Type , class Changer >
class CNetworkVarBase
{
public :
inline CNetworkVarBase ( )
{
NetworkVarConstruct ( m_Value ) ;
}
template < class C >
const Type & operator = ( const C & val )
{
return Set ( ( const Type ) val ) ;
}
template < class C >
const Type & operator = ( const CNetworkVarBase < C , Changer > & val )
{
return Set ( ( const Type ) val . m_Value ) ;
}
const Type & Set ( const Type & val )
{
if ( memcmp ( & m_Value , & val , sizeof ( Type ) ) )
{
NetworkStateChanged ( ) ;
m_Value = val ;
}
return m_Value ;
}
Type & GetForModify ( )
{
NetworkStateChanged ( ) ;
return m_Value ;
}
template < class C >
const Type & operator + = ( const C & val )
{
return Set ( m_Value + ( const Type ) val ) ;
}
template < class C >
const Type & operator - = ( const C & val )
{
return Set ( m_Value - ( const Type ) val ) ;
}
template < class C >
const Type & operator / = ( const C & val )
{
return Set ( m_Value / ( const Type ) val ) ;
}
template < class C >
const Type & operator * = ( const C & val )
{
return Set ( m_Value * ( const Type ) val ) ;
}
template < class C >
const Type & operator ^ = ( const C & val )
{
return Set ( m_Value ^ ( const Type ) val ) ;
}
template < class C >
const Type & operator | = ( const C & val )
{
return Set ( m_Value | ( const Type ) val ) ;
}
const Type & operator + + ( )
{
return ( * this + = 1 ) ;
}
Type operator - - ( )
{
return ( * this - = 1 ) ;
}
Type operator + + ( int ) // postfix version..
{
Type val = m_Value ;
( * this + = 1 ) ;
return val ;
}
Type operator - - ( int ) // postfix version..
{
Type val = m_Value ;
( * this - = 1 ) ;
return val ;
}
// For some reason the compiler only generates type conversion warnings for this operator when used like
// CNetworkVarBase<unsigned char> = 0x1
// (it warns about converting from an int to an unsigned char).
template < class C >
const Type & operator & = ( const C & val )
{
return Set ( m_Value & ( const Type ) val ) ;
}
operator const Type & ( ) const
{
return m_Value ;
}
const Type & Get ( ) const
{
return m_Value ;
}
const Type * operator - > ( ) const
{
return & m_Value ;
}
Type m_Value ;
protected :
inline void NetworkStateChanged ( )
{
Changer : : NetworkStateChanged ( this ) ;
}
} ;
template < class Type , class Changer >
class CNetworkColor32Base : public CNetworkVarBase < Type , Changer >
{
public :
inline void Init ( byte rVal , byte gVal , byte bVal )
{
SetR ( rVal ) ;
SetG ( gVal ) ;
SetB ( bVal ) ;
}
inline void Init ( byte rVal , byte gVal , byte bVal , byte aVal )
{
SetR ( rVal ) ;
SetG ( gVal ) ;
SetB ( bVal ) ;
SetA ( aVal ) ;
}
const Type & operator = ( const Type & val )
{
return this - > Set ( val ) ;
}
const Type & operator = ( const CNetworkColor32Base < Type , Changer > & val )
{
return CNetworkVarBase < Type , Changer > : : Set ( val . m_Value ) ;
}
inline byte GetR ( ) const { return CNetworkColor32Base < Type , Changer > : : m_Value . r ; }
inline byte GetG ( ) const { return CNetworkColor32Base < Type , Changer > : : m_Value . g ; }
inline byte GetB ( ) const { return CNetworkColor32Base < Type , Changer > : : m_Value . b ; }
inline byte GetA ( ) const { return CNetworkColor32Base < Type , Changer > : : m_Value . a ; }
inline void SetR ( byte val ) { SetVal ( CNetworkColor32Base < Type , Changer > : : m_Value . r , val ) ; }
inline void SetG ( byte val ) { SetVal ( CNetworkColor32Base < Type , Changer > : : m_Value . g , val ) ; }
inline void SetB ( byte val ) { SetVal ( CNetworkColor32Base < Type , Changer > : : m_Value . b , val ) ; }
inline void SetA ( byte val ) { SetVal ( CNetworkColor32Base < Type , Changer > : : m_Value . a , val ) ; }
protected :
inline void SetVal ( byte & out , const byte & in )
{
if ( out ! = in )
{
CNetworkVarBase < Type , Changer > : : NetworkStateChanged ( ) ;
out = in ;
}
}
} ;
// Network vector wrapper.
template < class Type , class Changer >
class CNetworkVectorBase : public CNetworkVarBase < Type , Changer >
{
public :
inline void Init ( float ix = 0 , float iy = 0 , float iz = 0 )
{
SetX ( ix ) ;
SetY ( iy ) ;
SetZ ( iz ) ;
}
const Type & operator = ( const Type & val )
{
return CNetworkVarBase < Type , Changer > : : Set ( val ) ;
}
const Type & operator = ( const CNetworkVectorBase < Type , Changer > & val )
{
return CNetworkVarBase < Type , Changer > : : Set ( val . m_Value ) ;
}
inline float GetX ( ) const { return CNetworkVectorBase < Type , Changer > : : m_Value . x ; }
inline float GetY ( ) const { return CNetworkVectorBase < Type , Changer > : : m_Value . y ; }
inline float GetZ ( ) const { return CNetworkVectorBase < Type , Changer > : : m_Value . z ; }
inline float operator [ ] ( int i ) const { return CNetworkVectorBase < Type , Changer > : : m_Value [ i ] ; }
inline void SetX ( float val ) { DetectChange ( CNetworkVectorBase < Type , Changer > : : m_Value . x , val ) ; }
inline void SetY ( float val ) { DetectChange ( CNetworkVectorBase < Type , Changer > : : m_Value . y , val ) ; }
inline void SetZ ( float val ) { DetectChange ( CNetworkVectorBase < Type , Changer > : : m_Value . z , val ) ; }
inline void Set ( int i , float val ) { DetectChange ( CNetworkVectorBase < Type , Changer > : : m_Value [ i ] , val ) ; }
bool operator = = ( const Type & val ) const
{
return CNetworkVectorBase < Type , Changer > : : m_Value = = ( Type ) val ;
}
bool operator ! = ( const Type & val ) const
{
return CNetworkVectorBase < Type , Changer > : : m_Value ! = ( Type ) val ;
}
const Type operator + ( const Type & val ) const
{
return CNetworkVectorBase < Type , Changer > : : m_Value + val ;
}
const Type operator - ( const Type & val ) const
{
return CNetworkVectorBase < Type , Changer > : : m_Value - val ;
}
const Type operator * ( const Type & val ) const
{
return CNetworkVectorBase < Type , Changer > : : m_Value * val ;
}
const Type & operator * = ( float val )
{
return CNetworkVarBase < Type , Changer > : : Set ( CNetworkVectorBase < Type , Changer > : : m_Value * val ) ;
}
const Type operator * ( float val ) const
{
return CNetworkVectorBase < Type , Changer > : : m_Value * val ;
}
const Type operator / ( const Type & val ) const
{
return CNetworkVectorBase < Type , Changer > : : m_Value / val ;
}
private :
inline void DetectChange ( float & out , float in )
{
if ( out ! = in )
{
CNetworkVectorBase < Type , Changer > : : NetworkStateChanged ( ) ;
out = in ;
}
}
} ;
// Network vector wrapper.
template < class Type , class Changer >
class CNetworkQuaternionBase : public CNetworkVarBase < Type , Changer >
{
public :
inline void Init ( float ix = 0 , float iy = 0 , float iz = 0 , float iw = 0 )
{
SetX ( ix ) ;
SetY ( iy ) ;
SetZ ( iz ) ;
SetW ( iw ) ;
}
const Type & operator = ( const Type & val )
{
return CNetworkVarBase < Type , Changer > : : Set ( val ) ;
}
const Type & operator = ( const CNetworkQuaternionBase < Type , Changer > & val )
{
return CNetworkVarBase < Type , Changer > : : Set ( val . m_Value ) ;
}
inline float GetX ( ) const { return CNetworkQuaternionBase < Type , Changer > : : m_Value . x ; }
inline float GetY ( ) const { return CNetworkQuaternionBase < Type , Changer > : : m_Value . y ; }
inline float GetZ ( ) const { return CNetworkQuaternionBase < Type , Changer > : : m_Value . z ; }
inline float GetW ( ) const { return CNetworkQuaternionBase < Type , Changer > : : m_Value . w ; }
inline float operator [ ] ( int i ) const { return CNetworkQuaternionBase < Type , Changer > : : m_Value [ i ] ; }
inline void SetX ( float val ) { DetectChange ( CNetworkQuaternionBase < Type , Changer > : : m_Value . x , val ) ; }
inline void SetY ( float val ) { DetectChange ( CNetworkQuaternionBase < Type , Changer > : : m_Value . y , val ) ; }
inline void SetZ ( float val ) { DetectChange ( CNetworkQuaternionBase < Type , Changer > : : m_Value . z , val ) ; }
inline void SetW ( float val ) { DetectChange ( CNetworkQuaternionBase < Type , Changer > : : m_Value . w , val ) ; }
inline void Set ( int i , float val ) { DetectChange ( CNetworkQuaternionBase < Type , Changer > : : m_Value [ i ] , val ) ; }
bool operator = = ( const Type & val ) const
{
return CNetworkQuaternionBase < Type , Changer > : : m_Value = = ( Type ) val ;
}
bool operator ! = ( const Type & val ) const
{
return CNetworkQuaternionBase < Type , Changer > : : m_Value ! = ( Type ) val ;
}
const Type operator + ( const Type & val ) const
{
return CNetworkQuaternionBase < Type , Changer > : : m_Value + val ;
}
const Type operator - ( const Type & val ) const
{
return CNetworkQuaternionBase < Type , Changer > : : m_Value - val ;
}
const Type operator * ( const Type & val ) const
{
return CNetworkQuaternionBase < Type , Changer > : : m_Value * val ;
}
const Type & operator * = ( float val )
{
return CNetworkQuaternionBase < Type , Changer > : : Set ( CNetworkQuaternionBase < Type , Changer > : : m_Value * val ) ;
}
const Type operator * ( float val ) const
{
return CNetworkQuaternionBase < Type , Changer > : : m_Value * val ;
}
const Type operator / ( const Type & val ) const
{
return CNetworkQuaternionBase < Type , Changer > : : m_Value / val ;
}
private :
inline void DetectChange ( float & out , float in )
{
if ( out ! = in )
{
CNetworkQuaternionBase < Type , Changer > : : NetworkStateChanged ( ) ;
out = in ;
}
}
} ;
// Network ehandle wrapper.
# if defined( CLIENT_DLL ) || defined( GAME_DLL )
inline void NetworkVarConstruct ( CBaseHandle & x ) { }
template < class Type , class Changer >
class CNetworkHandleBase : public CNetworkVarBase < CBaseHandle , Changer >
{
public :
const Type * operator = ( const Type * val )
{
return Set ( val ) ;
}
const Type & operator = ( const CNetworkHandleBase < Type , Changer > & val )
{
const CBaseHandle & handle = CNetworkVarBase < CBaseHandle , Changer > : : Set ( val . m_Value ) ;
return * ( const Type * ) handle . Get ( ) ;
}
bool operator ! ( ) const
{
return ! CNetworkHandleBase < Type , Changer > : : m_Value . Get ( ) ;
}
operator Type * ( ) const
{
return static_cast < Type * > ( CNetworkHandleBase < Type , Changer > : : m_Value . Get ( ) ) ;
}
const Type * Set ( const Type * val )
{
if ( CNetworkHandleBase < Type , Changer > : : m_Value ! = val )
{
this - > NetworkStateChanged ( ) ;
CNetworkHandleBase < Type , Changer > : : m_Value = val ;
}
return val ;
}
Type * Get ( ) const
{
return static_cast < Type * > ( CNetworkHandleBase < Type , Changer > : : m_Value . Get ( ) ) ;
}
Type * operator - > ( ) const
{
return static_cast < Type * > ( CNetworkHandleBase < Type , Changer > : : m_Value . Get ( ) ) ;
}
bool operator = = ( const Type * val ) const
{
return CNetworkHandleBase < Type , Changer > : : m_Value = = val ;
}
bool operator ! = ( const Type * val ) const
{
return CNetworkHandleBase < Type , Changer > : : m_Value ! = val ;
}
} ;
# define CNetworkHandle( type, name ) CNetworkHandleInternal( type, name, NetworkStateChanged )
# define CNetworkHandleInternal( type, name, stateChangedFn ) \
NETWORK_VAR_START ( type , name ) \
NETWORK_VAR_END ( type , name , CNetworkHandleBase , stateChangedFn )
# endif
// Use this macro to define a network variable.
# define CNetworkVar( type, name ) \
NETWORK_VAR_START ( type , name ) \
NETWORK_VAR_END ( type , name , CNetworkVarBase , NetworkStateChanged )
// Use this macro when you have a base class with a variable, and it doesn't have that variable in a SendTable,
// but a derived class does. Then, the entity is only flagged as changed when the variable is changed in
// an entity that wants to transmit the variable.
# define CNetworkVarForDerived( type, name ) \
virtual void NetworkStateChanged_ # # name ( ) { } \
virtual void NetworkStateChanged_ # # name ( void * pVar ) { } \
NETWORK_VAR_START ( type , name ) \
NETWORK_VAR_END ( type , name , CNetworkVarBase , NetworkStateChanged_ # # name )
# define CNetworkVectorForDerived( name ) \
virtual void NetworkStateChanged_ # # name ( ) { } \
virtual void NetworkStateChanged_ # # name ( void * pVar ) { } \
CNetworkVectorInternal ( Vector , name , NetworkStateChanged_ # # name )
# define CNetworkHandleForDerived( type, name ) \
virtual void NetworkStateChanged_ # # name ( ) { } \
virtual void NetworkStateChanged_ # # name ( void * pVar ) { } \
CNetworkHandleInternal ( type , name , NetworkStateChanged_ # # name )
# define CNetworkArrayForDerived( type, name, count ) \
virtual void NetworkStateChanged_ # # name ( ) { } \
virtual void NetworkStateChanged_ # # name ( void * pVar ) { } \
CNetworkArrayInternal ( type , name , count , NetworkStateChanged_ # # name )
# define IMPLEMENT_NETWORK_VAR_FOR_DERIVED( name ) \
virtual void NetworkStateChanged_ # # name ( ) { CHECK_USENETWORKVARS NetworkStateChanged ( ) ; } \
virtual void NetworkStateChanged_ # # name ( void * pVar ) { CHECK_USENETWORKVARS NetworkStateChanged ( pVar ) ; }
// This virtualizes the change detection on the variable, but it is ON by default.
// Use this when you have a base class in which MOST of its derived classes use this variable
// in their SendTables, but there are a couple that don't (and they
// can use DISABLE_NETWORK_VAR_FOR_DERIVED).
# define CNetworkVarForDerived_OnByDefault( type, name ) \
virtual void NetworkStateChanged_ # # name ( ) { CHECK_USENETWORKVARS NetworkStateChanged ( ) ; } \
virtual void NetworkStateChanged_ # # name ( void * pVar ) { CHECK_USENETWORKVARS NetworkStateChanged ( pVar ) ; } \
NETWORK_VAR_START ( type , name ) \
NETWORK_VAR_END ( type , name , CNetworkVarBase , NetworkStateChanged_ # # name )
# define DISABLE_NETWORK_VAR_FOR_DERIVED( name ) \
virtual void NetworkStateChanged_ # # name ( ) { } \
virtual void NetworkStateChanged_ # # name ( void * pVar ) { }
// Vectors + some convenient helper functions.
# define CNetworkVector( name ) CNetworkVectorInternal( Vector, name, NetworkStateChanged )
# define CNetworkQAngle( name ) CNetworkVectorInternal( QAngle, name, NetworkStateChanged )
# define CNetworkVectorInternal( type, name, stateChangedFn ) \
NETWORK_VAR_START ( type , name ) \
NETWORK_VAR_END ( type , name , CNetworkVectorBase , stateChangedFn )
# define CNetworkQuaternion( name ) \
NETWORK_VAR_START ( Quaternion , name ) \
NETWORK_VAR_END ( Quaternion , name , CNetworkQuaternionBase , NetworkStateChanged )
// Helper for color32's. Contains GetR(), SetR(), etc.. functions.
# define CNetworkColor32( name ) \
NETWORK_VAR_START ( color32 , name ) \
NETWORK_VAR_END ( color32 , name , CNetworkColor32Base , NetworkStateChanged )
# define CNetworkString( name, length ) \
class NetworkVar_ # # name ; \
friend class NetworkVar_ # # name ; \
typedef ThisClass MakeANetworkVar_ # # name ; \
class NetworkVar_ # # name \
{ \
public : \
NetworkVar_ # # name ( ) { m_Value [ 0 ] = ' \0 ' ; } \
operator const char * ( ) const { return m_Value ; } \
const char * Get ( ) const { return m_Value ; } \
char * GetForModify ( ) \
{ \
NetworkStateChanged ( ) ; \
return m_Value ; \
} \
protected : \
inline void NetworkStateChanged ( ) \
{ \
CHECK_USENETWORKVARS ( ( ThisClass * ) ( ( ( char * ) this ) - MyOffsetOf ( ThisClass , name ) ) ) - > NetworkStateChanged ( ) ; \
} \
private : \
char m_Value [ length ] ; \
} ; \
NetworkVar_ # # name name ;
// Use this to define networked arrays.
// You can access elements for reading with operator[], and you can set elements with the Set() function.
# define CNetworkArrayInternal( type, name, count, stateChangedFn ) \
class NetworkVar_ # # name ; \
friend class NetworkVar_ # # name ; \
typedef ThisClass MakeANetworkVar_ # # name ; \
class NetworkVar_ # # name \
{ \
public : \
inline NetworkVar_ # # name ( ) \
{ \
for ( int i = 0 ; i < count ; + + i ) \
NetworkVarConstruct ( m_Value [ i ] ) ; \
} \
template < typename T > friend int ServerClassInit ( T * ) ; \
const type & operator [ ] ( int i ) const \
{ \
return Get ( i ) ; \
} \
\
const type & Get ( int i ) const \
{ \
Assert ( i > = 0 & & i < count ) ; \
return m_Value [ i ] ; \
} \
\
type & GetForModify ( int i ) \
{ \
Assert ( i > = 0 & & i < count ) ; \
NetworkStateChanged ( i ) ; \
return m_Value [ i ] ; \
} \
\
void Set ( int i , const type & val ) \
{ \
Assert ( i > = 0 & & i < count ) ; \
if ( memcmp ( & m_Value [ i ] , & val , sizeof ( type ) ) ) \
{ \
NetworkStateChanged ( i ) ; \
m_Value [ i ] = val ; \
} \
} \
const type * Base ( ) const { return m_Value ; } \
int Count ( ) const { return count ; } \
protected : \
inline void NetworkStateChanged ( int net_change_index ) \
{ \
CHECK_USENETWORKVARS ( ( ThisClass * ) ( ( ( char * ) this ) - MyOffsetOf ( ThisClass , name ) ) ) - > stateChangedFn ( & m_Value [ net_change_index ] ) ; \
} \
type m_Value [ count ] ; \
} ; \
NetworkVar_ # # name name ;
# define CNetworkArray( type, name, count ) CNetworkArrayInternal( type, name, count, NetworkStateChanged )
// Internal macros used in definitions of network vars.
# define NETWORK_VAR_START( type, name ) \
class NetworkVar_ # # name ; \
friend class NetworkVar_ # # name ; \
typedef ThisClass MakeANetworkVar_ # # name ; \
class NetworkVar_ # # name \
{ \
public : \
template < typename T > friend int ServerClassInit ( T * ) ;
# define NETWORK_VAR_END( type, name, base, stateChangedFn ) \
public : \
static inline void NetworkStateChanged ( void * ptr ) \
{ \
CHECK_USENETWORKVARS ( ( ThisClass * ) ( ( ( char * ) ptr ) - MyOffsetOf ( ThisClass , name ) ) ) - > stateChangedFn ( ptr ) ; \
} \
} ; \
base < type , NetworkVar_ # # name > name ;
# endif // NETWORKVAR_H