359 lines
15 KiB
C++
359 lines
15 KiB
C++
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#ifndef PREDICTIONCOPY_H
|
|
#define PREDICTIONCOPY_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include <memory.h>
|
|
#include "datamap.h"
|
|
#include "ehandle.h"
|
|
#include "tier1/utlstring.h"
|
|
#include "tier1/utlrbtree.h"
|
|
#include "tier1/utlstack.h"
|
|
|
|
#if defined( CLIENT_DLL )
|
|
class C_BaseEntity;
|
|
typedef CHandle<C_BaseEntity> EHANDLE;
|
|
|
|
// #define COPY_CHECK_STRESSTEST
|
|
#if defined( COPY_CHECK_STRESSTEST )
|
|
class IGameSystem;
|
|
IGameSystem* GetPredictionCopyTester( void );
|
|
#endif
|
|
|
|
#else
|
|
class CBaseEntity;
|
|
typedef CHandle<CBaseEntity> EHANDLE;
|
|
#endif
|
|
|
|
typedef void ( *FN_FIELD_COMPARE )( const char *classname, const char *fieldname, const char *fieldtype,
|
|
bool networked, bool noterrorchecked, bool differs, bool withintolerance, const char *value );
|
|
|
|
// Each datamap_t is broken down into two flattened arrays of fields,
|
|
// one for PC_NETWORKED_DATA and one for PC_NON_NETWORKED_ONLY (optimized_datamap_t::datamapinfo_t::flattenedoffsets_t)
|
|
// Each flattened array is sorted by offset for better cache performance
|
|
// Finally, contiguous "runs" off offsets are precomputed (optimized_datamap_t::datamapinfo_t::datacopyruns_t) for fast copy operations
|
|
|
|
// A data run is a set of DEFINE_PRED_FIELD fields in a c++ object which are contiguous and can be processing
|
|
// using a single memcpy operation
|
|
struct datarun_t
|
|
{
|
|
datarun_t() : m_nStartFlatField( 0 ), m_nEndFlatField( 0 ), m_nLength( 0 )
|
|
{
|
|
for ( int i = 0 ; i < TD_OFFSET_COUNT; ++i )
|
|
{
|
|
m_nStartOffset[ i ] = 0;
|
|
#ifdef _X360
|
|
// These are the offsets of the next run, for priming the L1 cache
|
|
m_nPrefetchOffset[ i ] = 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Indices of start/end fields in the flattened typedescription_t list
|
|
int m_nStartFlatField;
|
|
int m_nEndFlatField;
|
|
|
|
// Offsets for run in the packed/unpacked data (I think the run starts need to be properly aligned)
|
|
int m_nStartOffset[ TD_OFFSET_COUNT ];
|
|
#ifdef _X360
|
|
// These are the offsets of the next run, for priming the L1 cache
|
|
int m_nPrefetchOffset[ TD_OFFSET_COUNT ];
|
|
#endif
|
|
int m_nLength;
|
|
};
|
|
|
|
struct datacopyruns_t
|
|
{
|
|
public:
|
|
CUtlVector< datarun_t > m_vecRuns;
|
|
};
|
|
|
|
struct flattenedoffsets_t
|
|
{
|
|
CUtlVector< typedescription_t > m_Flattened;
|
|
int m_nPackedSize; // Contiguous memory to pack all of these together for TD_OFFSET_PACKED
|
|
int m_nPackedStartOffset;
|
|
};
|
|
|
|
struct datamapinfo_t
|
|
{
|
|
// Flattened list, with FIELD_EMBEDDED, FTYPEDESC_PRIVATE,
|
|
// and FTYPEDESC_OVERRIDE (overridden) fields removed
|
|
flattenedoffsets_t m_Flat;
|
|
datacopyruns_t m_CopyRuns;
|
|
};
|
|
|
|
struct optimized_datamap_t
|
|
{
|
|
// Optimized info for PC_NON_NETWORKED and PC_NETWORKED data
|
|
datamapinfo_t m_Info[ PC_COPYTYPE_COUNT ];
|
|
};
|
|
|
|
class CPredictionCopy
|
|
{
|
|
public:
|
|
typedef enum
|
|
{
|
|
DIFFERS = 0,
|
|
IDENTICAL,
|
|
WITHINTOLERANCE,
|
|
} difftype_t;
|
|
|
|
typedef enum
|
|
{
|
|
TRANSFERDATA_COPYONLY = 0, // Data copying only (uses runs)
|
|
TRANSFERDATA_ERRORCHECK_NOSPEW, // Checks for errors, returns after first error found
|
|
TRANSFERDATA_ERRORCHECK_SPEW, // checks for errors, reports all errors to console
|
|
TRANSFERDATA_ERRORCHECK_DESCRIBE, // used by hud_pdump, dumps values, etc, for all fields
|
|
} optype_t;
|
|
|
|
CPredictionCopy( int type, byte *dest, bool dest_packed, const byte *src, bool src_packed,
|
|
optype_t opType, FN_FIELD_COMPARE func = NULL );
|
|
|
|
int TransferData( const char *operation, int entindex, datamap_t *dmap );
|
|
|
|
static bool PrepareDataMap( datamap_t *dmap );
|
|
static const typedescription_t *FindFlatFieldByName( const char *fieldname, const datamap_t *dmap );
|
|
private:
|
|
|
|
// Operations:
|
|
void TransferDataCopyOnly( const datamap_t *dmap );
|
|
void TransferDataErrorCheckNoSpew( char const *pchOperation, const datamap_t *dmap );
|
|
void TransferDataErrorCheckSpew( char const *pchOperation, const datamap_t *dmap );
|
|
void TransferDataDescribe( char const *pchOperation, const datamap_t *dmap );
|
|
|
|
|
|
// Report function
|
|
void ReportFieldsDiffer( const datamap_t *pCurrentMap, const typedescription_t *pField, const char *fmt, ... );
|
|
void OutputFieldDescription( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t dt, const char *fmt, ... );
|
|
|
|
// Helper for TransferDataCopyOnly
|
|
void CopyFlatFieldsUsingRuns( const datamap_t *pCurrentMap, int nPredictionCopyType );
|
|
void CopyFlatFields( const datamap_t *pCurrentMap, int nPredictionCopyType );
|
|
template< class T >
|
|
FORCEINLINE void CopyField( difftype_t difftype, T *outvalue, const T *invalue, int count );
|
|
|
|
// Helper for TransferDataErrorCheckNoSpew
|
|
void ErrorCheckFlatFields_NoSpew( const datamap_t *pCurrentMap, int nPredictionCopyType );
|
|
template< class T >
|
|
FORCEINLINE void ProcessField_Compare_NoSpew( const datamap_t *pCurrentMap, const typedescription_t *pField, const T *pOutputData, const T *pInputData, int fieldSize );
|
|
|
|
// Helper for TransferDataErrorCheckSpew
|
|
void ErrorCheckFlatFields_Spew( const datamap_t *pCurrentMap, int nPredictionCopyType );
|
|
template< class T >
|
|
FORCEINLINE void ProcessField_Compare_Spew( const datamap_t *pCurrentMap, const typedescription_t *pField, const T *pOutputData, const T *pInputData, int fieldSize );
|
|
|
|
// Helper for TransferDataDescribe
|
|
void DescribeFields( const CUtlVector< const datamap_t * > &vecGroups, const datamap_t *pCurrentMap, int nPredictionCopyType );
|
|
// Main entry point
|
|
template< class T >
|
|
FORCEINLINE void ProcessField_Describe( const datamap_t *pCurrentMap, const typedescription_t *pField, const T *pOutputData, const T *pInputData, int fieldSize );
|
|
|
|
// Helpers for entity field watcher
|
|
void DetermineWatchField( const char *operation, int entindex, const datamap_t *dmap );
|
|
void WatchMsg( const typedescription_t *pField, const char *fmt, ... );
|
|
void DumpWatchField( const typedescription_t *pField, const byte *outvalue, int count );
|
|
template< class T >
|
|
FORCEINLINE void WatchField( const typedescription_t *pField, const T *outvalue, int count );
|
|
|
|
// Helper for ErrorCheck ops
|
|
template< class T >
|
|
FORCEINLINE difftype_t CompareField( const typedescription_t *pField, const T *outvalue, const T *invalue, int count );
|
|
// Used by TRANSFERDATA_ERRORCHECK_SPEW and by TRANSFERDATA_ERRORCHECK_DESCRIBE
|
|
template< class T >
|
|
FORCEINLINE void DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const T *outvalue, const T *invalue, int count );
|
|
|
|
private:
|
|
|
|
optype_t m_OpType;
|
|
int m_nType;
|
|
byte *m_pDest;
|
|
const byte *m_pSrc;
|
|
int m_nDestOffsetIndex;
|
|
int m_nSrcOffsetIndex;
|
|
int m_nErrorCount;
|
|
int m_nEntIndex;
|
|
|
|
FN_FIELD_COMPARE m_FieldCompareFunc;
|
|
|
|
const typedescription_t *m_pWatchField;
|
|
char const *m_pOperation;
|
|
|
|
CUtlStack< const typedescription_t * > m_FieldStack;
|
|
};
|
|
|
|
typedef void (*FN_FIELD_DESCRIPTION)( const char *classname, const char *fieldname, const char *fieldtype,
|
|
bool networked, const char *value );
|
|
|
|
//
|
|
// Compare methods
|
|
//
|
|
// Specializations
|
|
template<> FORCEINLINE CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const float *outvalue, const float *invalue, int count );
|
|
template<> FORCEINLINE CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const Vector *outvalue, const Vector *invalue, int count );
|
|
template<> FORCEINLINE CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const Quaternion *outvalue, const Quaternion *invalue, int count );
|
|
template<> FORCEINLINE CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const char *outvalue, const char *invalue, int count );
|
|
template<> FORCEINLINE CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const EHANDLE *outvalue, const EHANDLE *invalue, int count );
|
|
template<> FORCEINLINE CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const color32 *outvalue, const color32 *invalue, int count );
|
|
|
|
//
|
|
// Describe Methods
|
|
//
|
|
|
|
// Specializations
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const short *outvalue, const short *invalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const int *outvalue, const int *invalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const bool *outvalue, const bool *invalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const float *outvalue, const float *invalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const char *outvalue, const char *invalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const Vector* outValue, const Vector *inValue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const Quaternion* outValue, const Quaternion *inValue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const EHANDLE *outvalue, const EHANDLE *invalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const color32 *outvalue, const color32 *invalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const uint8 *outvalue, const uint8 *invalue, int count );
|
|
|
|
|
|
//
|
|
// Watch Methods
|
|
//
|
|
// Specializations
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const short *outvalue,int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const int *outvalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const bool *outvalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const float *outvalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const Vector *outvalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const Quaternion *outvalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const EHANDLE *outvalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const char *outvalue, int count );
|
|
template<> FORCEINLINE void CPredictionCopy::WatchField( const typedescription_t *pField, const color32 *outvalue, int count );
|
|
//
|
|
// Copy Methods
|
|
//
|
|
// specializations
|
|
template<> FORCEINLINE void CPredictionCopy::CopyField( difftype_t difftype, char *outvalue, const char *invalue, int count );
|
|
|
|
template< class T >
|
|
FORCEINLINE void CPredictionCopy::ProcessField_Compare_NoSpew( const datamap_t *pCurrentMap, const typedescription_t *pField, const T *pOutputData, const T *pInputData, int fieldSize )
|
|
{
|
|
difftype_t difftype = CompareField( pField, pOutputData, pInputData, fieldSize );
|
|
if ( difftype == DIFFERS )
|
|
{
|
|
++m_nErrorCount;
|
|
}
|
|
}
|
|
|
|
|
|
template< class T >
|
|
FORCEINLINE void CPredictionCopy::ProcessField_Compare_Spew( const datamap_t *pCurrentMap, const typedescription_t *pField, const T *pOutputData, const T *pInputData, int fieldSize )
|
|
{
|
|
difftype_t difftype = CompareField( pField, pOutputData, pInputData, fieldSize );
|
|
DescribeField( pCurrentMap, pField, difftype, pOutputData, pInputData, fieldSize );
|
|
}
|
|
|
|
|
|
template< class T >
|
|
FORCEINLINE void CPredictionCopy::ProcessField_Describe( const datamap_t *pCurrentMap, const typedescription_t *pField, const T *pOutputData, const T *pInputData, int fieldSize )
|
|
{
|
|
difftype_t difftype = CompareField( pField, pOutputData, pInputData, fieldSize );
|
|
DescribeField( pCurrentMap, pField, difftype, pOutputData, pInputData, fieldSize );
|
|
}
|
|
|
|
#if defined( CLIENT_DLL )
|
|
class CValueChangeTracker
|
|
{
|
|
public:
|
|
CValueChangeTracker();
|
|
|
|
void Reset();
|
|
|
|
void StartTrack( char const *pchContext );
|
|
void EndTrack();
|
|
|
|
bool IsActive() const;
|
|
|
|
void SetupTracking( C_BaseEntity *ent, char const *pchFieldName );
|
|
void ClearTracking();
|
|
|
|
void Spew();
|
|
|
|
C_BaseEntity *GetEntity();
|
|
|
|
private:
|
|
|
|
enum
|
|
{
|
|
eChangeTrackerBufSize = 128,
|
|
};
|
|
|
|
// Returns field size
|
|
void GetValue( char *buf, size_t bufsize );
|
|
|
|
bool m_bActive : 1;
|
|
bool m_bTracking : 1;
|
|
EHANDLE m_hEntityToTrack;
|
|
const typedescription_t *m_pTrackField;
|
|
CUtlString m_strFieldName;
|
|
CUtlString m_strContext;
|
|
// First 128 bytes of data is all we will consider
|
|
char m_OrigValueBuf[ eChangeTrackerBufSize ];
|
|
CUtlVector< CUtlString > m_History;
|
|
};
|
|
|
|
extern CValueChangeTracker *g_pChangeTracker;
|
|
|
|
class CValueChangeTrackerScope
|
|
{
|
|
public:
|
|
CValueChangeTrackerScope( char const *pchContext )
|
|
{
|
|
m_bCallEndTrack = true;
|
|
g_pChangeTracker->StartTrack( pchContext );
|
|
}
|
|
|
|
// Only calls Start/End if passed in entity matches entity to track
|
|
CValueChangeTrackerScope( C_BaseEntity *pEntity, char const *pchContext )
|
|
{
|
|
m_bCallEndTrack = g_pChangeTracker->GetEntity() == pEntity;
|
|
if ( m_bCallEndTrack )
|
|
{
|
|
g_pChangeTracker->StartTrack( pchContext );
|
|
}
|
|
}
|
|
|
|
~CValueChangeTrackerScope()
|
|
{
|
|
if ( m_bCallEndTrack )
|
|
{
|
|
g_pChangeTracker->EndTrack();
|
|
}
|
|
}
|
|
private:
|
|
|
|
bool m_bCallEndTrack;
|
|
};
|
|
|
|
#if defined( _DEBUG )
|
|
#define PREDICTION_TRACKVALUECHANGESCOPE( context ) CValueChangeTrackerScope scope( context );
|
|
#define PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( entity, context ) CValueChangeTrackerScope scope( entity, context );
|
|
#define PREDICTION_STARTTRACKVALUE( context ) g_pChangeTracker->StartTrack( context );
|
|
#define PREDICTION_ENDTRACKVALUE() g_pChangeTracker->EndTrack();
|
|
#define PREDICTION_SPEWVALUECHANGES() g_pChangeTracker->Spew();
|
|
#else
|
|
#define PREDICTION_TRACKVALUECHANGESCOPE( context )
|
|
#define PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( entity, context )
|
|
#define PREDICTION_STARTTRACKVALUE( context )
|
|
#define PREDICTION_ENDTRACKVALUE()
|
|
#define PREDICTION_SPEWVALUECHANGES()
|
|
#endif
|
|
|
|
#endif // !CLIENT_DLL
|
|
#endif // PREDICTIONCOPY_H
|