//--------------------------------------------------------------------------------- // Purpose: returns the specified prop offset relative to the table provided. // if offset or table not found, bErr returns true and offset returned is 0 //--------------------------------------------------------------------------------- unsigned int GetPropOffsetFromTable(const char *pTableName, const char *pPropName) { ServerClass *pClass = pServerDLL->GetAllServerClasses(); if (!pClass) { Warning("servergamedll->GetAllServerClasses() returned null\n"); return 0; } while (pClass) { SendTable *pTable = GetDataTable( pTableName, pClass->m_pTable ); if (pTable == NULL) { pClass = pClass->m_pNext; continue; } int num = pTable->GetNumProps(); for (int i = 0; i < num; i++) { SendProp *pProp = pTable->GetProp(i); if ( FStrEq( pPropName, pProp->GetName() ) ) { return pProp->GetOffset(); } } pClass = pClass->m_pNext; } Warning("prop %s not found in %s or table name incorrect\n", pPropName, pTableName); return 0; }
bool UTIL_ContainsDataTable(SendTable *pTable, const char *name) { const char *pname = pTable->GetName(); int props = pTable->GetNumProps(); SendProp *prop; SendTable *table; if (pname && strcmp(name, pname) == 0) return true; for (int i=0; i<props; i++) { prop = pTable->GetProp(i); if ((table = prop->GetDataTable()) != NULL) { pname = table->GetName(); if (pname && strcmp(name, pname) == 0) { return true; } if (UTIL_ContainsDataTable(table, name)) { return true; } } } return false; }
//--------------------------------------------------------------------------------- // Purpose: returns the specified prop from the class and table provided. // if prop or table not found, pointer returns NULL //--------------------------------------------------------------------------------- SendProp *GetPropFromClassAndTable(const char *szClassName, const char *szTableName, const char *szPropName) { ServerClass *pServerClass = pServerDLL->GetAllServerClasses(); if (!pServerClass) { Warning("servergamedll->GetAllServerClasses() returned null\n"); return NULL; } while (pServerClass) { if ( FStrEq(szClassName, pServerClass->GetName()) ) { SendTable *pTable = GetDataTable( szTableName, pServerClass->m_pTable ); if (pTable) { int numprops = pTable->GetNumProps(); for (int i = 0; i < numprops; ++i) { SendProp *pProp = pTable->GetProp(i); if (pProp && FStrEq(szPropName, pProp->GetName()) ) { return pProp; } } } } pServerClass = pServerClass->m_pNext; } Warning("prop %s not found in %s => %s\n", szPropName, szClassName, szTableName); return NULL; }
void SendTable_PrintStats( void ) { int numTables = 0; int numFloats = 0; int numStrings = 0; int numArrays = 0; int numInts = 0; int numVecs = 0; int numSubTables = 0; int numSendProps = 0; int numFlatProps = 0; int numExcludeProps = 0; for ( int i=0; i < g_SendTables.Count(); i++ ) { SendTable *st = g_SendTables[i]; numTables++; numSendProps += st->GetNumProps(); numFlatProps += st->m_pPrecalc->GetNumProps(); for ( int j=0; j < st->GetNumProps(); j++ ) { SendProp* sp = st->GetProp( j ); if ( sp->IsExcludeProp() ) { numExcludeProps++; continue; // no real sendprops } if ( sp->IsInsideArray() ) continue; switch( sp->GetType() ) { case DPT_Int : numInts++; break; case DPT_Float : numFloats++; break; case DPT_Vector : numVecs++; break; case DPT_String : numStrings++; break; case DPT_Array : numArrays++; break; case DPT_DataTable : numSubTables++; break; } } } Msg("Total Send Table stats\n"); Msg("Send Tables : %i\n", numTables ); Msg("Send Props : %i\n", numSendProps ); Msg("Flat Props : %i\n", numFlatProps ); Msg("Int Props : %i\n", numInts ); Msg("Float Props : %i\n", numFloats ); Msg("Vector Props: %i\n", numVecs ); Msg("String Props: %i\n", numStrings ); Msg("Array Props : %i\n", numArrays ); Msg("Table Props : %i\n", numSubTables ); Msg("Exclu Props : %i\n", numExcludeProps ); }
cell_t GetNumProps(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast<Handle_t>(params[1]); HandleError err; HandleSecurity sec; sec.pOwner = NULL; sec.pIdentity = myself->GetIdentity(); SendTable *pTable; if ((err=g_pHandleSys->ReadHandle(hndl, g_SendTableHandle, &sec, (void **)&pTable)) != HandleError_None) { return pContext->ThrowNativeError("Invalid SendTable handle %x (error %d)", hndl, err); } return pTable->GetNumProps(); }
//--------------------------------------------------------------------------------- // Purpose: used by the GetPropOffsetFromTable func to get a specific table //--------------------------------------------------------------------------------- SendTable *GetDataTable( const char *pTableName, SendTable *pTable ) { if (!pTable) return NULL; if ( FStrEq( pTableName, pTable->GetName() ) ) return pTable; int num = pTable->GetNumProps(); for (int i = 0; i < num; i++) { SendProp *pProp = pTable->GetProp(i); if (pProp) { SendTable *pSubTable = GetDataTable( pTableName, pProp->GetDataTable() ); if (pSubTable == NULL) continue; if ( FStrEq(pSubTable->GetName(), pTableName) ) return pSubTable; } } return NULL; }
// Spits out warnings for invalid properties and forces property values to // be in valid ranges for the encoders and decoders. static void SendTable_Validate( CSendTablePrecalc *pPrecalc ) { SendTable *pTable = pPrecalc->m_pSendTable; for( int i=0; i < pTable->m_nProps; i++ ) { SendProp *pProp = &pTable->m_pProps[i]; if ( pProp->GetArrayProp() ) { if ( pProp->GetArrayProp()->GetType() == DPT_DataTable ) { Error( "Invalid property: %s/%s (array of datatables) [on prop %d of %d (%s)].", pTable->m_pNetTableName, pProp->GetName(), i, pTable->m_nProps, pProp->GetArrayProp()->GetName() ); } } else { ErrorIfNot( pProp->GetNumElements() == 1, ("Prop %s/%s has an invalid element count for a non-array.", pTable->m_pNetTableName, pProp->GetName()) ); } // Check for 1-bit signed properties (their value doesn't get down to the client). if ( pProp->m_nBits == 1 && !(pProp->GetFlags() & SPROP_UNSIGNED) ) { DataTable_Warning("SendTable prop %s::%s is a 1-bit signed property. Use SPROP_UNSIGNED or the client will never receive a value.\n", pTable->m_pNetTableName, pProp->GetName()); } } for ( int i = 0; i < pPrecalc->GetNumProps(); ++i ) { const SendProp *pProp = pPrecalc->GetProp( i ); if ( pProp->GetFlags() & SPROP_ENCODED_AGAINST_TICKCOUNT ) { pTable->SetHasPropsEncodedAgainstTickcount( true ); break; } } }
bool MyPlugin::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) { serverGameDLL = (IServerGameDLL *)gameServerFactory(INTERFACEVERSION_SERVERGAMEDLL, NULL); if (serverGameDLL) { ServerClass *svrclass = serverGameDLL->GetAllServerClasses(); while (svrclass) { const char *classname = svrclass->GetName(); Msg("[%s]\n", classname); if (strcmp(classname, "CBasePlayer") == 0) { SendTable *st = svrclass->m_pTable; for (int i = 0; i < st->m_nProps; i++) { SendProp *sp = st->GetProp(i); const char *propname = sp->GetName(); Msg("Prop name: %s | Prop Offset: %d | Type: %d | IsSigned: %d\n", propname, sp->GetOffset(), sp->GetType(), sp->IsSigned()); if (strcmp(propname, "m_fFlags") == 0) { m_fFlags_off = sp->GetOffset(); continue; } if (strcmp(propname, "m_iHealth") == 0) { m_iHealth_off = sp->GetOffset(); continue; } } } if (strcmp(classname, "CBaseEntity") == 0) { SendTable *st = svrclass->m_pTable; for (int i = 0; i < st->m_nProps; i++) { SendProp *sp = st->GetProp(i); const char *propname = sp->GetName(); Msg("Prop name: %s | Prop Offset: %d | Type: %d | IsSigned: %d\n", propname, sp->GetOffset(), sp->GetType(), sp->IsSigned()); if (strcmp(propname, "m_iTeamNum") == 0) { m_iTeamNum_off = sp->GetOffset(); continue; } if (strcmp(propname, "m_iPendingTeamNum") == 0) { m_iPendingTeamNum_off = sp->GetOffset(); continue; } if (strcmp(propname, "m_fEffects") == 0) { m_fEffects_off = sp->GetOffset(); continue; } if (strcmp(propname, "m_nRenderMode") == 0) { m_nRenderMode_off = sp->GetOffset(); continue; } } } /*if (strcmp(classname, "CBaseCombatWeapon") == 0) { SendTable *st = svrclass->m_pTable; for (int i = 0; i < st->m_nProps; i++) { SendProp *sp = st->GetProp(i); const char *propname = sp->GetName(); Msg("Prop name: %s | Prop Offset: %d | Type: %d | IsSigned: %d\n", propname, sp->GetOffset(), sp->GetType(), sp->IsSigned()); } }*/ svrclass = svrclass->m_pNext; } } else { Warning("Unable to load IServerGameDLL.\n"); return false; } serverGameEnts = (IServerGameEnts *)gameServerFactory(INTERFACEVERSION_SERVERGAMEENTS, NULL); if (!serverGameEnts) { Warning("Unable to load IServerGameEnts.\n"); return false; } playerInfoManager = (IPlayerInfoManager *)gameServerFactory(INTERFACEVERSION_PLAYERINFOMANAGER, NULL); if (playerInfoManager) { globalVars = playerInfoManager->GetGlobalVars(); } else { Warning("Unable to load IPlayerInfoManager.\n"); return false; } g_pCVar = (ICvar *)interfaceFactory(CVAR_INTERFACE_VERSION, NULL); if (g_pCVar) { ICvar::Iterator iter(g_pCVar); for (iter.SetFirst(); iter.IsValid(); iter.Next()) { ConCommandBase *cmd = iter.Get(); if (cmd->IsCommand()) continue; const char *cmdname = cmd->GetName(); ConVar *cvar = (ConVar *)cmd; if (strcmp(cmdname, "net_maxcleartime") == 0) cvar->SetValue(0.001f); /*if (strcmp(cmdname, "net_minroutable") == 0) cvar->SetValue(1000);*/ } } else { Warning("Unable to load ICVar.\n"); return false; } gameEventManager2 = (IGameEventManager2 *)interfaceFactory(INTERFACEVERSION_GAMEEVENTSMANAGER2, NULL); if (!gameEventManager2) { Warning("Unable to load IGameEventManager2.\n"); return false; } vEngineServer = (IVEngineServer *)interfaceFactory(INTERFACEVERSION_VENGINESERVER, NULL); if (!vEngineServer) { Warning("Unable to load IVEngineServer.\n"); return false; } serverTools = (IServerTools *)gameServerFactory(VSERVERTOOLS_INTERFACE_VERSION, NULL); if (!serverTools) { Warning("Unable to load IServerTools.\n"); return false; } serverPluginHelpers = (IServerPluginHelpers *)interfaceFactory(INTERFACEVERSION_ISERVERPLUGINHELPERS, NULL); if (!serverPluginHelpers) { Warning("Unable to load IServerPluginHelpers.\n"); return false; } //playerDeathEvent = new PlayerDeathEvent(); //playerSayEvent = new PlayerSayEvent(); //playerConnectEvent = new PlayerConnectEvent(); //playerDisconnectEvent = new PlayerDisconnectEvent(); roundStartEvent = new RoundStartEvent(); //itemPickupEvent = new ItemPickupEvent(); //playerSpawnEvent = new PlayerSpawnEvent(); //playerSpawnedEvent = new PlayerSpawnedEvent(); //announphaseendevent = new AnnouncePhaseEndEvent(); return true; }
void RunDataTableTest() { RecvTable *pRecvTable = &REFERENCE_RECV_TABLE(DT_DTTest); SendTable *pSendTable = &REFERENCE_SEND_TABLE(DT_DTTest); // Initialize the send and receive modules. SendTable_Init( &pSendTable, 1 ); RecvTable_Init( &pRecvTable, 1 ); pSendTable->SetWriteFlag( false ); // Send DataTable info to the client. unsigned char commBuf[8192]; bf_write bfWrite( "RunDataTableTest->commBuf", commBuf, sizeof(commBuf) ); if( !WriteSendTable_R( pSendTable, bfWrite, true ) ) { Assert( !"RunDataTableTest: SendTable_SendInfo failed." ); } bfWrite.WriteOneBit(0); // Receive the SendTable's info. bf_read bfRead( "RunDataTableTest->bfRead", commBuf, sizeof(commBuf)); while( bfRead.ReadOneBit() ) { bool bNeedsDecoder = bfRead.ReadOneBit()!=0; if( !RecvTable_RecvClassInfos( &bfRead, bNeedsDecoder ) ) { Assert( !"RunDataTableTest: RecvTable_ReadInfos failed." ); continue; } } // Register our receive table. if( !RecvTable_CreateDecoders( NULL ) ) { Assert(false); } // Setup the data with all zeros. DTTestServer dtServer; DTTestClient dtClient; unsigned char prevEncoded[4096]; unsigned char fullEncoded[4096]; memset(&dtServer, 0, sizeof(dtServer)); memset(&dtClient, 0, sizeof(dtClient)); memset(prevEncoded, 0, sizeof(prevEncoded)); SetGuardBytes( &dtClient ); // Now loop around, changing the data a little bit each time and send/recv deltas. int nIterations = 25; for( int iIteration=0; iIteration < nIterations; iIteration++ ) { // Change the server's data. g_bSendSub = true; if( (iIteration % 5) == 0 ) { g_bSendSub = false; // every 8th time, don't send the subtable } if( (iIteration & 3) == 0 ) { // Every once in a while, change ALL the properties. for( int iChange=0; iChange < NUMVARTESTINFOS; iChange++ ) g_VarTestInfos[iChange].m_ChangeFn( &dtServer ); } else { int nChanges = 3 + rand() % NUMVARTESTINFOS; for( int iChange=0; iChange < nChanges; iChange++ ) { int iInfo = rand() % NUMVARTESTINFOS; g_VarTestInfos[iInfo].m_ChangeFn( &dtServer ); } } // Fully encode it. bf_write bfFullEncoded( "RunDataTableTest->bfFullEncoded", fullEncoded, sizeof(fullEncoded) ); if( !SendTable_Encode( pSendTable, &dtServer, &bfFullEncoded, -1, NULL ) ) { Assert(false); } unsigned char deltaEncoded[4096]; bf_write bfDeltaEncoded( "RunDataTableTest->bfDeltaEncoded", deltaEncoded, sizeof(deltaEncoded) ); if ( iIteration == 0 ) { // On the first iteration, just write the whole state. if( !SendTable_Encode( pSendTable, &dtServer, &bfDeltaEncoded, -1, NULL ) ) { Assert( false ); } } else { // Figure out the delta between the newly encoded one and the previously encoded one. int deltaProps[MAX_DATATABLE_PROPS]; bf_read fullEncodedRead( "RunDataTableTest->fullEncodedRead", fullEncoded, sizeof( fullEncoded ), bfFullEncoded.GetNumBitsWritten() ); bf_read prevEncodedRead( "RunDataTableTest->prevEncodedRead", prevEncoded, sizeof( prevEncoded ) ); int nDeltaProps = SendTable_CalcDelta( pSendTable, prevEncoded, sizeof( prevEncoded ) * 8, fullEncoded, bfFullEncoded.GetNumBitsWritten(), deltaProps, ARRAYSIZE( deltaProps ), -1 ); Assert( nDeltaProps != -1 ); // BAD: buffer overflow // Reencode with just the delta. This is what is actually sent to the client. SendTable_WritePropList( pSendTable, fullEncoded, bfFullEncoded.GetNumBitsWritten(), &bfDeltaEncoded, -1111, deltaProps, nDeltaProps ); } memcpy( prevEncoded, fullEncoded, sizeof( prevEncoded ) ); // This step isn't necessary to have the client decode the data but it's here to test // RecvTable_CopyEncoding (and RecvTable_MergeDeltas). This call should just make an exact // copy of the encoded data. unsigned char copyEncoded[4096]; bf_read bfReadDeltaEncoded( "RunDataTableTest->bfReadDeltaEncoded", deltaEncoded, sizeof( deltaEncoded ) ); bf_write bfCopyEncoded( "RunDataTableTest->bfCopyEncoded", copyEncoded, sizeof(copyEncoded) ); RecvTable_CopyEncoding( pRecvTable, &bfReadDeltaEncoded, &bfCopyEncoded, -1 ); // Decode.. bf_read bfDecode( "RunDataTableTest->copyEncoded", copyEncoded, sizeof( copyEncoded ) ); if(!RecvTable_Decode(pRecvTable, &dtClient, &bfDecode, 1111)) { Assert(false); } // Make sure it didn't go into memory it shouldn't have. CheckGuardBytes( &dtClient ); // Verify that only the changed properties were sent and that they were received correctly. CompareDTTest( &dtClient, &dtServer ); } SendTable_Term(); RecvTable_Term(); }
int EntityPropsManager::getPropOffset(const std::string &path) { // Try to find if we have already this offset int iOffset = 0; int index = this->getIndexInList(path); if(index > -1) { iOffset = EntityPropsList.at(index).propOffset; } if(iOffset) { return iOffset; } // If not, we have to find it. iOffset = 0; int i = 0; std::string cpath; std::vector<std::string> props; strSplit(path, ".", &props); ServerClass *pAllClasses = gamedll->GetAllServerClasses(); while(pAllClasses) { if(pAllClasses->GetName() == props.at(0)) // If we found the class { const int pSize = props.size(); // The use of const will accelerate the for instruction if(pSize > 2) // path containing class.datatable.(...).prop { SendTable *lastTable = pAllClasses->m_pTable; int iProps = 0; for(int iPath = 1; iPath < pSize-1; iPath++) // get the last datatable in path { cpath = props.at(iPath); iProps = lastTable->GetNumProps(); for(i = 0; i < iProps; i++) { if(lastTable->GetProp(i)->GetName() == props.at(iPath)) { lastTable = lastTable->GetProp(i)->GetDataTable(); i = iProps; } } } iProps = lastTable->m_nProps; for(i = 0; i < iProps; i++) // get the prop offset { if(lastTable->GetProp(i)->GetName() == props.back()) { iOffset = lastTable->GetProp(i)->GetOffset(); if(iOffset < 0) // The offset must be not negative { iOffset *= -1; } return iOffset; } } } else // path containing only class.prop { const int iProps = pAllClasses->m_pTable->GetNumProps(); for(i = 0; i < iProps; i++) { //Msg(pAllClasses->m_pTable->GetProp(i)->GetName()); //Msg("\n"); if(pAllClasses->m_pTable->GetProp(i)->GetName() == props.back()) { iOffset = pAllClasses->m_pTable->GetProp(i)->GetOffset(); if(iOffset < 0) // The offset must be not negative { iOffset *= -1; } return iOffset; } } break; } } // End if(pAllClasses->GetName() == props.at(0)) pAllClasses = pAllClasses->m_pNext; } // End while(!pAllClasses) return 0; }