//================= Copyright kotofyt, All rights reserved ==================// // // Purpose: // //===========================================================================// #include "entitysystem.h" #include "baseentity.h" #include "stddef.h" #include "string.h" #include "stdlib.h" #include "netprotocol.h" static C_BaseEntity *s_pLocalEntity; 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; } C_BaseEntity *CEntitySystem::CreateByClassname( const char *szName ) { IEntityFactory *pFactory; C_BaseEntity *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++; return pEntity; } C_BaseEntity *CEntitySystem::CreateByClassnameWithIndex( const char *szName, uint32_t uIndex ) { IEntityFactory *pFactory; C_BaseEntity *pEntity; // Do not create such shit if (uIndex >= MAX_EDICTS) return NULL; pFactory = GetFactoryByClassname(szName); if ( !pFactory ) return NULL; pEntity = pFactory->Create(); pEntity->m_szClassName = szName; m_pEntities[uIndex] = pEntity; m_nEntityCount++; 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::DestroyEntityByIndex( uint32_t uIndex ) { if ( uIndex >= MAX_EDICTS ) return; if (m_pEntities[uIndex]) { V_printf("Deleting: %i\n", uIndex); if (m_pEntities[uIndex] == s_pLocalEntity) s_pLocalEntity = 0; delete m_pEntities[uIndex]; m_pEntities[uIndex] = 0; } } void CEntitySystem::DestroyEntityByPtr( C_BaseEntity *pEntity ) { } void CEntitySystem::Think() { C_BaseEntity *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)(0); } } static void *UTIL_GetNetMapData( C_BaseEntity *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; C_BaseEntity *pEntity; switch (pPlayerPacket->m_eType) { case MESSAGE_ENTITY_CLASS_SYNC: pEntity = CreateByClassnameWithIndex( (char*)pPlayerPacket->m_entityClass.m_szEntityName, pPlayerPacket->m_entityClass.m_uIndex ); if (pEntity == NULL) break; pEntity->Spawn(); break; case MESSAGE_ENTITY_DATA_SYNC: pEntity = m_pEntities[pPlayerPacket->m_entityData.m_uIndex]; if (pEntity == NULL) 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; case k_EMessage_PlayerSetLocalEntity: if (pPlayerPacket->m_setLocalEntity.m_uIndex > MAX_EDICTS) break; s_pLocalEntity = m_pEntities[pPlayerPacket->m_setLocalEntity.m_uIndex]; default: break; } } void CEntitySystem::NetSendThink( INetworkBase *pBase ) { C_BaseEntity *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; }; pEntity = UTIL_GetLocalPlayer(); if ( pEntity == NULL ) return; 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; for ( i = 0; i < MAX_EDICTS; i++ ) { if ( m_pEntities[i] != pEntity ) continue; pSync->m_uIndex = i; break; } 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); } C_BaseEntity **CEntitySystem::GetEntities() { return m_pEntities; }; C_BaseEntity *UTIL_GetLocalPlayer() { return s_pLocalEntity; }