diff options
Diffstat (limited to 'public/saverestoretypes.h')
| -rw-r--r-- | public/saverestoretypes.h | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/public/saverestoretypes.h b/public/saverestoretypes.h new file mode 100644 index 0000000..491a96e --- /dev/null +++ b/public/saverestoretypes.h @@ -0,0 +1,541 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// @Note (toml 12-02-02): For now, all of the methods in the types defined here +// are inline to permit simple cross-DLL usage +//=============================================================================// + +#ifndef SAVERESTORETYPES_H +#define SAVERESTORETYPES_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier1/utlhash.h" + +#include <string_t.h> // NULL_STRING define +struct edict_t; + + +#ifdef EHANDLE_H // not available to engine +#define SR_ENTS_VISIBLE 1 +#endif + + +//----------------------------------------------------------------------------- +// +// class CSaveRestoreSegment +// + +class CSaveRestoreSegment +{ +public: + CSaveRestoreSegment(); + + //--------------------------------- + // Buffer operations + // + void Init( void *pNewBase, int nBytes ); + void Rebase(); + void Rewind( int nBytes ); + char *GetBuffer(); + int BytesAvailable() const; + int SizeBuffer() const; + bool Write( const void *pData, int nBytes ); + bool Read( void *pOutput, int nBytes ); + int GetCurPos(); + char *AccessCurPos(); + bool Seek( int absPosition ); + void MoveCurPos( int nBytes ); + + //--------------------------------- + // Symbol table operations + // + void InitSymbolTable( char **pNewTokens, int sizeTable); + char **DetachSymbolTable(); + int SizeSymbolTable(); + bool DefineSymbol( const char *pszToken, int token ); + unsigned short FindCreateSymbol( const char *pszToken ); + const char *StringFromSymbol( int token ); + +private: + unsigned int HashString( const char *pszToken ); + + //--------------------------------- + // Buffer data + // + char *pBaseData; // Start of all entity save data + char *pCurrentData; // Current buffer pointer for sequential access + int size; // Current data size, aka, pCurrentData - pBaseData + int bufferSize; // Total space for data + + //--------------------------------- + // Symbol table + // + int tokenCount; // Number of elements in the pTokens table + char **pTokens; // Hash table of entity strings (sparse) +}; + + +//----------------------------------------------------------------------------- +// +// class CGameSaveRestoreInfo +// + +struct levellist_t +{ + DECLARE_SIMPLE_DATADESC(); + + char mapName[ MAX_MAP_NAME_SAVE ]; + char landmarkName[ 32 ]; + edict_t *pentLandmark; + Vector vecLandmarkOrigin; +}; + +#define MAX_LEVEL_CONNECTIONS 16 // These are encoded in the lower 16bits of entitytable_t->flags + +//------------------------------------- + +struct EHandlePlaceholder_t // Engine does some of the game writing (alas, probably shouldn't), but can't see ehandle.h +{ + unsigned long i; +}; + +//------------------------------------- + +struct entitytable_t +{ + void Clear() + { + id = -1; + edictindex = -1; + saveentityindex = -1; + restoreentityindex = -1; + location = 0; + size = 0; + flags = 0; + classname = NULL_STRING; + globalname = NULL_STRING; + landmarkModelSpace.Init(); + modelname = NULL_STRING; + } + + int id; // Ordinal ID of this entity (used for entity <--> pointer conversions) + int edictindex; // saved for if the entity requires a certain edict number when restored (players, world) + + int saveentityindex; // the entity index the entity had at save time ( for fixing up client side entities ) + int restoreentityindex; // the entity index given to this entity at restore time + +#ifdef SR_ENTS_VISIBLE + EHANDLE hEnt; // Pointer to the in-game entity +#else + EHandlePlaceholder_t hEnt; +#endif + + int location; // Offset from the base data of this entity + int size; // Byte size of this entity's data + int flags; // This could be a short -- bit mask of transitions that this entity is in the PVS of + string_t classname; // entity class name + string_t globalname; // entity global name + Vector landmarkModelSpace; // a fixed position in model space for comparison + // NOTE: Brush models can be built in different coordiante systems + // in different levels, so this fixes up local quantities to match + // those differences. + string_t modelname; + + DECLARE_SIMPLE_DATADESC(); +}; + +#define FENTTABLE_PLAYER 0x80000000 +#define FENTTABLE_REMOVED 0x40000000 +#define FENTTABLE_MOVEABLE 0x20000000 +#define FENTTABLE_GLOBAL 0x10000000 +#define FENTTABLE_PLAYERCHILD 0x08000000 // this entity is connected to a player, so it must be spawned with it +#define FENTTABLE_LEVELMASK 0x0000FFFF // reserve bits for 16 level connections +//------------------------------------- + +struct saverestorelevelinfo_t +{ + int connectionCount;// Number of elements in the levelList[] + levellist_t levelList[ MAX_LEVEL_CONNECTIONS ]; // List of connections from this level + + // smooth transition + int fUseLandmark; + char szLandmarkName[20]; // landmark we'll spawn near in next level + Vector vecLandmarkOffset; // for landmark transitions + float time; + char szCurrentMapName[MAX_MAP_NAME_SAVE]; // To check global entities + int mapVersion; +}; + +//------------------------------------- + +class CGameSaveRestoreInfo +{ +public: + CGameSaveRestoreInfo() + : tableCount( 0 ), pTable( 0 ), m_pCurrentEntity( 0 ), m_EntityToIndex( 1024 ) + { + memset( &levelInfo, 0, sizeof( levelInfo ) ); + modelSpaceOffset.Init( 0, 0, 0 ); + } + + void InitEntityTable( entitytable_t *pNewTable = NULL, int size = 0 ) + { + pTable = pNewTable; + tableCount = size; + + for ( int i = 0; i < NumEntities(); i++ ) + { + GetEntityInfo( i )->Clear(); + } + } + + entitytable_t *DetachEntityTable() + { + entitytable_t *pReturn = pTable; + pTable = NULL; + tableCount = 0; + return pReturn; + } + + CBaseEntity *GetCurrentEntityContext() { return m_pCurrentEntity; } + void SetCurrentEntityContext(CBaseEntity *pEntity) { m_pCurrentEntity = pEntity; } + + int NumEntities() { return tableCount; } + entitytable_t *GetEntityInfo( int i ) { return (pTable + i); } + float GetBaseTime() const { return levelInfo.time; } + Vector GetLandmark() const { return ( levelInfo.fUseLandmark ) ? levelInfo.vecLandmarkOffset : vec3_origin; } + + void BuildEntityHash() + { +#ifdef GAME_DLL + int i; + entitytable_t *pTable; + int nEntities = NumEntities(); + + for ( i = 0; i < nEntities; i++ ) + { + pTable = GetEntityInfo( i ); + m_EntityToIndex.Insert( CHashElement( pTable->hEnt.Get(), i ) ); + } +#endif + } + + void PurgeEntityHash() + { + m_EntityToIndex.Purge(); + } + + int GetEntityIndex( const CBaseEntity *pEntity ) + { +#ifdef SR_ENTS_VISIBLE + if ( pEntity ) + { + if ( m_EntityToIndex.Count() ) + { + UtlHashHandle_t hElement = m_EntityToIndex.Find( CHashElement( pEntity ) ); + if ( hElement != m_EntityToIndex.InvalidHandle() ) + { + return m_EntityToIndex.Element( hElement ).index; + } + } + else + { + int i; + entitytable_t *pEntTable; + + int nEntities = NumEntities(); + for ( i = 0; i < nEntities; i++ ) + { + pEntTable = GetEntityInfo( i ); + if ( pEntTable->hEnt == pEntity ) + return pEntTable->id; + } + } + } +#endif + return -1; + } + + saverestorelevelinfo_t levelInfo; + Vector modelSpaceOffset; // used only for globaly entity brushes modelled in different coordinate systems. + +private: + int tableCount; // Number of elements in the entity table + entitytable_t *pTable; // Array of entitytable_t elements (1 for each entity) + CBaseEntity *m_pCurrentEntity; // only valid during the save functions of this entity, NULL otherwise + + + struct CHashElement + { + const CBaseEntity *pEntity; + int index; + + CHashElement( const CBaseEntity *pEntity, int index) : pEntity(pEntity), index(index) {} + CHashElement( const CBaseEntity *pEntity ) : pEntity(pEntity) {} + CHashElement() {} + }; + + class CHashFuncs + { + public: + CHashFuncs( int ) {} + + // COMPARE + bool operator()( const CHashElement &lhs, const CHashElement &rhs ) const + { + return lhs.pEntity == rhs.pEntity; + } + + // HASH + unsigned int operator()( const CHashElement &item ) const + { + return HashItem( item.pEntity ); + } + }; + + typedef CUtlHash<CHashElement, CHashFuncs, CHashFuncs> CEntityToIndexHash; + + CEntityToIndexHash m_EntityToIndex; +}; + +//----------------------------------------------------------------------------- + + +class CSaveRestoreData : public CSaveRestoreSegment, + public CGameSaveRestoreInfo +{ +public: + CSaveRestoreData() : bAsync( false ) {} + + + bool bAsync; +}; + +inline CSaveRestoreData *MakeSaveRestoreData( void *pMemory ) +{ + return new (pMemory) CSaveRestoreData; +} + +//----------------------------------------------------------------------------- +// +// class CSaveRestoreSegment, inline functions +// + +inline CSaveRestoreSegment::CSaveRestoreSegment() +{ + memset( this, 0, sizeof(*this) ); +} + +inline void CSaveRestoreSegment::Init( void *pNewBase, int nBytes ) +{ + pCurrentData = pBaseData = (char *)pNewBase; + size = 0; + bufferSize = nBytes; +} + +inline void CSaveRestoreSegment::MoveCurPos( int nBytes ) +{ + pCurrentData += nBytes; + size += nBytes; +} + +inline void CSaveRestoreSegment::Rebase() +{ + pBaseData = pCurrentData; + bufferSize -= size; + size = 0; +} + +inline void CSaveRestoreSegment::Rewind( int nBytes ) +{ + if ( size < nBytes ) + nBytes = size; + + MoveCurPos( -nBytes ); +} + +inline char *CSaveRestoreSegment::GetBuffer() +{ + return pBaseData; +} + +inline int CSaveRestoreSegment::BytesAvailable() const +{ + return (bufferSize - size); +} + +inline int CSaveRestoreSegment::SizeBuffer() const +{ + return bufferSize; +} + +inline bool CSaveRestoreSegment::Write( const void *pData, int nBytes ) +{ + if ( nBytes > BytesAvailable() ) + { + size = bufferSize; + return false; + } + + memcpy( pCurrentData, pData, nBytes ); + MoveCurPos( nBytes ); + + return true; +} + +inline bool CSaveRestoreSegment::Read( void *pOutput, int nBytes ) +{ + if ( !BytesAvailable() ) + return false; + + if ( nBytes > BytesAvailable() ) + { + size = bufferSize; + return false; + } + + if ( pOutput ) + memcpy( pOutput, pCurrentData, nBytes ); + MoveCurPos( nBytes ); + return true; +} + +inline int CSaveRestoreSegment::GetCurPos() +{ + return size; +} + +inline char *CSaveRestoreSegment::AccessCurPos() +{ + return pCurrentData; +} + +inline bool CSaveRestoreSegment::Seek( int absPosition ) +{ + if ( absPosition < 0 || absPosition >= bufferSize ) + return false; + + size = absPosition; + pCurrentData = pBaseData + size; + return true; +} + +inline void CSaveRestoreSegment::InitSymbolTable( char **pNewTokens, int sizeTable) +{ + Assert( !pTokens ); + tokenCount = sizeTable; + pTokens = pNewTokens; + memset( pTokens, 0, sizeTable * sizeof( pTokens[0]) ); +} + +inline char **CSaveRestoreSegment::DetachSymbolTable() +{ + char **pResult = pTokens; + tokenCount = 0; + pTokens = NULL; + return pResult; +} + +inline int CSaveRestoreSegment::SizeSymbolTable() +{ + return tokenCount; +} + +inline bool CSaveRestoreSegment::DefineSymbol( const char *pszToken, int token ) +{ + if ( pTokens[token] == NULL ) + { + pTokens[token] = (char *)pszToken; + return true; + } + Assert( 0 ); + return false; +} + +inline unsigned short CSaveRestoreSegment::FindCreateSymbol( const char *pszToken ) +{ + unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)tokenCount ); + +#if _DEBUG + static int tokensparsed = 0; + tokensparsed++; + if ( !tokenCount || !pTokens ) + { + AssertMsg( 0, ("No token table array in TokenHash()!") ); + } +#endif + + for ( int i=0; i<tokenCount; i++ ) + { +#if _DEBUG + static bool beentheredonethat = false; + if ( i > 50 && !beentheredonethat ) + { + beentheredonethat = true; + AssertMsg( 0, ("CSaveRestoreBuffer::TokenHash() is getting too full!" ) ); + } +#endif + + int index = hash + i; + if ( index >= tokenCount ) + index -= tokenCount; + + if ( !pTokens[index] || strcmp( pszToken, pTokens[index] ) == 0 ) + { + pTokens[index] = (char *)pszToken; + return index; + } + } + + // Token hash table full!!! + // [Consider doing overflow table(s) after the main table & limiting linear hash table search] + Warning( "CSaveRestoreBuffer::TokenHash() is COMPLETELY FULL!" ); + Assert( 0 ); + return 0; +} + +inline const char *CSaveRestoreSegment::StringFromSymbol( int token ) +{ + if ( token >= 0 && token < tokenCount ) + return pTokens[token]; + Assert( 0 ); + return "<<illegal>>"; +} + +/// XXX(JohnS): I'm not sure using an intrinsic has any value here, just doing the shift should be recognized by most +/// compilers. Either way, there's no portable intrinsic. + +// Newer GCC versions provide this in this header, older did by default. +#if !defined( _rotr ) && defined( COMPILER_GCC ) +#include <x86intrin.h> +#endif + +#ifdef COMPILER_CLANG +static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__)) +_rotr(unsigned int _Value, int _Shift) { + _Shift &= 0x1f; + return _Shift ? (_Value >> _Shift) | (_Value << (32 - _Shift)) : _Value; +} +#endif + + +inline unsigned int CSaveRestoreSegment::HashString( const char *pszToken ) +{ + COMPILE_TIME_ASSERT( sizeof( unsigned int ) == 4 ); + unsigned int hash = 0; + + while ( *pszToken ) + hash = _rotr( hash, 4 ) ^ *pszToken++; + + return hash; +} + +//============================================================================= + +#endif // SAVERESTORETYPES_H |