CryEngine 5.4 - Traverse all the entities in the entity system properly

#1
I see that in CryEngine 5.4, when I create a new third person project, I have some C++ code.
There is the method SpawnAtSpawnPoint()

Code: Select all

void CPlayerComponent::SpawnAtSpawnPoint()
{
//....
// Spawn at first default spawner
auto *pEntityIterator = gEnv->pEntitySystem->GetEntityIterator();
pEntityIterator->MoveFirst();

while (!pEntityIterator->IsEnd())
{
IEntity *pEntity = pEntityIterator->Next();

if (auto* pSpawner = pEntity->GetComponent<CSpawnPointComponent>())
{
pSpawner->SpawnEntity(m_pEntity);
break;
}
}
}
first, is this example code missing something? I think it really should release the pEntityIterator after it's done using the Iterator

Code: Select all

pEntityIterator->Release();
Did Crytek forget or is there any other reason?

Is it a good idea to traverse all the entities in the entity system to just find one (or some) entity that match the condition, I mean there could be like billion of entities in the scene, if methods like this get called often, could it be bad for the performance? How can I improve it? Like just search for entities in a list of CSpawnPointComponent's entity only.
Small tips
How to add an image to a forum post
[C++] How to smoothly turn your character

Re: CryEngine 5.4 - Traverse all the entities in the entity system properly

#4
You are right, this is a memory leak. CEntitySystem::GetEntityIterator() allocates new iterator object https://github.com/CRYTEK/CRYENGINE/blo ... .cpp#L1743
And then game code should call Release() to free it.
As IEntityIt provides ref-counting interface, better to use CryEngine's smart pointer wrapper. And there is even a typedef for it already - IEntityItPtr.
Also, I believe example can be done better - explicit MoveFirst() and IsEnd() are not needed. MoveFirst() is done by ctor, IsEnd() is checked by Next(). So code becomes like this:

Code: Select all

IEntityItPtr pEntityIterator = gEnv->pEntitySystem->GetEntityIterator();
while (IEntity* pEntity = pEntityIterator->Next())
{
...
}
Would be good to open issue on github or even make pull request to notify Crytek, that example contains a bug and can be improved. And maybe IEntitySystem::GetEntityIterator() should even return IEntityItPtr to prevent confusion.

Now regarding your second question. AFAIK, there is no better API to enumerate components of same type from multiple entities (at least, there was no such API few versions ago). And you are right, even if billion of entities is not supported (only up to 65K), iterating over all entities and probing their component vectors sounds like a potential performance hit.
If you expect that your application will have to enumerate particular components often, maybe it's worth to create a little manager which maintains a list of them. And then components can register and unregister themselves in this manager on init and shutdown.

Re: CryEngine 5.4 - Traverse all the entities in the entity system properly

#6
Hello,
Thanks for reporting this issue, indeed we would leak memory in this case because the pointer would never be released. Great catch!
We will change the return type of the GetEntityIterator function to IEntityItPtr so we can ensure that it doesn't leak memory accidentally. We will also mention this change in the important changes for 5.5, since you might have to adjust your code accordingly. But overall this should make the usage of the iterator easier. I will also post this answer on GitHub so other users can see it on both platforms.

In this example we choose to just traverse all entities to search for the spawn point component for multiple reasons. We want to keep the templates as simple, small and understandable as possible. Off course this approach isn't ideal but for this case it's perfectly fine. If you would have a world with hundreds of entities you should avoid going trough all of them and query their components. You could for example have a SpawnPointManager which would already know all spawn points through entity links or a special layer for spawn points only, which is then way easier to search. Another way would be to just search for the name of the entity, which would be still faster then just iterating over all entities (although I wouldn't recommend this approach too much).

Cheers,
Alex

Who is online

Users browsing this forum: No registered users and 2 guests

cron