317 lines
6.6 KiB
C++
317 lines
6.6 KiB
C++
//================= 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;
|
|
}
|