//================= Copyright kotofyt, All rights reserved ==================// // // Purpose: // //===========================================================================// #include "entitysystem.h" #include "baseentity.h" #include "stddef.h" #include "string.h" #include "stdlib.h" #include "game.h" #include "netprotocol.h" CEntitySystem *EntitySystem() { static CEntitySystem s_entitySystem; return &s_entitySystem; } static struct EntityRegistry_t { IEntityFactory *m_pFactory; const char *m_szClassName; struct EntityRegistry_t *m_pNext; } *s_pEntitiesRegistry = NULL; CEntitySystem::CEntitySystem() { int i = 0; for ( i = 0; i < MAX_EDICTS; i++ ) { m_pEntities[i] = NULL; } m_nEntityCount = 0; } void CEntitySystem::RegisterEntityClass( IEntityFactory *pEntityFactory, const char *szClassName ) { IEntityFactory *pFactory; EntityRegistry_t *pRegistry; pFactory = GetFactoryByClassname(szClassName); if ( pFactory != NULL ) { // Already registered return; } pRegistry = new EntityRegistry_t; pRegistry->m_pFactory = pEntityFactory; pRegistry->m_pNext = s_pEntitiesRegistry; pRegistry->m_szClassName = szClassName; s_pEntitiesRegistry = pRegistry; } CBaseEntity *CEntitySystem::CreateByClassname( const char *szName, int *pOutputIndex ) { IEntityFactory *pFactory; CBaseEntity *pEntity; int i; int iSelectedSlot; pFactory = GetFactoryByClassname(szName); if ( !pFactory ) return NULL; // We do not want to have more than MAX_EDICT entities if ( m_nEntityCount >= MAX_EDICTS-1 ) return NULL; // Search for space // Could be more efficient but nobody cares for ( i = 0; i < MAX_EDICTS; i++ ) { if ( m_pEntities[i] == NULL ) { iSelectedSlot = i; break; } } pEntity = pFactory->Create(); pEntity->m_szClassName = szName; m_pEntities[iSelectedSlot] = pEntity; m_nEntityCount++; if (pOutputIndex) *pOutputIndex = iSelectedSlot; EntityClass_t stClassSync = { MESSAGE_ENTITY_CLASS_SYNC, iSelectedSlot, }; V_strncpy((char*)stClassSync.m_szEntityName, szName, 256); if (g_pCurrentConnection) g_pCurrentConnection->SendPacket({&stClassSync, sizeof(stClassSync), 0, PACKET_MUST_ARRIVE}); return pEntity; } IEntityFactory *CEntitySystem::GetFactoryByClassname( const char *szName ) { EntityRegistry_t *pEntity; for ( pEntity = s_pEntitiesRegistry; pEntity; pEntity = pEntity->m_pNext ) { if (!strcmp(szName, pEntity->m_szClassName)) { return pEntity->m_pFactory; } } return NULL; } void CEntitySystem::Think( float fDelta ) { CBaseEntity *pEntity; int i; for ( i = 0; i < MAX_EDICTS; i++ ) { pEntity = m_pEntities[i]; if ( pEntity == NULL ) continue; if ( !pEntity->m_pfnThink ) continue; (pEntity->*pEntity->m_pfnThink)(fDelta); } } static void *UTIL_GetNetMapData( CBaseEntity *pEntity, netmap_t *pMap, uint32_t uIndex ) { netmap_t *pCurrentMap = pMap; uint32_t uCurrentIndex = uIndex; searchIndex: if ( pCurrentMap ) { if (uCurrentIndex >= pCurrentMap->m_uFieldCount) { uCurrentIndex -= pCurrentMap->m_uFieldCount; pCurrentMap = pCurrentMap->m_pBase; goto searchIndex; } return (char*)pEntity+pCurrentMap->m_pFields[uCurrentIndex].m_uOffset; } return NULL; } void CEntitySystem::NetRecvPacket( NetPacket_t *pPacket ) { PlayerPacket_t *pPlayerPacket = (PlayerPacket_t*)pPacket->pData; CBaseEntity *pEntity; switch (pPlayerPacket->m_eType) { case MESSAGE_ENTITY_DATA_SYNC: if ( pPlayerPacket->m_entityData.m_uIndex >= MAX_EDICTS ) break; pEntity = m_pEntities[pPlayerPacket->m_entityData.m_uIndex]; // check for owner being moron if ( pEntity == NULL ) break; if ( pEntity->m_ullOwner != pPacket->m_uOwner) break; union { void *pData; char *pcCurrentData; EntityDataSyncValue_t *pcSyncValue; }; pData = pPlayerPacket; pcCurrentData += sizeof(EntityDataSync_t); // too bad // this shall be reworked for ( uint32_t u = 0; u < pPlayerPacket->m_entityData.m_uCount; u++ ) { uint32_t uVariableSize = pcSyncValue->m_uVariableSize; void *pValueData = (float*)UTIL_GetNetMapData( pEntity, pEntity->GetRecvMap(), pcSyncValue->m_uVariableIndex); pcCurrentData += sizeof(EntityDataSyncValue_t); if (pValueData) V_memcpy(pValueData, pcCurrentData, uVariableSize); pcCurrentData += (uVariableSize+7) & ~7; } break; default: break; } } //------------------------------------------------------------------------------- // Purpose: Sends packets to clients. // Since we are running this on server we can't really accept any packet. // We only allow packets from the entities sent by a client //------------------------------------------------------------------------------- void CEntitySystem::NetSendThink( INetworkBase *pBase ) { CBaseEntity *pEntity; int i; uint32_t u; uint32_t x; uint32_t uSize; netmap_t *pNetMap; void *pData; union { void *pCurrentData; char *pcCurrentData; EntityDataSync_t *pSync; EntityDataSyncValue_t *pValue; }; for ( i = 0; i < MAX_EDICTS; i++ ) { pEntity = m_pEntities[i]; if ( pEntity == NULL ) continue; pNetMap = pEntity->GetSendMap(); uSize = sizeof(EntityDataSyncValue_t); x = 0; while ( pNetMap ) { for ( u = 0; u < pNetMap->m_uFieldCount; u++ ) { x++; uSize += (pNetMap->m_pFields[u].m_uSize+7) & ~7; uSize += sizeof(EntityDataSyncValue_t); } pNetMap = pNetMap->m_pBase; } pData = V_malloc(uSize); V_memset(pData, 0, uSize); pCurrentData = pData; pSync->m_eType = MESSAGE_ENTITY_DATA_SYNC; pSync->m_uIndex = i; pSync->m_uCount = x; pcCurrentData += sizeof(EntityDataSync_t); pNetMap = pEntity->GetSendMap(); x = 0; while ( pNetMap ) { for ( u = 0; u < pNetMap->m_uFieldCount; u++ ) { pValue->m_uVariableSize = pNetMap->m_pFields[u].m_uSize; pValue->m_uVariableIndex = x; uint32_t uVariableSize; pcCurrentData += sizeof(EntityDataSyncValue_t); V_memcpy(pcCurrentData, pNetMap->m_pFields[u].m_uOffset+(char*)pEntity, pNetMap->m_pFields[u].m_uSize); pcCurrentData += (pNetMap->m_pFields[u].m_uSize+7) & ~7; x++; } pNetMap = pNetMap->m_pBase; } if (pBase) pBase->SendPacket({pData, uSize}); V_free(pData); } } CBaseEntity **CEntitySystem::GetEntities() { return m_pEntities; } void CEntitySystem::SetAllowedEntityForPlayer( uint64_t ullPlayer, CBaseEntity *pEntity ) { if (pEntity) { } else { } }