!I integrate from //ce/main...
[CRYENGINE.git] / Code / CryEngine / CryAction / ActorSystem.cpp
blobea496a8c27e89aeade1cb1abb9dd1f6bfa152291
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 /*************************************************************************
4 -------------------------------------------------------------------------
5 $Id$
6 $DateTime$
8 -------------------------------------------------------------------------
9 History:
10 - 23:8:2004 15:52 : Created by Márcio Martins
12 *************************************************************************/
13 #include "StdAfx.h"
14 #include "ActorSystem.h"
15 #include "Network/GameServerChannel.h"
16 #include "Network/GameServerNub.h"
17 #include <CryString/CryPath.h>
18 #include "CryAction.h"
20 //------------------------------------------------------------------------
21 void CActorSystem::DemoSpectatorSystem::SwitchSpectator(TActorMap* pActors, EntityId id)
23 if (pActors->size() <= 1)
24 return;
26 IActor* nextActor, * lastActor;
28 lastActor = (*pActors)[m_currentActor];
30 if (id == 0)
32 TActorMap::const_iterator it = pActors->begin();
33 while (it->first != m_currentActor)
34 ++it;
35 ++it;
36 if (it == pActors->end())
37 it = pActors->begin();
38 nextActor = it->second;
40 else
42 nextActor = (*pActors)[id];
43 if (!nextActor)
44 return;
47 if (nextActor == lastActor)
48 return;
50 m_currentActor = nextActor->GetEntityId();
51 if (IView* view = gEnv->pGameFramework->GetIViewSystem()->GetActiveView())
52 view->LinkTo(nextActor->GetEntity());
54 nextActor->SwitchDemoModeSpectator(true);
55 lastActor->SwitchDemoModeSpectator(false);
58 //------------------------------------------------------------------------
59 CActorSystem::CActorSystem(ISystem* pSystem, IEntitySystem* pEntitySystem)
60 : m_pSystem(pSystem),
61 m_pEntitySystem(pEntitySystem)
63 m_demoPlaybackMappedOriginalServerPlayer = 0;
65 if (gEnv->pEntitySystem)
67 gEnv->pEntitySystem->AddSink(this, IEntitySystem::OnReused);
71 // Iterators now have their destructors called before they enter the pool - so we only need to free the memory here {2008/12/09}
72 void DeleteActorIterator(IActorIterator* ptr) { operator delete(ptr); }
74 //------------------------------------------------------------------------
75 CActorSystem::~CActorSystem()
77 if (gEnv->pEntitySystem)
79 gEnv->pEntitySystem->RemoveSink(this);
82 std::for_each(m_iteratorPool.begin(), m_iteratorPool.end(), DeleteActorIterator);
83 // delete the created userdata in each class
84 for (TActorClassMap::iterator it = m_classes.begin(); it != m_classes.end(); ++it)
86 IEntityClass* pClass = m_pEntitySystem->GetClassRegistry()->FindClass(it->first.c_str());
87 if (pClass)
88 delete (char*)pClass->GetUserProxyData();
92 void CActorSystem::Reset()
94 if (GetISystem()->IsSerializingFile() == 1)
96 TActorMap::iterator it = m_actors.begin();
97 IEntitySystem* pEntitySystem = gEnv->pEntitySystem;
98 for (; it != m_actors.end(); )
100 EntityId id = it->first;
101 IEntity* pEntity = pEntitySystem->GetEntity(id);
102 if (pEntity != NULL)
104 ++it;
106 else
108 TActorMap::iterator eraseIt = it++;
109 m_actors.erase(eraseIt);
114 std::for_each(m_iteratorPool.begin(), m_iteratorPool.end(), DeleteActorIterator);
115 stl::free_container(m_iteratorPool);
118 //------------------------------------------------------------------------
119 IActor* CActorSystem::GetActor(EntityId entityId)
121 TActorMap::iterator it = m_actors.find(entityId);
123 if (it != m_actors.end())
125 return it->second;
128 return 0;
131 //------------------------------------------------------------------------
132 IActor* CActorSystem::GetActorByChannelId(uint16 channelId)
134 for (TActorMap::iterator it = m_actors.begin(); it != m_actors.end(); ++it)
136 if (it->second->GetGameObject()->GetChannelId() == channelId)
138 return it->second;
142 return 0;
145 //------------------------------------------------------------------------
146 IActor* CActorSystem::CreateActor(uint16 channelId, const char* name, const char* actorClass, const Vec3& pos, const Quat& rot, const Vec3& scale, EntityId id)
148 // get the entity class
149 IEntityClass* pEntityClass = m_pEntitySystem->GetClassRegistry()->FindClass(actorClass);
151 if (!pEntityClass)
153 CRY_ASSERT(pEntityClass);
155 return 0;
158 // if a channel is specified and already has a player,
159 // use that entity id
161 bool bIsClient = false;
162 if (channelId)
164 if (CGameServerNub* pGameServerNub = CCryAction::GetCryAction()->GetGameServerNub())
165 if (CGameServerChannel* pGameServerChannel = pGameServerNub->GetChannel(channelId))
166 if (pGameServerChannel->GetNetChannel()->IsLocal())
168 id = LOCAL_PLAYER_ENTITY_ID;
169 bIsClient = true;
170 if (IsDemoPlayback()) //if playing a demo - spectator id is changed
171 m_demoSpectatorSystem.m_currentActor = m_demoSpectatorSystem.m_originalActor = id;
175 IGameObjectSystem::SEntitySpawnParamsForGameObjectWithPreactivatedExtension userData;
176 userData.hookFunction = HookCreateActor;
177 userData.pUserData = &channelId;
179 SEntitySpawnParams params;
180 params.id = id;
181 params.pUserData = (void*)&userData;
182 params.sName = name;
183 params.vPosition = pos;
184 params.qRotation = rot;
185 params.vScale = scale;
186 params.nFlags = ENTITY_FLAG_TRIGGER_AREAS;
187 params.nFlagsExtended = ENTITY_FLAG_EXTENDED_NEEDS_MOVEINSIDE; // ensures the audio triggered on the actor entity will get proper environment values
189 params.pClass = pEntityClass;
191 IEntity* pEntity = m_pEntitySystem->SpawnEntity(params);
192 CRY_ASSERT(pEntity);
194 if (!pEntity)
196 return 0;
199 return GetActor(pEntity->GetId());
202 //------------------------------------------------------------------------
203 void CActorSystem::SetDemoPlaybackMappedOriginalServerPlayer(EntityId id)
205 m_demoPlaybackMappedOriginalServerPlayer = id;
208 EntityId CActorSystem::GetDemoPlaybackMappedOriginalServerPlayer() const
210 return m_demoPlaybackMappedOriginalServerPlayer;
213 //------------------------------------------------------------------------
214 void CActorSystem::SwitchDemoSpectator(EntityId id)
216 m_demoSpectatorSystem.SwitchSpectator(&m_actors, id);
219 //------------------------------------------------------------------------
220 IActor* CActorSystem::GetCurrentDemoSpectator()
222 return m_actors[m_demoSpectatorSystem.m_currentActor];
225 //------------------------------------------------------------------------
226 IActor* CActorSystem::GetOriginalDemoSpectator()
228 return m_actors[m_demoSpectatorSystem.m_originalActor];
231 //------------------------------------------------------------------------
232 void CActorSystem::RegisterActorClass(const char* name, IGameFramework::IActorCreator* pCreator, bool isAI)
234 IEntityClassRegistry::SEntityClassDesc actorClass;
236 char scriptName[1024] = { 0 };
237 if (!isAI)
238 cry_sprintf(scriptName, "Scripts/Entities/Actor/%s.lua", name);
239 else
240 cry_sprintf(scriptName, "Scripts/Entities/AI/%s.lua", name);
242 // Allow the name to contain relative path, but use only the name part as class name.
243 string className(PathUtil::GetFile(name));
244 actorClass.sName = className.c_str();
245 actorClass.sScriptFile = scriptName;
246 if (!isAI)
247 actorClass.flags |= ECLF_INVISIBLE;
249 CCryAction::GetCryAction()->GetIGameObjectSystem()->RegisterExtension(className.c_str(), pCreator, &actorClass);
251 SActorClassDesc classDesc;
252 classDesc.pEntityClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(className.c_str());
253 classDesc.pCreator = pCreator;
255 m_classes.insert(TActorClassMap::value_type(name, classDesc));
257 // Automatically register scheduling profile
258 gEnv->pGameFramework->GetIGameObjectSystem()->RegisterSchedulingProfile(actorClass.sName, "dude", "own");
261 //------------------------------------------------------------------------
262 void CActorSystem::AddActor(EntityId entityId, IActor* pProxy)
264 m_actors.insert(TActorMap::value_type(entityId, pProxy));
267 //------------------------------------------------------------------------
268 void CActorSystem::RemoveActor(EntityId entityId)
270 stl::member_find_and_erase(m_actors, entityId);
273 //------------------------------------------------------------------------
274 bool CActorSystem::HookCreateActor(IEntity* pEntity, IGameObject* pGameObject, void* pUserData)
276 pGameObject->SetChannelId(*reinterpret_cast<uint16*>(pUserData));
277 return true;
280 //---------------------------------------------------------------------
281 void CActorSystem::Reload()
283 Reset();
284 Scan(m_actorParamsFolder.c_str());
287 //---------------------------------------------------------------------
288 void CActorSystem::Scan(const char* folderName)
290 stack_string folder = folderName;
291 stack_string search = folder;
292 stack_string subName;
293 stack_string xmlFile;
294 search += "/*.*";
296 ICryPak* pPak = gEnv->pCryPak;
298 _finddata_t fd;
299 intptr_t handle = pPak->FindFirst(search.c_str(), &fd);
300 //Scan only one directory, not recursion supported (add it if need it)
301 if (handle > -1)
305 if (!strcmp(fd.name, ".") || !strcmp(fd.name, ".."))
306 continue;
308 const char* fileExtension = PathUtil::GetExt(fd.name);
309 if (stricmp(fileExtension, "xml"))
311 continue;
314 xmlFile = folder + "/" + fd.name;
315 XmlNodeRef rootNode = gEnv->pSystem->LoadXmlFromFile(xmlFile.c_str());
317 if (!rootNode)
319 ActorSystemErrorMessage(xmlFile.c_str(), "Root xml node couldn't be loaded", true);
320 continue;
323 if (!ScanXML(rootNode, xmlFile.c_str()))
325 continue;
329 while (pPak->FindNext(handle, &fd) >= 0);
332 m_actorParamsFolder = folderName;
335 //--------------------------------------------------------------------
336 bool CActorSystem::ScanXML(const XmlNodeRef& root, const char* xmlFile)
338 if (strcmpi(root->getTag(), "ActorParams") && strcmpi(root->getTag(), "EntityClassParams"))
340 CryFixedStringT<128> errorBuffer;
341 errorBuffer.Format("Root tag is '%s', expecting 'ActorParams' or 'EntityClassParams', Skipping...");
342 ActorSystemErrorMessage(xmlFile, errorBuffer.c_str(), true);
343 return false;
346 const char* type = root->getAttr("type");
347 if (!type)
349 ActorSystemErrorMessage(xmlFile, "Actor/EntityClass params file does not contain attribute 'type'! Skipping...", true);
350 return false;
353 TActorParamsMap::iterator dit = m_actorParams.find(CONST_TEMP_STRING(type));
355 //Insert only if new, might be reloading...
356 if (dit == m_actorParams.end())
358 std::pair<TActorParamsMap::iterator, bool> result = m_actorParams.insert(TActorParamsMap::value_type(type, SActorParamsDesc()));
359 dit = result.first;
362 SActorParamsDesc& desc = dit->second;
364 if (desc.params)
365 desc.params->Release();
367 desc.params = new CItemParamsNode();
368 desc.params->ConvertFromXML(root);
370 return true;
373 //-----------------------------------------------------------------
374 const IItemParamsNode* CActorSystem::GetActorParams(const char* actorClass) const
376 TActorParamsMap::const_iterator it = m_actorParams.find(CONST_TEMP_STRING(actorClass));
377 if (it != m_actorParams.end())
379 return it->second.params;
382 return 0;
385 //-----------------------------------------------------------------
386 bool CActorSystem::IsActorClass(IEntityClass* pClass) const
388 bool bResult = false;
390 TActorClassMap::const_iterator itClass = m_classes.begin();
391 TActorClassMap::const_iterator itClassEnd = m_classes.end();
392 for (; !bResult && itClass != itClassEnd; ++itClass)
394 const SActorClassDesc& classDesc = itClass->second;
395 bResult = (pClass == classDesc.pEntityClass);
398 return bResult;
401 //------------------------------------------------------------------------
402 bool CActorSystem::OnBeforeSpawn(SEntitySpawnParams& params)
404 return true; // nothing else (but needed to implement IEntitySystemSink)
407 //------------------------------------------------------------------------
408 void CActorSystem::OnSpawn(IEntity* pEntity, SEntitySpawnParams& params)
410 // nothing (but needed to implement IEntitySystemSink)
413 //------------------------------------------------------------------------
414 bool CActorSystem::OnRemove(IEntity* pEntity)
416 return true; // nothing else (but needed to implement IEntitySystemSink)
419 //------------------------------------------------------------------------
420 void CActorSystem::OnReused(IEntity* pEntity, SEntitySpawnParams& params)
422 for (TActorMap::const_iterator it = m_actors.begin(); it != m_actors.end(); ++it)
424 IActor* actor = it->second;
425 IEntity* ent = actor->GetEntity();
427 if (ent && ent == pEntity)
429 actor->OnReused(pEntity, params);
434 //------------------------------------------------------------------------
435 void CActorSystem::GetMemoryUsage(class ICrySizer* pSizer) const
437 pSizer->Add(sizeof *this);
440 IActorIteratorPtr CActorSystem::CreateActorIterator()
442 if (m_iteratorPool.empty())
444 return new CActorIterator(this);
446 else
448 CActorIterator* pIter = m_iteratorPool.back();
449 m_iteratorPool.pop_back();
450 new(pIter) CActorIterator(this);
451 return pIter;
455 void CActorSystem::ActorSystemErrorMessage(const char* fileName, const char* errorInfo, bool displayErrorDialog)
457 if ((fileName == NULL) || (errorInfo == NULL))
458 return;
460 CryFixedStringT<1024> messageBuffer;
461 messageBuffer.Format("ERROR: Failed to load '%s'. Required data missing, which could lead to un-expected game behavior or crashes. ( %s )", fileName, errorInfo);
463 CryLogAlways("%s", messageBuffer.c_str());
465 if (displayErrorDialog)
467 CryMessageBox(messageBuffer.c_str(), "Error", eMB_Error);
471 void CActorSystem::GetMemoryStatistics(ICrySizer* pSizer)
473 SIZER_SUBCOMPONENT_NAME(pSizer, "ActorSystem");
474 pSizer->AddObject(this, sizeof(*this));
475 pSizer->AddObject(m_actors);